merge-one-file: use common as base, instead of emptiness.

Subsystems: the rest

2 messages, 2 authors, 2016-06-15 · open the first message on its own page

merge-one-file: use common as base, instead of emptiness.

From: Junio C Hamano <hidden>
Date: 2016-06-15 22:42:11

Petr Baudis [off-list ref] writes:
I think having

	<<<<<
	file1
	=====
	file2
	>>>>>

is an awful PITA to resolve, especially when the files actually are
similar. Running some vimdiff (or just diff and possibly applying either
way) on two separate files is much more convenient.
You are right.

How about something like this?  This adds a specialized hackery
flag, --no-add, to git-apply, and uses it to compute common base
to be used for 2-file merge, instead of using /dev/null.

On top of the previous round.

 -- >8 -- cut here -- >8 --
Unlike the previous round that merged the path added differently
in each branches using emptiness as the base, compute a common
version and use it as input to 'merge' program.

This would show the resulting (still conflicting) file left in
the working tree as:

	common file contents...
	<<<<<< FILENAME
	version from our branch...
	======
	version from their branch...
	>>>>>> .merge_file_XXXXXX
	more common file contents...

when both sides added similar contents.

Signed-off-by: Junio C Hamano <redacted>

---

 apply.c               |   11 +++++++++--
 git-merge-one-file.sh |    6 ++++--
 2 files changed, 13 insertions(+), 4 deletions(-)

applies-to: 75c7cdf0addfcb4df5ed093f9b57bb98432489e1
f158ab58fd3846a784805849bd9228bf060e4b2d
diff --git a/apply.c b/apply.c
index 3e53b34..7584888 100644
--- a/apply.c
+++ b/apply.c
@@ -23,6 +23,7 @@ static int numstat = 0;
 static int summary = 0;
 static int check = 0;
 static int apply = 1;
+static int no_add = 0;
 static int show_index_info = 0;
 static int line_termination = '\n';
 static const char apply_usage[] =
@@ -1099,8 +1100,10 @@ static int apply_one_fragment(struct buf
 				break;
 		/* Fall-through for ' ' */
 		case '+':
-			memcpy(new + newsize, patch + 1, plen);
-			newsize += plen;
+			if (*patch != '+' || !no_add) {
+				memcpy(new + newsize, patch + 1, plen);
+				newsize += plen;
+			}
 			break;
 		case '@': case '\\':
 			/* Ignore it, we already handled it */
@@ -1697,6 +1700,10 @@ int main(int argc, char **argv)
 			excludes = x;
 			continue;
 		}
+		if (!strcmp(arg, "--no-add")) {
+			no_add = 1;
+			continue;
+		}
 		if (!strcmp(arg, "--stat")) {
 			apply = 0;
 			diffstat = 1;
diff --git a/git-merge-one-file.sh b/git-merge-one-file.sh
index 32e17cb..d9ee458 100755
--- a/git-merge-one-file.sh
+++ b/git-merge-one-file.sh
@@ -57,18 +57,20 @@ case "${1:-.}${2:-.}${3:-.}" in
 # Modified in both, but differently.
 #
 "$1$2$3" | ".$2$3")
+	src2=`git-unpack-file $3`
 	case "$1" in
 	'')
 		echo "Added $4 in both, but differently."
+		# This extracts OUR file in $orig, and uses git-apply to
+		# remove lines that are unique to ours.
 		orig=`git-unpack-file $2`
-		: >$orig
+		diff -u -La/$orig -Lb/$orig $orig $src2 | git-apply --no-add 
 		;;
 	*)
 		echo "Auto-merging $4."
 		orig=`git-unpack-file $1`
 		;;
 	esac
-	src2=`git-unpack-file $3`
 
 	# We reset the index to the first branch, making
 	# git-diff-file useful
---
0.99.9.GIT

Re: merge-one-file: use common as base, instead of emptiness.

From: Petr Baudis <hidden>
Date: 2016-06-15 22:42:11

Dear diary, on Thu, Nov 10, 2005 at 05:41:10AM CET, I got a letter
where Junio C Hamano [off-list ref] said that...
Petr Baudis [off-list ref] writes:
quoted
I think having

	<<<<<
	file1
	=====
	file2
	>>>>>

is an awful PITA to resolve, especially when the files actually are
similar. Running some vimdiff (or just diff and possibly applying either
way) on two separate files is much more convenient.
You are right.

How about something like this?  This adds a specialized hackery
flag, --no-add, to git-apply, and uses it to compute common base
to be used for 2-file merge, instead of using /dev/null.
Wow, astonishingly simple.
 -- >8 -- cut here -- >8 --
Unlike the previous round that merged the path added differently
in each branches using emptiness as the base, compute a common
version and use it as input to 'merge' program.

This would show the resulting (still conflicting) file left in
the working tree as:

	common file contents...
	<<<<<< FILENAME
	version from our branch...
	======
	version from their branch...
	>>>>>> .merge_file_XXXXXX
	more common file contents...

when both sides added similar contents.
But obviously now the trouble is opposite, when the files are completely
unrelated, since now you likely get large conflicting areas interleaved
with some scarce common lines... And this might get to be a big PITA to
resolve as well.

That said, I still really like --no-add and it would be heart-wrenching
to just coldly dismiss it. It is a great tool, but I would let the user
to use it manually. Possibly something like

	git-twofile-merge foo~1 foo~2

(the name is stupid, obviously) or a button in some GUI tool.

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
VI has two modes: the one in which it beeps and the one in which
it doesn't.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help