Skip to content

Commit ab02095

Browse files
committed
Merge branch 'jm/mergetool-submodules' into maint
* jm/mergetool-submodules: mergetool: Teach about submodules
2 parents 92b501f + ff7f089 commit ab02095

File tree

2 files changed

+371
-9
lines changed

2 files changed

+371
-9
lines changed

git-mergetool.sh

Lines changed: 84 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ is_symlink () {
2121
test "$1" = 120000
2222
}
2323

24+
is_submodule () {
25+
test "$1" = 160000
26+
}
27+
2428
local_present () {
2529
test -n "$local_mode"
2630
}
@@ -35,7 +39,8 @@ base_present () {
3539

3640
cleanup_temp_files () {
3741
if test "$1" = --save-backup ; then
38-
mv -- "$BACKUP" "$MERGED.orig"
42+
rm -rf -- "$MERGED.orig"
43+
test -e "$BACKUP" && mv -- "$BACKUP" "$MERGED.orig"
3944
rm -f -- "$LOCAL" "$REMOTE" "$BASE"
4045
else
4146
rm -f -- "$LOCAL" "$REMOTE" "$BASE" "$BACKUP"
@@ -52,11 +57,13 @@ describe_file () {
5257
echo "deleted"
5358
elif is_symlink "$mode" ; then
5459
echo "a symbolic link -> '$(cat "$file")'"
60+
elif is_submodule "$mode" ; then
61+
echo "submodule commit $file"
5562
else
5663
if base_present; then
57-
echo "modified"
64+
echo "modified file"
5865
else
59-
echo "created"
66+
echo "created file"
6067
fi
6168
fi
6269
}
@@ -112,6 +119,67 @@ resolve_deleted_merge () {
112119
done
113120
}
114121

122+
resolve_submodule_merge () {
123+
while true; do
124+
printf "Use (l)ocal or (r)emote, or (a)bort? "
125+
read ans
126+
case "$ans" in
127+
[lL]*)
128+
if ! local_present; then
129+
if test -n "$(git ls-tree HEAD -- "$MERGED")"; then
130+
# Local isn't present, but it's a subdirectory
131+
git ls-tree --full-name -r HEAD -- "$MERGED" | git update-index --index-info || exit $?
132+
else
133+
test -e "$MERGED" && mv -- "$MERGED" "$BACKUP"
134+
git update-index --force-remove "$MERGED"
135+
cleanup_temp_files --save-backup
136+
fi
137+
elif is_submodule "$local_mode"; then
138+
stage_submodule "$MERGED" "$local_sha1"
139+
else
140+
git checkout-index -f --stage=2 -- "$MERGED"
141+
git add -- "$MERGED"
142+
fi
143+
return 0
144+
;;
145+
[rR]*)
146+
if ! remote_present; then
147+
if test -n "$(git ls-tree MERGE_HEAD -- "$MERGED")"; then
148+
# Remote isn't present, but it's a subdirectory
149+
git ls-tree --full-name -r MERGE_HEAD -- "$MERGED" | git update-index --index-info || exit $?
150+
else
151+
test -e "$MERGED" && mv -- "$MERGED" "$BACKUP"
152+
git update-index --force-remove "$MERGED"
153+
fi
154+
elif is_submodule "$remote_mode"; then
155+
! is_submodule "$local_mode" && test -e "$MERGED" && mv -- "$MERGED" "$BACKUP"
156+
stage_submodule "$MERGED" "$remote_sha1"
157+
else
158+
test -e "$MERGED" && mv -- "$MERGED" "$BACKUP"
159+
git checkout-index -f --stage=3 -- "$MERGED"
160+
git add -- "$MERGED"
161+
fi
162+
cleanup_temp_files --save-backup
163+
return 0
164+
;;
165+
[aA]*)
166+
return 1
167+
;;
168+
esac
169+
done
170+
}
171+
172+
stage_submodule () {
173+
path="$1"
174+
submodule_sha1="$2"
175+
mkdir -p "$path" || die "fatal: unable to create directory for module at $path"
176+
# Find $path relative to work tree
177+
work_tree_root=$(cd_to_toplevel && pwd)
178+
work_rel_path=$(cd "$path" && GIT_WORK_TREE="${work_tree_root}" git rev-parse --show-prefix)
179+
test -n "$work_rel_path" || die "fatal: unable to get path of module $path relative to work tree"
180+
git update-index --add --replace --cacheinfo 160000 "$submodule_sha1" "${work_rel_path%/}" || die
181+
}
182+
115183
checkout_staged_file () {
116184
tmpfile=$(expr "$(git checkout-index --temp --stage="$1" "$2")" : '\([^ ]*\) ')
117185

@@ -139,13 +207,23 @@ merge_file () {
139207
REMOTE="./$MERGED.REMOTE.$ext"
140208
BASE="./$MERGED.BASE.$ext"
141209

142-
mv -- "$MERGED" "$BACKUP"
143-
cp -- "$BACKUP" "$MERGED"
144-
145210
base_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==1) print $1;}')
146211
local_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==2) print $1;}')
147212
remote_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==3) print $1;}')
148213

214+
if is_submodule "$local_mode" || is_submodule "$remote_mode"; then
215+
echo "Submodule merge conflict for '$MERGED':"
216+
local_sha1=$(git ls-files -u -- "$MERGED" | awk '{if ($3==2) print $2;}')
217+
remote_sha1=$(git ls-files -u -- "$MERGED" | awk '{if ($3==3) print $2;}')
218+
describe_file "$local_mode" "local" "$local_sha1"
219+
describe_file "$remote_mode" "remote" "$remote_sha1"
220+
resolve_submodule_merge
221+
return
222+
fi
223+
224+
mv -- "$MERGED" "$BACKUP"
225+
cp -- "$BACKUP" "$MERGED"
226+
149227
base_present && checkout_staged_file 1 "$MERGED" "$BASE"
150228
local_present && checkout_staged_file 2 "$MERGED" "$LOCAL"
151229
remote_present && checkout_staged_file 3 "$MERGED" "$REMOTE"

0 commit comments

Comments
 (0)