-
Notifications
You must be signed in to change notification settings - Fork 0
/
gitCopy.bash
111 lines (88 loc) · 2.77 KB
/
gitCopy.bash
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
#!/bin/bash
# Source: [21 April 2021] https://gitlab.inria.fr/-/snippets/520
#
# HOW TO USE:
#
# PSEUDO-CODE TEMPLATE:
# ```
# bash ./gitCopy.bash {fileToCopy} {...newFiles}
# ```
#
# EXAMPLE:
# Lets say you have a file called Section.tsx. Your section has grown very big
# and you want to split it into into three subsection files, while preserving
# the git history. Your plan is to copy the section file into three new files, in
# a new subfolder called "subsections".
#
# In that case, you would do something like this:
#
# ```
# bash ./gitCopy.bash ./components/Section.tsx ./components/subsections/Section1.tsx ./components/subsections/Section3.tsx ./components/subsections/Section3.tsx
# ```
GRAY='\033[1;30m'
GREEN='\033[0;32m'
LIGHT_BLUE='\033[1;34m'
RED='\033[0;31m'
NO_COLOR='\033[0m'
fail_and_quit () {
echo -e "\n${RED}Failed to git copy.${NO_COLOR}"
exit 0
}
if [ ! \( -f "$1" -a $# -ge 2 \) ]; then
echo -e "\n${RED}Invalid inputs${NO_COLOR}"
cat 1>&2 <<-EOF
Usage: \$0 ORIGINAL copy1 [... copyN]
Copy ORIGINAL, preserving history for git blame
New history will have N+3 commits
EOF
exit 1
fi
ORIGINAL="$1";
# shift to $2 and start counting arguments from 2
shift;
# Messages
echo -e "\nWill split ${GRAY}${ORIGINAL}${NO_COLOR} into ${LIGHT_BLUE}+$# files${NO_COLOR}:"
args=("$@")
for i in "${!args[@]}"; do
echo -e " $i. ${GRAY}${args[$i]}${NO_COLOR}"
done
echo -e "New history will have ${GREEN}+$(($# + 3)) commits ${NO_COLOR}\n"
# /Messages
KEEP=$(mkdir -p $(dirname $1) && mktemp ./"$1".XXXXXXXX);
MESSAGE="Copy $ORIGINAL to $@ keep history"
SPLIT=""
# Remember current commit
ROOT=$(git rev-parse HEAD)
# Check for errors
if [ -z "$ORIGINAL" ]; then
echo -e "\n${RED}ERROR:${NO_COLOR} Did not get ORIGINAL variable."
fail_and_quit
elif [ -z "$KEEP" ]; then
echo -e "\n${RED}ERROR:${NO_COLOR} Did not get KEEP variable."
fail_and_quit
elif [ -z "$MESSAGE" ]; then
echo -e "\n${RED}ERROR:${NO_COLOR} Did not get MESSAGE variable."
fail_and_quit
fi
# Create branch where $2 has $ORIGINAL's history
for f in "$@"; do
git reset --soft $ROOT
git checkout $ROOT "$ORIGINAL"
git mv -f "$ORIGINAL" "$f"
git commit -n -m "* $MESSAGE: create $f"
SPLIT="$(git rev-parse HEAD) $SPLIT"
done
# Go back to initial branch and move $ORIGINAL out of the way
git reset --hard HEAD^
git mv "$ORIGINAL" -f "$KEEP"
git commit -n -m "* $MESSAGE: keep $ORIGINAL"
# Merge $2's branch back into the original
git merge $SPLIT -m "* $MESSAGE: merge"
git commit -a -n -m "* $MESSAGE: merge"
# Move $ORIGINAL back where it was
git mv "$KEEP" "$ORIGINAL"
git commit -n -m "$MESSAGE"
# Report
echo -e "\nNew history: ${GRAY}$(git rev-parse --short $ROOT)..$(git rev-parse --short HEAD)${NO_COLOR}"
echo -e "\n${GREEN}Success!${NO_COLOR}\n"
exit 0