-
Notifications
You must be signed in to change notification settings - Fork 596
/
migrate-git-history.sh
executable file
·146 lines (121 loc) · 3.93 KB
/
migrate-git-history.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#!/bin/bash
# Copyright 2022 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set -ex
if [ $# -lt 4 ]
then
echo "Usage: $0 <source-repo> <target-repo> <source-path> <target-path> [folders,to,skip] [files,to,keep] [branch-name]"
exit 1
fi
# source GitHub repository. format: <owner>/<repo>
SOURCE_REPO=$1
# destination GitHub repository. format: <owner>/<repo>
TARGET_REPO=$2
# path in the source repo to copy code from. Defaults to the root directory
SOURCE_PATH=$3
# path in the target repo to put the copied code
TARGET_PATH=$4
# comma-separated list of files/folders to skip
IGNORE_FOLDERS=$5
# keep these specific files that would otherwise be deleted by IGNORE_FOLDERS
KEEP_FILES=$6
# override the HEAD branch name for the migration PR
BRANCH=$7
if [[ ! -z "${UPDATE_SCRIPT}" ]]
then
UPDATE_SCRIPT=$(realpath "${UPDATE_SCRIPT}")
fi
if [[ -z "${BRANCH}" ]]
then
# default the branch name to be generated from the source repo name
BRANCH=$(basename ${SOURCE_REPO})-migration
fi
export FILTER_BRANCH_SQUELCH_WARNING=1
# create a working directory
WORKDIR=$(mktemp -d -t code-migration-XXXXXXXXXX)
echo "Created working directory: ${WORKDIR}"
pushd "${WORKDIR}"
echo "Cloning source repository: ${SOURCE_REPO}"
git clone "[email protected]:${SOURCE_REPO}.git" source-repo
pushd source-repo
git remote remove origin
# prune only files within the specified directory
if [[ ! -z "${SOURCE_PATH}" ]]
then
echo "Pruning commits only including path: ${SOURCE_PATH}"
git filter-branch \
--prune-empty \
--subdirectory-filter "${SOURCE_PATH}"
fi
if [[ ! -z "${IGNORE_FOLDERS}" ]]
then
echo "Ignoring folder: ${IGNORE_FOLDERS}"
mkdir -p ${WORKDIR}/filtered-source
FOLDERS=$(echo ${IGNORE_FOLDERS} | tr "," " ")
# remove files/folders we don't want
FILTER="(rm -rf ${FOLDERS} || true)"
if [[ ! -z "${KEEP_FILES}" ]]
then
KEEP_FILES_SPACES=($(echo ${KEEP_FILES} | tr "," " "))
LAST_ELEMENT=$(( ${#KEEP_FILES_SPACES[@]} - 1 ))
KEEP_FILE_COMMANDS=""
for file in "${KEEP_FILES_SPACES[@]}"
do
if [[ $file == "${KEEP_FILES_SPACES[$LAST_ELEMENT]}" ]]
then
KEEP_FILE_COMMANDS+="git checkout -- ${file} 2>/dev/null || true"
else
KEEP_FILE_COMMANDS+="git checkout -- ${file} 2>/dev/null || true; "
fi
done
# restore files to keep, silence errors if the file doesn't exist
FILTER="${FILTER}; ${KEEP_FILE_COMMANDS}"
fi
git filter-branch \
--force \
--prune-empty \
--tree-filter "${FILTER}"
fi
# reorganize the filtered code into the desired target locations
if [[ ! -z "${TARGET_PATH}" ]]
then
echo "Moving files to destination path: ${TARGET_PATH}"
git filter-branch \
--force \
--prune-empty \
--tree-filter \
"shopt -s dotglob; mkdir -p ${WORKDIR}/migrated-source; mv * ${WORKDIR}/migrated-source; mkdir -p ${TARGET_PATH}; mv ${WORKDIR}/migrated-source/* ${TARGET_PATH}"
fi
# back to workdir
popd
# merge histories
echo "Cloning target repository: ${SOURCE_REPO}"
git clone "[email protected]:${TARGET_REPO}.git" target-repo
pushd target-repo
git remote add --fetch migration ../source-repo
git checkout -b "${BRANCH}"
git merge --allow-unrelated-histories migration/main --no-edit
if [[ ! -z "${UPDATE_SCRIPT}" ]]
then
bash "${UPDATE_SCRIPT}"
fi
git push -u origin "${BRANCH}" --force
# create pull request
if gh --help > /dev/null
then
gh pr create --title "migrate code from ${SOURCE_REPO}"
else
hub pull-request -m "migrate code from ${SOURCE_REPO}"
fi
popd