added maybe supreseded note
[git-test-merge.git] / git-test-merge
blobf8c1f7527caca52446682861437ddffb803cdf2c
1 #!/nix/var/nix/profiles/per-user/marc/profile/bin/bash
2 # needing bash because of < <( .. ) below
3 # author Marc Weber Th 17. Jul 00:58:14 CEST 2008
5 # TODO: integrate http://thread.gmane.org/gmane.comp.version-control.git/89644 somehow
6 set -e
8 me="git-test-merge" # name of script
9 tmp=".git/$me/tmp"
10 cont=".git/$me/continue"
11 merge_hist=".git/$me/merge_hist"
13 mkdir -p ".git/$me"
14 [ -f "$tmp" ] && rm "$tmp"
15 COMMIT_MESSAGE=" auto merge MERGE  - warning, this branch will be rebased, don't base your work on this branch" 
17 failmessage="!!        git-test-merge failed, log : \`$tmp'\n"
18 trappedFailure(){
19   echo -en "$failmessage"
20   errors="`egrep 'You have local changes to' "$tmp"`"
21   [ -n "$errors" ] && {
22     echo 
23     echo "    failure probably caused by"
24     echo "$errors"
25   }
27 trap  'trappedFailure' EXIT;
28 echo log is "$tmp"
30 conflicted(){
31   for f in "$@"; do
32     if egrep -l '^<<<<<<<|^>>>>>>>'  "$f" &> /dev/null; then
33       return 1
34     fi
35   done
36   return 0
39 fst(){ echo "$1"; }
41 # args : env $name
42 # argv : branch names left to merge
43 submerge(){
44   while let $(( $# > 0 )); do
45     echo "* merging with $1 ";
46     git merge -m "${COMMIT_MESSAGE/MERGE/$name}" "$1" >> "$tmp" 2>&1 \
47     || { 
48     grep ' does not point to a commit' "$tmp" && { echo '        ^^^^^^^^^^^^ ';  exit 1; }
49     echo "probably merge conflicts, have they all been resolved by git-rerere ?"
50       while read -er f; do
51         echo -n "checking $f .. "
52         if conflicted "$f"; then
53           echo "resolved"
54           git add "$f"
55         else
56           echo -e "\n >>    \`$f' contains unresolved conflicts"
57           echo "$name" > "$cont"; echo "$@" >> "$cont"
58           conflicted=1
59         fi
60         [ -n "$conflicted" ] && { 
61           echo "resolve conflicts, run   $me c to continue"
62           echo " unmerged files will be git-added automatically"
63           exit 1
64         }
65       done < <( git status | sed -n 's/#\s*unmerged:\s*\(.*\)/\1/p' )
66       # commit ourselves.. and continue 
67       echo "continuing"
68       git commit -m "${COMMIT_MESSAGE/MERGE/$name}" >> "$tmp" 2>&1
69    }
70     shift; 
71   done # submerge
72   logSuccessfulMerge $name
75 logSuccessfulMerge(){
76   echo `date` $name set to `git rev-parse --verify HEAD` >> $merge_hist
79 gittestmerge(){
80   case "$1" in
81     d|debug) shift
82       set -x; gittestmerge "$@";;
83     c|continue)
84       while read -er f; do
85         conflicted "$f" || { echo " \`$f' still contains conflicts, resolve them and continue, exiting"; failmessage=; exit 1; }
86         git add "$f" >> "$tmp" 2>&1
87       done < <( git status | sed -n 's/#\s*unmerged:\s*\(.*\)/\1/p' )
88       { read name; read x; set -- $x; } < $cont
89       submerge "$@"
90     ;;
91     u|update) shift
92       git config --get rerere.enabled >>/dev/null || {
93         echo ">> git rerere is disabled, maybe you want to enable it using the following command"
94         echo "# git config rerere.enabled 1"
95       }
96       names=$1;
97       if [ "$names" == "" ]; then
98         names=$(fst $(git config -l | sed -n "s/$me\\.\\([^=]*\\).*/\\1/p"))
99       else
100         shift
101       fi
102       for name in $names; do
103         echo -e "\nupdating merge $name"
104         set -- `git config --get "$me.$name"`
105         git checkout "$1" >> "$tmp" 2>&1 || {
106           grep 'error: you need to resolve your current index first' "$tmp" && { echo '        ^^^^^^^^^^^^ ';  exit 1; }
107         }
108         git branch -f "$name" "$1" >> "$tmp" 2>&1; shift # setting it to the first branch, could be another one
109         git checkout "$name" >> "$tmp" 2>&1
110         # try octopus first
111         echo "* merging using octopus"
112         { git merge -s octopus -m "${COMMIT_MESSAGE/MERGE/$name based on $@}" "$@" >> "$tmp" 2>&1 \
113           && logSuccessfulMerge $name
114         } || {
115           grep ' - not something we can merge' "$tmp" && { echo '^^^^^^^^^^^^ ';  exit 1; }
116           echo "octopus merge failed, resetting, using git merge multiple times .."
118           # remove all unmerged files before running git reset because I had a case where a file was left in work directory
119           # causing submerge failure
120           while read -er f; do
121             rm -fr "$f";
122           done < <( git status | sed -n 's/#\s*unmerged:\s*\(.*\)/\1/p' )
123           git reset --hard  >> "$tmp" 2>&1
124           submerge "$@"
125         }
126       done
127     ;;
128     s|set) shift
129       name="$1"; shift
130       IFS=, git config "$me.$name" "$*"
131     ;;
132     a|add) shift
133       name="$1"; shift
134       IFS=, git config "$me.$name" "`git config --get "$me.$name"` $*"
135     ;;
136     l|list)
137       git config -l | sed -n "s/$me\\.//p"
138     ;;
139     *) echo '
140       git-test-merge usage:
142       git-test-merge (s or set) name branch1 branch2 branch3
143          defines b
144       git-test-merge (a or add) name b1 b2
145          adds branches b1 b2 to merge name
146       git-test-merge (l or list) shows all defined merge sets
148       git-test-merge (u or update) list of names
149       if you omit the list of names the first entry will be updated
151       git-test-merge (c or continue) will continue merge (this name only)
153       update name will create a new branch called name by merging
154               branch1, branch2, branch3
155       If you commit to branch1 and you want the the merge
156       to be based on the last commit, run update again
158       if your first arg is (d or debug) set -x will be used.
159       ';;
160   esac
163 gittestmerge "$@"; # on failure script will exit with trap
164 failmessage=