Test commit
[cogito/jonas.git] / cg-Xmergefile
blobac9d356f9669931309640ffbe45486b6efb4491c
1 #!/usr/bin/env bash
3 # Merge two revisions of a file
4 # Copyright (c) Linus Torvalds, 2005
5 # Copyright (c) Petr Baudis, 2005, 2006
7 # This is the git per-file merge script, called with
9 # $1 - original file SHA1 (or empty)
10 # $2 - file in branch1 SHA1 (or empty)
11 # $3 - file in branch2 SHA1 (or empty)
12 # $4 - pathname in repository
13 # $5 - original file mode (or empty)
14 # $6 - file in branch1 mode (or empty)
15 # $7 - file in branch2 mode (or empty)
17 # We are designed to merge $3 _to_ $2, so we will give it
18 # a preference.
20 # FIXME: Make at least some effort to protect against checking in
21 # the conflicts.
23 # FIXME: What if a symlink replaces a regular file? What if symlinks conflict?
24 # What about directory-regularfile conflicts?
26 # ENVIRONMENT
27 # -----------
28 # _CG_MERGING_LOCAL::
29 # If set, we are merging local changes, not "real" three trees.
31 . "${COGITO_LIB}"cg-Xlib || exit 1
33 id0="${ARGS[0]}"
34 id1="${ARGS[1]}"
35 id2="${ARGS[2]}"
36 file="${ARGS[3]}"
37 mode0="${ARGS[4]}"
38 mode1="${ARGS[5]}"
39 mode2="${ARGS[6]}"
41 error()
43 echo "MERGE ERROR: $@" >&2
44 return 1
47 warning()
49 echo "MERGE WARNING: $@" >&2
52 # Returns stuff in $_pmxmc
53 # PlusMinus+XModeChar ;-)
54 pmxmc()
56 if [ "$1" = "755" ]; then
57 _pmxmc=+
58 else
59 _pmxmc=-
63 # Set ways[] to the symbolic names of the particular ways
64 load_unescaped_sym_ways()
66 if [ "$_CG_MERGING_LOCAL" ]; then
67 ways=("original" "local" "target")
68 else
69 ways=("merge base" "$_git_head" "$(cat "$_git/cg-merge-state/merging-sym")")
72 load_sym_ways()
74 load_unescaped_sym_ways
75 ways[0]="${ways[0]// //}"
76 ways=("${ways[@]//\//~}")
80 case "${id0:-.}${id1:-.}${id2:-.}" in
82 # Deleted in both or deleted in one and unchanged in the other
84 "$id0.." | "$id0.$id0" | "$id0$id0.")
85 #echo "Removing $file"
86 if test -f "$file"; then
87 rm -f -- "$file"
88 fi &&
89 exec git-update-index --remove -- "$file"
93 # Deleted in one and changed in the other
95 "$id0$id1." | "$id0.$id2")
96 #echo "Removing $file"
97 filev="$file"
98 load_sym_ways
99 if [ "$id1" ]; then
100 num=1; mode="$mode1"; id="$id1"
101 else
102 num=2; mode="$mode2"; id="$id2"
104 while [ -e "$filev~${ways[0]}" ] || [ -e "$filev~${ways[$num]}" ]; do
105 filev="$filev~"
106 done
107 error "File $file removed in one branch but modified in the other!"
108 error "The original version saved as '$filev~${ways[0]}', the modified one as '$filev~${ways[$num]}'."
109 git-update-index --add --cacheinfo "$mode0" "$id0" "$file" &&
110 git-checkout-index -u -f -- "$file" &&
111 mv "$file" "$filev~${ways[0]}" ||
112 error "Cannot create '$filev~${ways[0]}'"
113 git-update-index --add --cacheinfo "$mode" "$id" "$file" &&
114 git-checkout-index -u -f -- "$file" &&
115 mv "$file" "$filev~${ways[$num]}" ||
116 error "Cannot create '$filev~${ways[$num]}'"
117 git-update-index --force-remove "$file"
120 # Added in one.
122 ".$id1." | "..$id2" )
123 #echo "Adding $file"
124 git-update-index --add --cacheinfo "$mode1$mode2" "$id1$id2" "$file" &&
125 exec git-checkout-index -u -f -- "$file"
129 # Added same in both (check for same permissions).
131 ".$id2$id1")
132 #echo "Adding $file"
133 git-update-index --add --cacheinfo "$mode1" "$id1" "$file" &&
134 git-checkout-index -u -f -- "$file"
135 ret=$?
136 if [ "$mode1" != "$mode2" ]; then
137 pmxmc "$mode2"; chmod ${_pmxmc}x "$file"
138 error "$file: added in both branches, permissions conflict $mode1->$mode2 (defaulting to $mode2)"
139 exit 1
141 exit $ret
145 # Added in both (different in each).
147 ".$id1$id2")
148 #echo "Adding $file"
149 filev="$file"
150 load_sym_ways
151 while [ -e "$filev~${ways[1]}" ] || [ -e "$filev~${ways[2]}" ]; do
152 filev="$filev~"
153 done
154 error "File $file added in both branches, but different in each!"
155 error "Conflicting versions saved as '$filev~${ways[1]}' and '$filev~${ways[2]}'."
156 git-update-index --add --cacheinfo "$mode1" "$id1" "$file" &&
157 git-checkout-index -u -f -- "$file" &&
158 mv "$file" "$filev~${ways[1]}" ||
159 error "Cannot create '$filev~${ways[1]}'"
160 git-update-index --add --cacheinfo "$mode2" "$id2" "$file" &&
161 git-checkout-index -u -f -- "$file" &&
162 mv "$file" "$filev~${ways[2]}" ||
163 error "Cannot create '$filev~${ways[2]}'"
164 exit 1
168 # Modified in both, but differently.
170 "$id0$id1$id2")
171 echo "... Auto-merging $file"
172 orig=$(git-unpack-file $id0)
173 src2=$(git-unpack-file $id2)
174 merged=$(mktemp .mergeresult-XXXXXX)
176 load_unescaped_sym_ways
177 # We reset the index to the first branch, making
178 # git-diff-file useful
179 git-update-index --add --cacheinfo "$mode1" "$id1" "$file"
180 git-checkout-index -u -f -- "$file" &&
181 { diff3 -m -E -L "${ways[1]}" -L "${ways[0]}" -L "${ways[2]}" "$file" "$orig" "$src2" >"$merged"; }
182 ret=$?
183 rm -f -- "$orig" "$src2"
184 cat "$merged" >"$file"
185 rm "$merged"
187 if [ "$mode1" != "$mode2" ]; then
188 if [ "$mode0" = "$mode1" ]; then
189 moded="$mode2"
190 else
191 moded="$mode1"
193 pmxmc "$moded"; chmod ${_pmxmc}x "$file"
194 error "Permissions conflict: $mode0->$mode1,$mode2 (defaulting to $moded)"
195 ret=1
198 if [ $ret -ne 0 ]; then
199 echo " CONFLICTS during merge." >&2
200 exit 1
202 exec git-update-index -- "$file"
206 error "$file: Not handling case: ${id0:-empty} -> ${id1:-empty} -> ${id2:-empty} (this would be a Cogito bug, please report it)"
208 esac
209 exit 1