mirror of
https://github.com/git/git.git
synced 2026-03-14 02:43:25 +01:00
git-merge: preserve and merge local changes when doing fast forward
The idea and the logic are identical to what "checkout -m" does when switching the branches. Instead of refusing the two-way merge, perform the three-way merge between the old head, the working tree and the new head, and leave the (potentially conflicted) merge result in the working tree. When the resulting conflict were too much to handle for the user, there is no easy way to get that back, so they are stashed away in $GIT_DIR/LOCAL_DIFF file. We do the same for "git checkout -m". If this turns out to be a sane thing to do, we probably should make the common logic between "checkout -m" and this into a built-in command. Signed-off-by: Junio C Hamano <junkio@cox.net>
This commit is contained in:
@@ -168,6 +168,9 @@ else
|
||||
exit 1 ;;
|
||||
esac
|
||||
|
||||
# First stash away the local changes
|
||||
git diff-index --binary -p HEAD >"$GIT_DIR"/LOCAL_DIFF
|
||||
|
||||
# Match the index to the working tree, and do a three-way.
|
||||
git diff-files --name-only | git update-index --remove --stdin &&
|
||||
work=`git write-tree` &&
|
||||
@@ -195,6 +198,10 @@ else
|
||||
sed -e 's/^[0-7]* [0-9a-f]* /'"0 $z40 /"
|
||||
echo "$unmerged"
|
||||
) | git update-index --index-info
|
||||
|
||||
echo >&2 "Conflicts in locally modified files:"
|
||||
git diff --name-only --diff-filter=U >&2
|
||||
echo >&2 "Your local changes are found in $GIT_DIR/LOCAL_DIFF"
|
||||
;;
|
||||
esac
|
||||
exit 0
|
||||
|
||||
47
git-merge.sh
47
git-merge.sh
@@ -91,6 +91,51 @@ finish () {
|
||||
esac
|
||||
}
|
||||
|
||||
merge_local_changes () {
|
||||
merge_error=$(git-read-tree -m -u $1 $2 2>&1) || (
|
||||
|
||||
# First stash away the local changes
|
||||
git diff-index --binary -p HEAD >"$GIT_DIR"/LOCAL_DIFF
|
||||
|
||||
# Match the index to the working tree, and do a three-way.
|
||||
git diff-files --name-only |
|
||||
git update-index --remove --stdin &&
|
||||
work=`git write-tree` &&
|
||||
git read-tree --reset -u $2 &&
|
||||
git read-tree -m -u --aggressive $1 $2 $work || exit
|
||||
|
||||
echo >&2 "Carrying local changes forward."
|
||||
if result=`git write-tree 2>/dev/null`
|
||||
then
|
||||
echo >&2 "Trivially automerged."
|
||||
else
|
||||
git merge-index -o git-merge-one-file -a
|
||||
fi
|
||||
|
||||
# Do not register the cleanly merged paths in the index
|
||||
# yet; this is not a real merge before committing, but
|
||||
# just carrying the working tree changes along.
|
||||
unmerged=`git ls-files -u`
|
||||
git read-tree --reset $2
|
||||
case "$unmerged" in
|
||||
'') ;;
|
||||
*)
|
||||
(
|
||||
z40=0000000000000000000000000000000000000000
|
||||
echo "$unmerged" |
|
||||
sed -e 's/^[0-7]* [0-9a-f]* /'"0 $z40 /"
|
||||
echo "$unmerged"
|
||||
) | git update-index --index-info
|
||||
|
||||
echo >&2 "Conflicts in locally modified files:"
|
||||
git diff --name-only --diff-filter=U >&2
|
||||
echo >&2 "Your local changes are found in $GIT_DIR/LOCAL_DIFF"
|
||||
;;
|
||||
esac
|
||||
exit 0
|
||||
)
|
||||
}
|
||||
|
||||
case "$#" in 0) usage ;; esac
|
||||
|
||||
rloga= have_message=
|
||||
@@ -264,7 +309,7 @@ f,*)
|
||||
echo "Updating $(git-rev-parse --short $head)..$(git-rev-parse --short $1)"
|
||||
git-update-index --refresh 2>/dev/null
|
||||
new_head=$(git-rev-parse --verify "$1^0") &&
|
||||
git-read-tree -u -v -m $head "$new_head" &&
|
||||
merge_local_changes $head $new_head &&
|
||||
finish "$new_head" "Fast forward"
|
||||
dropsave
|
||||
exit 0
|
||||
|
||||
Reference in New Issue
Block a user