Skip to content

Commit

Permalink
Fix overzealous cleanliness check in git-merge
Browse files Browse the repository at this point in the history
Being able to try multiple strategies and automatically picking one
that seems to give less conflicting result may or may not much sense
in practice.  At least that should not force normal use case to
additionally require the working tree to be fully clean.  As Linus
shouted, local changes do not matter unless they interfere with the
merge.

This commit changes git-merge not to require a clean working tree.
Only when we will iterate through more than one merge strategies,
local changes are stashed away before trying the first merge, and
restored before second and later merges are attempted.

The index file must be in sync with HEAD in any case -- otherwise the
merge result would contain changes since HEAD that was done locally
and registered in the index.  This check is already enforced by
three-way read-tree existing merge strategies use, but is done here as
a safeguard as well.

Signed-off-by: Junio C Hamano <junkio@cox.net>
  • Loading branch information
Junio C Hamano committed Sep 27, 2005
1 parent 036a72d commit a935824
Showing 1 changed file with 50 additions and 18 deletions.
68 changes: 50 additions & 18 deletions git-merge.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,19 @@ all_strategies='recursive octopus resolve stupid'
default_strategies='resolve octopus'
use_strategies=

dropheads() {
rm -f -- "$GIT_DIR/MERGE_HEAD" || exit 1
dropsave() {
rm -f -- "$GIT_DIR/MERGE_HEAD" \
"$GIT_DIR/MERGE_SAVE" || exit 1
}

savestate() {
git diff -r -z --name-only $head | cpio -0 -o >"$GIR_DIR/MERGE_SAVE"
}

restorestate() {
git reset --hard $head
cpio -iuv <"$GIT_DIR/MERGE_SAVE"
git-update-index --refresh >/dev/null
}

summary() {
Expand Down Expand Up @@ -93,7 +104,7 @@ case "$#,$common" in
# If head can reach all the merge then we are up to date.
# but first the most common case of merging one remote
echo "Already up-to-date. Yeeah!"
dropheads
dropsave
exit 0
;;
1,"$head")
Expand All @@ -103,7 +114,7 @@ case "$#,$common" in
git-read-tree -u -m $head "$1" || exit 1
git-rev-parse --verify "$1^0" > "$GIT_DIR/HEAD"
summary "$1"
dropheads
dropsave
exit 0
;;
1,*)
Expand All @@ -125,30 +136,51 @@ case "$#,$common" in
if test "$up_to_date" = t
then
echo "Already up-to-date. Yeeah!"
dropheads
dropsave
exit 0
fi
;;
esac

# At this point we need a real merge. Require that the tree matches
# exactly our head.
# At this point, we need a real merge. No matter what strategy
# we use, it would operate on the index, possibly affecting the
# working tree, and when resolved cleanly, have the desired tree
# in the index -- this means that the index must be in sync with
# the $head commit.
files=$(git-diff-index --cached --name-only $head) || exit
if [ "$files" ]; then
echo >&2 "Dirty index: cannot merge (dirty: $files)"
exit 1
fi

git-update-index --refresh &&
test '' = "`git-diff-index --cached --name-only $head`" || {
die "Need real merge but the working tree has local changes."
}
case "$use_strategies" in
?*' '?*)
# Stash away the local changes so that we can try more than one.
savestate
single_strategy=no
;;
*)
single_strategy=yes
;;
esac

result_tree= best_cnt=-1 best_strategy= wt_strategy=
for strategy in $use_strategies
do
test "$wt_strategy" = '' || {
echo "Rewinding the tree to pristine..."
git reset --hard $head
restorestate
}
echo "Trying merge strategy $strategy..."
case "$single_strategy" in
no)
echo "Trying merge strategy $strategy..."
;;
esac

# Remember which strategy left the state in the working tree
wt_strategy=$strategy
git-merge-$strategy $common -- $head_arg "$@" || {

git-merge-$strategy $common -- "$head_arg" "$@" || {

# The backend exits with 1 when conflicts are left to be resolved,
# with 2 when it does not handle the given merge at all.
Expand Down Expand Up @@ -186,24 +218,24 @@ then
echo "Committed merge $result_commit, made by $wt_strategy."
echo $result_commit >"$GIT_DIR/HEAD"
summary $result_commit
dropheads
dropsave
exit 0
fi

# Pick the result from the best strategy and have the user fix it up.
case "$best_strategy" in
'')
git reset --hard $head
restorestate
die "No merge strategy handled the merge."
;;
"$wt_strategy")
# We already have its result in the working tree.
;;
*)
echo "Rewinding the tree to pristine..."
git reset --hard $head
restorestate
echo "Using the $best_strategy to prepare resolving by hand."
git-merge-$best_strategy $common -- $head_arg "$@"
git-merge-$best_strategy $common -- "$head_arg" "$@"
;;
esac
for remote
Expand Down

0 comments on commit a935824

Please sign in to comment.