2005-04-18 21:15:10 +02:00
|
|
|
#!/bin/sh
|
|
|
|
#
|
2005-06-09 01:38:20 +02:00
|
|
|
# Copyright (c) Linus Torvalds, 2005
|
|
|
|
#
|
|
|
|
# This is the git per-file merge script, called with
|
2005-04-18 21:15:10 +02:00
|
|
|
#
|
2005-04-18 23:17:58 +02:00
|
|
|
# $1 - original file SHA1 (or empty)
|
|
|
|
# $2 - file in branch1 SHA1 (or empty)
|
|
|
|
# $3 - file in branch2 SHA1 (or empty)
|
2005-04-18 21:15:10 +02:00
|
|
|
# $4 - pathname in repository
|
2006-07-10 07:50:18 +02:00
|
|
|
# $5 - original file mode (or empty)
|
2005-05-02 08:53:32 +02:00
|
|
|
# $6 - file in branch1 mode (or empty)
|
|
|
|
# $7 - file in branch2 mode (or empty)
|
2005-04-18 21:15:10 +02:00
|
|
|
#
|
2005-04-18 23:17:58 +02:00
|
|
|
# Handle some trivial cases.. The _really_ trivial cases have
|
2007-07-03 07:52:14 +02:00
|
|
|
# been handled already by git read-tree, but that one doesn't
|
2005-06-09 01:38:20 +02:00
|
|
|
# do any merges that might change the tree layout.
|
2005-04-19 04:55:19 +02:00
|
|
|
|
2009-11-09 16:04:53 +01:00
|
|
|
USAGE='<orig blob> <our blob> <their blob> <path>'
|
|
|
|
USAGE="$USAGE <orig mode> <our mode> <their mode>"
|
2013-02-24 01:50:12 +01:00
|
|
|
LONG_USAGE="usage: git merge-one-file $USAGE
|
2009-11-09 16:04:53 +01:00
|
|
|
|
|
|
|
Blob ids and modes should be empty for missing files."
|
|
|
|
|
2011-04-30 00:24:32 +02:00
|
|
|
SUBDIRECTORY_OK=Yes
|
|
|
|
. git-sh-setup
|
|
|
|
cd_to_toplevel
|
|
|
|
require_work_tree
|
|
|
|
|
2013-03-24 13:26:23 +01:00
|
|
|
if test $# != 7
|
2009-11-09 16:04:53 +01:00
|
|
|
then
|
|
|
|
echo "$LONG_USAGE"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
2005-04-18 23:17:58 +02:00
|
|
|
case "${1:-.}${2:-.}${3:-.}" in
|
2005-04-18 21:15:10 +02:00
|
|
|
#
|
2005-06-09 02:56:09 +02:00
|
|
|
# Deleted in both or deleted in one and unchanged in the other
|
2005-04-18 21:15:10 +02:00
|
|
|
#
|
2005-06-09 02:56:09 +02:00
|
|
|
"$1.." | "$1.$1" | "$1$1.")
|
2015-10-26 22:39:39 +01:00
|
|
|
if { test -z "$6" && test "$5" != "$7"; } ||
|
|
|
|
{ test -z "$7" && test "$5" != "$6"; }
|
|
|
|
then
|
|
|
|
echo "ERROR: File $4 deleted on one branch but had its" >&2
|
|
|
|
echo "ERROR: permissions changed on the other." >&2
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
2013-03-24 13:26:23 +01:00
|
|
|
if test -n "$2"
|
|
|
|
then
|
[PATCH] Make "git resolve" less scary
When we resolve a merge between two branches, and it removes a file in the
current branch, we notify the person doing the resolve with a big nice
notice like
Removing xyzzy
which is all well and good.
HOWEVER, we also do this when the file was actually removed in the current
branch, and we're merging with another branch that didn't have it removed
(or, indeed, if the other branch _did_ have it removed, but the common
parent was far enough back that the file still existed in there).
And that just doesn't make sense. In that case we're not removing
anything: the file didn't exist in the branch we're merging into in the
first place. So the message just makes people nervous, and makes no sense.
This has been around forever, but I never bothered to do anything about
it.
Until now.
The trivial fix is to only talk about removing files if the file existed
in the branch we're merging into, but will not exist in the result.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-08-30 07:36:16 +02:00
|
|
|
echo "Removing $4"
|
2006-10-09 07:48:06 +02:00
|
|
|
else
|
|
|
|
# read-tree checked that index matches HEAD already,
|
|
|
|
# so we know we do not have this path tracked.
|
|
|
|
# there may be an unrelated working tree file here,
|
2007-07-08 23:42:05 +02:00
|
|
|
# which we should just leave unmolested. Make sure
|
|
|
|
# we do not have it in the index, though.
|
|
|
|
exec git update-index --remove -- "$4"
|
[PATCH] Make "git resolve" less scary
When we resolve a merge between two branches, and it removes a file in the
current branch, we notify the person doing the resolve with a big nice
notice like
Removing xyzzy
which is all well and good.
HOWEVER, we also do this when the file was actually removed in the current
branch, and we're merging with another branch that didn't have it removed
(or, indeed, if the other branch _did_ have it removed, but the common
parent was far enough back that the file still existed in there).
And that just doesn't make sense. In that case we're not removing
anything: the file didn't exist in the branch we're merging into in the
first place. So the message just makes people nervous, and makes no sense.
This has been around forever, but I never bothered to do anything about
it.
Until now.
The trivial fix is to only talk about removing files if the file existed
in the branch we're merging into, but will not exist in the result.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-08-30 07:36:16 +02:00
|
|
|
fi
|
2013-03-24 13:26:23 +01:00
|
|
|
if test -f "$4"
|
|
|
|
then
|
2005-11-20 04:50:44 +01:00
|
|
|
rm -f -- "$4" &&
|
2006-04-14 00:01:24 +02:00
|
|
|
rmdir -p "$(expr "z$4" : 'z\(.*\)/')" 2>/dev/null || :
|
2005-06-25 11:24:50 +02:00
|
|
|
fi &&
|
2007-07-03 07:52:14 +02:00
|
|
|
exec git update-index --remove -- "$4"
|
2005-06-09 01:38:20 +02:00
|
|
|
;;
|
|
|
|
|
2005-04-18 21:15:10 +02:00
|
|
|
#
|
2005-05-02 08:53:32 +02:00
|
|
|
# Added in one.
|
2005-04-18 21:15:10 +02:00
|
|
|
#
|
2006-10-09 07:48:06 +02:00
|
|
|
".$2.")
|
|
|
|
# the other side did not add and we added so there is nothing
|
2007-07-08 23:42:05 +02:00
|
|
|
# to be done, except making the path merged.
|
|
|
|
exec git update-index --add --cacheinfo "$6" "$2" "$4"
|
2006-10-09 07:48:06 +02:00
|
|
|
;;
|
|
|
|
"..$3")
|
2005-06-09 02:56:09 +02:00
|
|
|
echo "Adding $4"
|
2008-03-18 00:47:18 +01:00
|
|
|
if test -f "$4"
|
|
|
|
then
|
2013-03-24 13:26:24 +01:00
|
|
|
echo "ERROR: untracked $4 is overwritten by the merge." >&2
|
2006-10-09 07:48:06 +02:00
|
|
|
exit 1
|
2008-03-18 00:47:18 +01:00
|
|
|
fi
|
2007-07-08 23:42:05 +02:00
|
|
|
git update-index --add --cacheinfo "$7" "$3" "$4" &&
|
2007-07-03 07:52:14 +02:00
|
|
|
exec git checkout-index -u -f -- "$4"
|
2005-06-09 01:38:20 +02:00
|
|
|
;;
|
|
|
|
|
2005-04-24 05:50:10 +02:00
|
|
|
#
|
2005-11-08 07:03:46 +01:00
|
|
|
# Added in both, identically (check for same permissions).
|
2005-04-24 05:50:10 +02:00
|
|
|
#
|
2005-05-02 08:53:32 +02:00
|
|
|
".$3$2")
|
2013-03-24 13:26:23 +01:00
|
|
|
if test "$6" != "$7"
|
|
|
|
then
|
2013-03-24 13:26:24 +01:00
|
|
|
echo "ERROR: File $4 added identically in both branches," >&2
|
|
|
|
echo "ERROR: but permissions conflict $6->$7." >&2
|
2005-04-24 05:50:10 +02:00
|
|
|
exit 1
|
|
|
|
fi
|
2005-06-09 02:56:09 +02:00
|
|
|
echo "Adding $4"
|
2007-07-03 07:52:14 +02:00
|
|
|
git update-index --add --cacheinfo "$6" "$2" "$4" &&
|
|
|
|
exec git checkout-index -u -f -- "$4"
|
2005-06-09 01:38:20 +02:00
|
|
|
;;
|
|
|
|
|
2005-04-18 23:17:58 +02:00
|
|
|
#
|
2005-05-02 08:53:32 +02:00
|
|
|
# Modified in both, but differently.
|
2005-04-18 23:17:58 +02:00
|
|
|
#
|
2005-11-08 07:03:46 +01:00
|
|
|
"$1$2$3" | ".$2$3")
|
2005-12-02 09:54:50 +01:00
|
|
|
|
|
|
|
case ",$6,$7," in
|
|
|
|
*,120000,*)
|
2013-03-24 13:26:24 +01:00
|
|
|
echo "ERROR: $4: Not merging symbolic link changes." >&2
|
2005-12-02 09:54:50 +01:00
|
|
|
exit 1
|
|
|
|
;;
|
2007-12-10 20:22:05 +01:00
|
|
|
*,160000,*)
|
2013-03-24 13:26:24 +01:00
|
|
|
echo "ERROR: $4: Not merging conflicting submodule changes." >&2
|
2007-12-10 20:22:05 +01:00
|
|
|
exit 1
|
|
|
|
;;
|
2005-12-02 09:54:50 +01:00
|
|
|
esac
|
|
|
|
|
mergetools/p4merge: create a base if none available
Originally, with no base, Git gave P4Merge $LOCAL as a dummy base:
p4merge "$LOCAL" "$LOCAL" "$REMOTE" "$MERGED"
Commit 0a0ec7bd changed this to:
p4merge "empty file" "$LOCAL" "$REMOTE" "$MERGED"
to avoid the problem of being unable to save in some circumstances with
similar inputs.
Unfortunately this approach produces much worse results on differing
inputs. P4Merge really regards the blank file as the base, and once you
have just a couple of differences between the two branches you end up
with one a massive full-file conflict. The 3-way diff is not readable,
and you have to invoke "difftool MERGE_HEAD HEAD" manually to get a
useful view.
The original approach appears to have invoked special 2-way merge
behaviour in P4Merge that occurs only if the base filename is "" or
equal to the left input. You get a good visual comparison, and it does
not auto-resolve differences. (Normally if one branch matched the base,
it would autoresolve to the other branch).
But there appears to be no way of getting this 2-way behaviour and being
able to reliably save. Having base==left appears to be triggering other
assumptions. There are tricks the user can use to force the save icon
on, but it's not intuitive.
So we now follow a suggestion given in the original patch's discussion:
generate a virtual base, consisting of the lines common to the two
branches. This is the same as the technique used in resolve and octopus
merges, so we relocate that code to a shared function.
Note that if there are no differences at the same location, this
technique can lead to automatic resolution without conflict, combining
everything from the 2 files. As with the other merges using this
technique, we assume the user will inspect the result before saving.
Signed-off-by: Kevin Bracey <kevin@bracey.fi>
Reviewed-by: David Aguilar <davvid@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-03-13 02:12:21 +01:00
|
|
|
src1=$(git-unpack-file $2)
|
|
|
|
src2=$(git-unpack-file $3)
|
2005-11-08 07:03:46 +01:00
|
|
|
case "$1" in
|
|
|
|
'')
|
|
|
|
echo "Added $4 in both, but differently."
|
merge-one-file: use empty blob for add/add base
When we see an add/add conflict on a file, we generate the
conflicted content by doing a 3-way merge with a "virtual"
base consisting of the common lines of the two sides. This
strategy dates back to cb93c19 (merge-one-file: use common
as base, instead of emptiness., 2005-11-09).
Back then, the next step was to call rcs merge to generate
the 3-way conflicts. Using the virtual base produced much
better results, as rcs merge does not attempt to minimize
the hunks. As a result, you'd get a conflict with the
entirety of the files on either side.
Since then, though, we've switched to using git-merge-file,
which uses xdiff's "zealous" merge. This will find the
minimal hunks even with just the simple, empty base.
Let's switch to using that empty base. It's simpler, more
efficient, and reduces our dependencies (we no longer need a
working diff binary). It's also how the merge-recursive
strategy handles this same case.
We can almost get rid of git-sh-setup's create_virtual_base,
but we don't here, for two reasons:
1. The functions in git-sh-setup are part of our public
interface, so it's possible somebody is depending on
it. We'd at least need to deprecate it first.
2. It's also used by mergetool's p4merge driver. It's
unknown whether its 3-way merge is as capable as git's;
if not, then it is benefiting from the function.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-23 07:04:41 +01:00
|
|
|
orig=$(git-unpack-file e69de29bb2d1d6434b8b29ae775ad8c2e48c5391)
|
2005-11-08 07:03:46 +01:00
|
|
|
;;
|
|
|
|
*)
|
2006-01-05 12:46:16 +01:00
|
|
|
echo "Auto-merging $4"
|
mergetools/p4merge: create a base if none available
Originally, with no base, Git gave P4Merge $LOCAL as a dummy base:
p4merge "$LOCAL" "$LOCAL" "$REMOTE" "$MERGED"
Commit 0a0ec7bd changed this to:
p4merge "empty file" "$LOCAL" "$REMOTE" "$MERGED"
to avoid the problem of being unable to save in some circumstances with
similar inputs.
Unfortunately this approach produces much worse results on differing
inputs. P4Merge really regards the blank file as the base, and once you
have just a couple of differences between the two branches you end up
with one a massive full-file conflict. The 3-way diff is not readable,
and you have to invoke "difftool MERGE_HEAD HEAD" manually to get a
useful view.
The original approach appears to have invoked special 2-way merge
behaviour in P4Merge that occurs only if the base filename is "" or
equal to the left input. You get a good visual comparison, and it does
not auto-resolve differences. (Normally if one branch matched the base,
it would autoresolve to the other branch).
But there appears to be no way of getting this 2-way behaviour and being
able to reliably save. Having base==left appears to be triggering other
assumptions. There are tricks the user can use to force the save icon
on, but it's not intuitive.
So we now follow a suggestion given in the original patch's discussion:
generate a virtual base, consisting of the lines common to the two
branches. This is the same as the technique used in resolve and octopus
merges, so we relocate that code to a shared function.
Note that if there are no differences at the same location, this
technique can lead to automatic resolution without conflict, combining
everything from the 2 files. As with the other merges using this
technique, we assume the user will inspect the result before saving.
Signed-off-by: Kevin Bracey <kevin@bracey.fi>
Reviewed-by: David Aguilar <davvid@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-03-13 02:12:21 +01:00
|
|
|
orig=$(git-unpack-file $1)
|
2005-11-08 07:03:46 +01:00
|
|
|
;;
|
|
|
|
esac
|
2005-06-09 01:38:20 +02:00
|
|
|
|
2007-07-03 07:52:14 +02:00
|
|
|
git merge-file "$src1" "$orig" "$src2"
|
2005-04-24 05:50:10 +02:00
|
|
|
ret=$?
|
2009-04-29 23:40:50 +02:00
|
|
|
msg=
|
merge-one-file: force content conflict for "both sides added" case
Historically, we tried to be lenient to "both sides added, slightly
differently" case and as long as the files can be merged using a
made-up common ancestor cleanly, since f7d24bbefb06 (merge with
/dev/null as base, instead of punting O==empty case, 2005-11-07).
This was later further refined to use a better made-up common file
with fd66dbf5297a (merge-one-file: use empty- or common-base
condintionally in two-stage merge., 2005-11-10), but the spirit has
been the same.
But the original fix in f7d24bbefb06 to avoid punting on "both sides
added" case had a code to unconditionally error out the merge. When
this triggers, even though the content-level merge can be done
cleanly, we end up not saying "content conflict" in the message, but
still issue the error message, showing "ERROR: in <pathname>".
Move that "always fail for add/add conflict" logic a bit higher to
fix this.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-03-25 18:05:13 +01:00
|
|
|
if test $ret != 0 || test -z "$1"
|
2013-03-24 13:26:23 +01:00
|
|
|
then
|
2009-04-29 23:40:50 +02:00
|
|
|
msg='content conflict'
|
merge-one-file: force content conflict for "both sides added" case
Historically, we tried to be lenient to "both sides added, slightly
differently" case and as long as the files can be merged using a
made-up common ancestor cleanly, since f7d24bbefb06 (merge with
/dev/null as base, instead of punting O==empty case, 2005-11-07).
This was later further refined to use a better made-up common file
with fd66dbf5297a (merge-one-file: use empty- or common-base
condintionally in two-stage merge., 2005-11-10), but the spirit has
been the same.
But the original fix in f7d24bbefb06 to avoid punting on "both sides
added" case had a code to unconditionally error out the merge. When
this triggers, even though the content-level merge can be done
cleanly, we end up not saying "content conflict" in the message, but
still issue the error message, showing "ERROR: in <pathname>".
Move that "always fail for add/add conflict" logic a bit higher to
fix this.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-03-25 18:05:13 +01:00
|
|
|
ret=1
|
2009-04-29 23:40:50 +02:00
|
|
|
fi
|
2005-12-07 09:50:33 +01:00
|
|
|
|
|
|
|
# Create the working tree file, using "our tree" version from the
|
|
|
|
# index, and then store the result of the merge.
|
2011-04-30 00:24:32 +02:00
|
|
|
git checkout-index -f --stage=2 -- "$4" && cat "$src1" >"$4" || exit 1
|
2005-12-07 09:50:33 +01:00
|
|
|
rm -f -- "$orig" "$src1" "$src2"
|
2005-06-08 23:26:55 +02:00
|
|
|
|
2013-03-24 13:26:23 +01:00
|
|
|
if test "$6" != "$7"
|
|
|
|
then
|
|
|
|
if test -n "$msg"
|
|
|
|
then
|
2009-04-29 23:40:50 +02:00
|
|
|
msg="$msg, "
|
|
|
|
fi
|
|
|
|
msg="${msg}permissions conflict: $5->$6,$7"
|
2005-06-08 20:40:59 +02:00
|
|
|
ret=1
|
2005-04-24 05:50:10 +02:00
|
|
|
fi
|
2005-06-08 23:26:55 +02:00
|
|
|
|
2013-03-24 13:26:23 +01:00
|
|
|
if test $ret != 0
|
|
|
|
then
|
2013-03-24 13:26:24 +01:00
|
|
|
echo "ERROR: $msg in $4" >&2
|
2005-04-19 04:55:19 +02:00
|
|
|
exit 1
|
|
|
|
fi
|
2007-07-03 07:52:14 +02:00
|
|
|
exec git update-index -- "$4"
|
2005-06-09 01:38:20 +02:00
|
|
|
;;
|
|
|
|
|
2005-04-18 23:17:58 +02:00
|
|
|
*)
|
2013-03-24 13:26:24 +01:00
|
|
|
echo "ERROR: $4: Not handling case $1 -> $2 -> $3" >&2
|
2005-06-09 01:38:20 +02:00
|
|
|
;;
|
2005-04-18 23:17:58 +02:00
|
|
|
esac
|
|
|
|
exit 1
|