mirror of
https://github.com/git/git.git
synced 2026-01-09 17:46:37 +00:00
mergetool: Teach about submodules
When the index has conflicted submodules, mergetool used to mildly
clobber the module, renaming it to mymodule.BACKUP.nnnn, then failing to
copy it non-recursively.
Recognize submodules and offer a resolution instead:
Submodule merge conflict for 'Shared':
{local}: submodule commit ad9f12e3e6205381bf2163a793d1e596a9e211d0
{remote}: submodule commit f5893fb70ec5646efcd9aa643c5136753ac89253
Use (l)ocal or (r)emote, or (a)bort?
Selecting a commit will stage it, but not update the submodule (as git
does had there been no conflict). Type changes are also supported,
should the path be a submodule on one side, and a file, symlink,
directory, or deleted on the other.
Signed-off-by: Jonathon Mah <me@JonathonMah.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
committed by
Junio C Hamano
parent
c3f6163b0b
commit
ff7f089ed1
@@ -21,6 +21,10 @@ is_symlink () {
|
||||
test "$1" = 120000
|
||||
}
|
||||
|
||||
is_submodule () {
|
||||
test "$1" = 160000
|
||||
}
|
||||
|
||||
local_present () {
|
||||
test -n "$local_mode"
|
||||
}
|
||||
@@ -35,7 +39,8 @@ base_present () {
|
||||
|
||||
cleanup_temp_files () {
|
||||
if test "$1" = --save-backup ; then
|
||||
mv -- "$BACKUP" "$MERGED.orig"
|
||||
rm -rf -- "$MERGED.orig"
|
||||
test -e "$BACKUP" && mv -- "$BACKUP" "$MERGED.orig"
|
||||
rm -f -- "$LOCAL" "$REMOTE" "$BASE"
|
||||
else
|
||||
rm -f -- "$LOCAL" "$REMOTE" "$BASE" "$BACKUP"
|
||||
@@ -52,11 +57,13 @@ describe_file () {
|
||||
echo "deleted"
|
||||
elif is_symlink "$mode" ; then
|
||||
echo "a symbolic link -> '$(cat "$file")'"
|
||||
elif is_submodule "$mode" ; then
|
||||
echo "submodule commit $file"
|
||||
else
|
||||
if base_present; then
|
||||
echo "modified"
|
||||
echo "modified file"
|
||||
else
|
||||
echo "created"
|
||||
echo "created file"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
@@ -112,6 +119,67 @@ resolve_deleted_merge () {
|
||||
done
|
||||
}
|
||||
|
||||
resolve_submodule_merge () {
|
||||
while true; do
|
||||
printf "Use (l)ocal or (r)emote, or (a)bort? "
|
||||
read ans
|
||||
case "$ans" in
|
||||
[lL]*)
|
||||
if ! local_present; then
|
||||
if test -n "$(git ls-tree HEAD -- "$MERGED")"; then
|
||||
# Local isn't present, but it's a subdirectory
|
||||
git ls-tree --full-name -r HEAD -- "$MERGED" | git update-index --index-info || exit $?
|
||||
else
|
||||
test -e "$MERGED" && mv -- "$MERGED" "$BACKUP"
|
||||
git update-index --force-remove "$MERGED"
|
||||
cleanup_temp_files --save-backup
|
||||
fi
|
||||
elif is_submodule "$local_mode"; then
|
||||
stage_submodule "$MERGED" "$local_sha1"
|
||||
else
|
||||
git checkout-index -f --stage=2 -- "$MERGED"
|
||||
git add -- "$MERGED"
|
||||
fi
|
||||
return 0
|
||||
;;
|
||||
[rR]*)
|
||||
if ! remote_present; then
|
||||
if test -n "$(git ls-tree MERGE_HEAD -- "$MERGED")"; then
|
||||
# Remote isn't present, but it's a subdirectory
|
||||
git ls-tree --full-name -r MERGE_HEAD -- "$MERGED" | git update-index --index-info || exit $?
|
||||
else
|
||||
test -e "$MERGED" && mv -- "$MERGED" "$BACKUP"
|
||||
git update-index --force-remove "$MERGED"
|
||||
fi
|
||||
elif is_submodule "$remote_mode"; then
|
||||
! is_submodule "$local_mode" && test -e "$MERGED" && mv -- "$MERGED" "$BACKUP"
|
||||
stage_submodule "$MERGED" "$remote_sha1"
|
||||
else
|
||||
test -e "$MERGED" && mv -- "$MERGED" "$BACKUP"
|
||||
git checkout-index -f --stage=3 -- "$MERGED"
|
||||
git add -- "$MERGED"
|
||||
fi
|
||||
cleanup_temp_files --save-backup
|
||||
return 0
|
||||
;;
|
||||
[aA]*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
stage_submodule () {
|
||||
path="$1"
|
||||
submodule_sha1="$2"
|
||||
mkdir -p "$path" || die "fatal: unable to create directory for module at $path"
|
||||
# Find $path relative to work tree
|
||||
work_tree_root=$(cd_to_toplevel && pwd)
|
||||
work_rel_path=$(cd "$path" && GIT_WORK_TREE="${work_tree_root}" git rev-parse --show-prefix)
|
||||
test -n "$work_rel_path" || die "fatal: unable to get path of module $path relative to work tree"
|
||||
git update-index --add --replace --cacheinfo 160000 "$submodule_sha1" "${work_rel_path%/}" || die
|
||||
}
|
||||
|
||||
checkout_staged_file () {
|
||||
tmpfile=$(expr "$(git checkout-index --temp --stage="$1" "$2")" : '\([^ ]*\) ')
|
||||
|
||||
@@ -139,13 +207,23 @@ merge_file () {
|
||||
REMOTE="./$MERGED.REMOTE.$ext"
|
||||
BASE="./$MERGED.BASE.$ext"
|
||||
|
||||
mv -- "$MERGED" "$BACKUP"
|
||||
cp -- "$BACKUP" "$MERGED"
|
||||
|
||||
base_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==1) print $1;}')
|
||||
local_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==2) print $1;}')
|
||||
remote_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==3) print $1;}')
|
||||
|
||||
if is_submodule "$local_mode" || is_submodule "$remote_mode"; then
|
||||
echo "Submodule merge conflict for '$MERGED':"
|
||||
local_sha1=$(git ls-files -u -- "$MERGED" | awk '{if ($3==2) print $2;}')
|
||||
remote_sha1=$(git ls-files -u -- "$MERGED" | awk '{if ($3==3) print $2;}')
|
||||
describe_file "$local_mode" "local" "$local_sha1"
|
||||
describe_file "$remote_mode" "remote" "$remote_sha1"
|
||||
resolve_submodule_merge
|
||||
return
|
||||
fi
|
||||
|
||||
mv -- "$MERGED" "$BACKUP"
|
||||
cp -- "$BACKUP" "$MERGED"
|
||||
|
||||
base_present && checkout_staged_file 1 "$MERGED" "$BASE"
|
||||
local_present && checkout_staged_file 2 "$MERGED" "$LOCAL"
|
||||
remote_present && checkout_staged_file 3 "$MERGED" "$REMOTE"
|
||||
|
||||
Reference in New Issue
Block a user