git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] fix recursive-merge of empty files with different permissions
@ 2008-03-08 17:17 Clemens Buchacher
  2008-03-08 17:51 ` Johannes Schindelin
  0 siblings, 1 reply; 23+ messages in thread
From: Clemens Buchacher @ 2008-03-08 17:17 UTC (permalink / raw)
  To: git; +Cc: Johannes.Schindelin

If git-merge-recursive attempts to merge two empty new files with
different executable flags, eventually xdl_merge() is called and produces
empty diffs for both files and therefore does not choose either file as
successor. Make xdl_merge() choose one of the files instead.

Signed-off-by: Clemens Buchacher <drizzd@aon.at>
---

Hi,

The change in indentation makes this patch look larger than it is. All I
actually did was remove the "if (xscr1 || xscr2)" condition.

Previously to this patch the included test showed the following output:

	Merging a with b
	Merging:
	82712b3 branch a
	7eacd6f branch b
	found 1 common ancestor(s):
	33b7ba5 initial commit
	Auto-merged a
	fatal: Failed to execute internal merge

I do not understand why, but this does not happen if the file permissions are
the same.

Thanks,
Clemens

 t/t6031-merge-recursive.sh |   23 +++++++++++++++++++++++
 xdiff/xmerge.c             |   30 ++++++++++++++----------------
 2 files changed, 37 insertions(+), 16 deletions(-)
 create mode 100755 t/t6031-merge-recursive.sh

diff --git a/t/t6031-merge-recursive.sh b/t/t6031-merge-recursive.sh
new file mode 100755
index 0000000..4e3456b
--- /dev/null
+++ b/t/t6031-merge-recursive.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+test_description='merge-recursive corner cases'
+. ./test-lib.sh
+
+test_expect_success 'merge empty files with different permission flags' '
+	: >dummy &&
+	git add dummy &&
+	git commit -m "initial commit" &&
+	git checkout -b a master &&
+	: >a &&
+	git add a &&
+	git commit -m "branch a" &&
+	git checkout -b b master &&
+	: >a &&
+	chmod +x a &&
+	git add a &&
+	git commit -m "branch b" &&
+	git checkout master &&
+	git merge-recursive master -- a b
+'
+
+test_done
diff --git a/xdiff/xmerge.c b/xdiff/xmerge.c
index 82b3573..92127e1 100644
--- a/xdiff/xmerge.c
+++ b/xdiff/xmerge.c
@@ -470,23 +470,21 @@ int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,
 		return -1;
 	}
 	status = 0;
-	if (xscr1 || xscr2) {
-		if (!xscr1) {
-			result->ptr = xdl_malloc(mf2->size);
-			memcpy(result->ptr, mf2->ptr, mf2->size);
-			result->size = mf2->size;
-		} else if (!xscr2) {
-			result->ptr = xdl_malloc(mf1->size);
-			memcpy(result->ptr, mf1->ptr, mf1->size);
-			result->size = mf1->size;
-		} else {
-			status = xdl_do_merge(&xe1, xscr1, name1,
-					      &xe2, xscr2, name2,
-					      level, xpp, result);
-		}
-		xdl_free_script(xscr1);
-		xdl_free_script(xscr2);
+	if (!xscr1) {
+		result->ptr = xdl_malloc(mf2->size);
+		memcpy(result->ptr, mf2->ptr, mf2->size);
+		result->size = mf2->size;
+	} else if (!xscr2) {
+		result->ptr = xdl_malloc(mf1->size);
+		memcpy(result->ptr, mf1->ptr, mf1->size);
+		result->size = mf1->size;
+	} else {
+		status = xdl_do_merge(&xe1, xscr1, name1,
+				      &xe2, xscr2, name2,
+				      level, xpp, result);
 	}
+	xdl_free_script(xscr1);
+	xdl_free_script(xscr2);
 	xdl_free_env(&xe1);
 	xdl_free_env(&xe2);
 
-- 
1.5.4.3.468.g36990.dirty


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH] fix recursive-merge of empty files with different permissions
  2008-03-08 17:17 [PATCH] fix recursive-merge of empty files with different permissions Clemens Buchacher
@ 2008-03-08 17:51 ` Johannes Schindelin
  2008-03-13 12:52   ` Clemens Buchacher
  0 siblings, 1 reply; 23+ messages in thread
From: Johannes Schindelin @ 2008-03-08 17:51 UTC (permalink / raw)
  To: Clemens Buchacher; +Cc: git

Hi,

On Sat, 8 Mar 2008, Clemens Buchacher wrote:

> I do not understand why, but this does not happen if the file 
> permissions are the same.

I think this is the biggest problem.

>  t/t6031-merge-recursive.sh |   23 +++++++++++++++++++++++
>  xdiff/xmerge.c             |   30 ++++++++++++++----------------

... because xdiff/xmerge.c is definitely the wrong place to "fix" this 
issue.  xdl_merge() does not even _know_ about permissions.

Ciao,
Dscho

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH] fix recursive-merge of empty files with different permissions
  2008-03-08 17:51 ` Johannes Schindelin
@ 2008-03-13 12:52   ` Clemens Buchacher
  2008-03-13 15:19     ` Johannes Schindelin
  0 siblings, 1 reply; 23+ messages in thread
From: Clemens Buchacher @ 2008-03-13 12:52 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git

Hi,

On Sat, Mar 08, 2008 at 06:17:26PM +0100, Clemens Buchacher wrote:
> If git-merge-recursive attempts to merge two empty new files with
> different executable flags, eventually xdl_merge() is called and produces
> empty diffs for both files and therefore does not choose either file as
> successor. Make xdl_merge() choose one of the files instead.

On Sat, Mar 08, 2008 at 06:51:48PM +0100, Johannes Schindelin wrote:
> On Sat, 8 Mar 2008, Clemens Buchacher wrote:
> > I do not understand why, but this does not happen if the file 
> > permissions are the same.
> 
> I think this is the biggest problem.
> 
> >  t/t6031-merge-recursive.sh |   23 +++++++++++++++++++++++
> >  xdiff/xmerge.c             |   30 ++++++++++++++----------------
> 
> ... because xdiff/xmerge.c is definitely the wrong place to "fix" this 
> issue.  xdl_merge() does not even _know_ about permissions.

After analyzing the problem in greater detail, I have to disagree. It is true,
of course, that xdl_merge() does not and should not know about permissions at
all. However, the bug is still in xdl_merge(). Different permissions are only
the trigger of the problem, because only then will xdl_merge() be called at
all.

What happens is this. Before looking at the file contents directly
merge_trees() attempts to resolve the merge trivially. If both sha1 and mode of
the head and remote entries match, the merge will be resolved as per case #5ALT
(see Documentation/trivial-merge.txt), i.e. head is chosen as the merge result.

If either sha1 _or_ mode differ between the head and remote entries, however,
merge_trees() will use xdl_merge() to merge the file content and the remote
entry's mode will be chosen as result mode.

One could argue that it would be better to mark the mismatching permissions as
a conflict. However, this is how the merge currently silently succeeds _unless_
both files are empty. If they are, xdl_merge() will effectively exit with an
error status and git-merge-recursive will fail with an internal error (as shown
in the testcase).

In any case, I think it is reasonable to expect xdl_merge() to work with empty
files. Whether or not the current "mode merging" behavior is desired is a
different matter.

Regards,
Clemens

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH] fix recursive-merge of empty files with different permissions
  2008-03-13 12:52   ` Clemens Buchacher
@ 2008-03-13 15:19     ` Johannes Schindelin
  2008-03-13 18:50       ` Junio C Hamano
  2008-03-13 19:22       ` [PATCH] merge-recursive: cause a conflict if file mode does not match Clemens Buchacher
  0 siblings, 2 replies; 23+ messages in thread
From: Johannes Schindelin @ 2008-03-13 15:19 UTC (permalink / raw)
  To: Clemens Buchacher; +Cc: git, gitster

Hi,

[Junio, there is a bugfix at the end of this mail.]

On Thu, 13 Mar 2008, Clemens Buchacher wrote:

> Hi,
> 
> On Sat, Mar 08, 2008 at 06:17:26PM +0100, Clemens Buchacher wrote:
> > If git-merge-recursive attempts to merge two empty new files with 
> > different executable flags, eventually xdl_merge() is called and 
> > produces empty diffs for both files and therefore does not choose 
> > either file as successor. Make xdl_merge() choose one of the files 
> > instead.
> 
> On Sat, Mar 08, 2008 at 06:51:48PM +0100, Johannes Schindelin wrote:
> > On Sat, 8 Mar 2008, Clemens Buchacher wrote:
> > > I do not understand why, but this does not happen if the file 
> > > permissions are the same.
> > 
> > I think this is the biggest problem.
> > 
> > >  t/t6031-merge-recursive.sh |   23 +++++++++++++++++++++++
> > >  xdiff/xmerge.c             |   30 ++++++++++++++----------------
> > 
> > ... because xdiff/xmerge.c is definitely the wrong place to "fix" this 
> > issue.  xdl_merge() does not even _know_ about permissions.
> 
> After analyzing the problem in greater detail, I have to disagree. It is 
> true, of course, that xdl_merge() does not and should not know about 
> permissions at all. However, the bug is still in xdl_merge(). Different 
> permissions are only the trigger of the problem, because only then will 
> xdl_merge() be called at all.
> 
> What happens is this. Before looking at the file contents directly 
> merge_trees() attempts to resolve the merge trivially. If both sha1 and 
> mode of the head and remote entries match, the merge will be resolved as 
> per case #5ALT (see Documentation/trivial-merge.txt), i.e. head is 
> chosen as the merge result.
> 
> If either sha1 _or_ mode differ between the head and remote entries, 
> however, merge_trees() will use xdl_merge() to merge the file content 
> and the remote entry's mode will be chosen as result mode.
> 
> One could argue that it would be better to mark the mismatching 
> permissions as a conflict.

Right you are.  Your whole "it still is xdl_merge()s fault" point was just 
contradicted by your own analysis.  Calling xdl_merge() when the sha1 does 
_not_ differ is _a mistake_.  _That_ is the bug.  Not xdl_merge() 
returning 0 (because there were 0 conflicts).

> However, this is how the merge currently silently succeeds _unless_ both 
> files are empty. If they are, xdl_merge() will effectively exit with an 
> error status and git-merge-recursive will fail with an internal error 
> (as shown in the testcase).
> 
> In any case, I think it is reasonable to expect xdl_merge() to work with 
> empty files. Whether or not the current "mode merging" behavior is 
> desired is a different matter.

I just tested.  xdl_merge() is _just fine_ with empty files.  However, 
git-merge-file was not.  Fixed by this:

-- snipsnap --
[PATCH] merge-file: handle empty files gracefully

Earlier, it would error out while trying to read and/or writing them.
Now, calling merge-file with empty files is neither interesting nor
useful, but it is a bug that needed fixing.

Noticed by Clemens Buchacher.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin-merge-file.c |    3 ++-
 xdiff-interface.c    |    4 ++--
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/builtin-merge-file.c b/builtin-merge-file.c
index adce6d4..cde4b2c 100644
--- a/builtin-merge-file.c
+++ b/builtin-merge-file.c
@@ -57,7 +57,8 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
 
 		if (!f)
 			ret = error("Could not open %s for writing", filename);
-		else if (fwrite(result.ptr, result.size, 1, f) != 1)
+		else if (result.size &&
+				fwrite(result.ptr, result.size, 1, f) != 1)
 			ret = error("Could not write to %s", filename);
 		else if (fclose(f))
 			ret = error("Could not close %s", filename);
diff --git a/xdiff-interface.c b/xdiff-interface.c
index bba2364..61dc5c5 100644
--- a/xdiff-interface.c
+++ b/xdiff-interface.c
@@ -152,8 +152,8 @@ int read_mmfile(mmfile_t *ptr, const char *filename)
 	if ((f = fopen(filename, "rb")) == NULL)
 		return error("Could not open %s", filename);
 	sz = xsize_t(st.st_size);
-	ptr->ptr = xmalloc(sz);
-	if (fread(ptr->ptr, sz, 1, f) != 1)
+	ptr->ptr = xmalloc(sz ? sz : 1);
+	if (sz && fread(ptr->ptr, sz, 1, f) != 1)
 		return error("Could not read %s", filename);
 	fclose(f);
 	ptr->size = sz;
-- 
1.5.4.4.706.ga822

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH] fix recursive-merge of empty files with different permissions
  2008-03-13 15:19     ` Johannes Schindelin
@ 2008-03-13 18:50       ` Junio C Hamano
  2008-03-13 21:28         ` Johannes Schindelin
  2008-03-13 19:22       ` [PATCH] merge-recursive: cause a conflict if file mode does not match Clemens Buchacher
  1 sibling, 1 reply; 23+ messages in thread
From: Junio C Hamano @ 2008-03-13 18:50 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Clemens Buchacher, git

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:

> diff --git a/builtin-merge-file.c b/builtin-merge-file.c
> index adce6d4..cde4b2c 100644
> --- a/builtin-merge-file.c
> +++ b/builtin-merge-file.c
> @@ -57,7 +57,8 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
>  
>  		if (!f)
>  			ret = error("Could not open %s for writing", filename);
> -		else if (fwrite(result.ptr, result.size, 1, f) != 1)
> +		else if (result.size &&
> +				fwrite(result.ptr, result.size, 1, f) != 1)
>  			ret = error("Could not write to %s", filename);
>  		else if (fclose(f))
>  			ret = error("Could not close %s", filename);

Lol.  We are dealing with N-byte quantity so we send one record of length
N and make sure we processed one record, and it does not work when N is
zero.

We could instead send N records of size 1 and make sure we processed N
records to lose the conditional instead, but the patch avoids unnecessary
call to fread/fwrite so that is good.  Thanks.

It felt funny because my current bedtime reading happens to be "Zero: The
Biography of a Dangerous Idea (ISBN 0140296476)".

> diff --git a/xdiff-interface.c b/xdiff-interface.c
> index bba2364..61dc5c5 100644
> --- a/xdiff-interface.c
> +++ b/xdiff-interface.c
> @@ -152,8 +152,8 @@ int read_mmfile(mmfile_t *ptr, const char *filename)
>  	if ((f = fopen(filename, "rb")) == NULL)
>  		return error("Could not open %s", filename);
>  	sz = xsize_t(st.st_size);
> -	ptr->ptr = xmalloc(sz);
> -	if (fread(ptr->ptr, sz, 1, f) != 1)
> +	ptr->ptr = xmalloc(sz ? sz : 1);
> +	if (sz && fread(ptr->ptr, sz, 1, f) != 1)
>  		return error("Could not read %s", filename);
>  	fclose(f);
>  	ptr->size = sz;

Do you need to actually allocate ptr->ptr when sz is zero, instead of
setting it to NULL, like:

	sz = xsize_t(st.st_size);
	ptr->size = sz;
        if (!sz)
        	ptr->ptr = NULL;
	else {
        	ptr->ptr = xmalloc(sz);
		if (fread(ptr->ptr, 1, sz, f) != sz)
			return error("Could not read %s", filename);
	}
	fclose(f);

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH] merge-recursive: cause a conflict if file mode does not match
  2008-03-13 15:19     ` Johannes Schindelin
  2008-03-13 18:50       ` Junio C Hamano
@ 2008-03-13 19:22       ` Clemens Buchacher
  2008-03-13 21:17         ` Johannes Schindelin
  1 sibling, 1 reply; 23+ messages in thread
From: Clemens Buchacher @ 2008-03-13 19:22 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git, gitster

Previously, mismatching file modes would be auto-merged by picking the
mode in the remote tree.

This also fixes a bug which caused merge-recursive to fail if the merged
files were empty.

Signed-off-by: Clemens Buchacher <drizzd@aon.at>
---

Hi Dscho,

Your patch certainly fixes a bug in git-merge-file. It does not fix the bug in
git-merge-recursive, however. The test script also fails with your patch.

On Thu, Mar 13, 2008 at 04:19:35PM +0100, Johannes Schindelin wrote:
> On Sat, Mar 08, 2008 at 06:17:26PM +0100, Clemens Buchacher wrote:
> > One could argue that it would be better to mark the mismatching 
> > permissions as a conflict.
> 
> Right you are.  Your whole "it still is xdl_merge()s fault" point was just 
> contradicted by your own analysis.  Calling xdl_merge() when the sha1 does 
> _not_ differ is _a mistake_.  _That_ is the bug.

Alright, fixed in the appended patch.

Regards,
Clemens

 merge-recursive.c          |    9 +++++++--
 t/t6031-merge-recursive.sh |   23 +++++++++++++++++++++++
 2 files changed, 30 insertions(+), 2 deletions(-)
 create mode 100755 t/t6031-merge-recursive.sh

diff --git a/merge-recursive.c b/merge-recursive.c
index 34e3167..01918a7 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -1028,9 +1028,14 @@ static struct merge_file_info merge_file(struct diff_filespec *o,
 		if (!sha_eq(a->sha1, o->sha1) && !sha_eq(b->sha1, o->sha1))
 			result.merge = 1;
 
-		result.mode = a->mode == o->mode ? b->mode: a->mode;
+		if (!o->mode) {
+			if (a->mode != b->mode)
+				result.clean = 0;
+			result.mode = b->mode;
+		} else
+			result.mode = a->mode == o->mode ? b->mode: a->mode;
 
-		if (sha_eq(a->sha1, o->sha1))
+		if (sha_eq(a->sha1, b->sha1) || sha_eq(a->sha1, o->sha1))
 			hashcpy(result.sha, b->sha1);
 		else if (sha_eq(b->sha1, o->sha1))
 			hashcpy(result.sha, a->sha1);
diff --git a/t/t6031-merge-recursive.sh b/t/t6031-merge-recursive.sh
new file mode 100755
index 0000000..7ea371e
--- /dev/null
+++ b/t/t6031-merge-recursive.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+test_description='merge-recursive corner cases'
+. ./test-lib.sh
+
+test_expect_success 'merge empty files with different permission flags' '
+	: >dummy &&
+	git add dummy &&
+	git commit -m "initial commit" &&
+	git checkout -b a master &&
+	: >a &&
+	git add a &&
+	git commit -m "branch a" &&
+	git checkout -b b master &&
+	: >a &&
+	chmod +x a &&
+	git add a &&
+	git commit -m "branch b" &&
+	git checkout master &&
+	! (git merge-recursive master -- a b || test $? -ne 1)
+'
+
+test_done
-- 
1.5.4.4.2.gd2fe

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH] merge-recursive: cause a conflict if file mode does not match
  2008-03-13 19:22       ` [PATCH] merge-recursive: cause a conflict if file mode does not match Clemens Buchacher
@ 2008-03-13 21:17         ` Johannes Schindelin
  2008-03-13 22:47           ` [PATCH] merge-recursive: handle file mode changes Clemens Buchacher
  2008-03-14 10:07           ` [PATCH] merge-recursive: cause a conflict if file mode does not match Clemens Buchacher
  0 siblings, 2 replies; 23+ messages in thread
From: Johannes Schindelin @ 2008-03-13 21:17 UTC (permalink / raw)
  To: Clemens Buchacher; +Cc: git, gitster

Hi,

On Thu, 13 Mar 2008, Clemens Buchacher wrote:

> Previously, mismatching file modes would be auto-merged by picking the 
> mode in the remote tree.
> 
> This also fixes a bug which caused merge-recursive to fail if the merged 
> files were empty.
> 
> Signed-off-by: Clemens Buchacher <drizzd@aon.at>
> ---
> 
> Hi Dscho,
> 
> Your patch certainly fixes a bug in git-merge-file. It does not fix the 
> bug in git-merge-recursive, however. The test script also fails with 
> your patch.

Now, _that_ is funny.  I tested before sending, and my test suit runs just 
fine.

> On Thu, Mar 13, 2008 at 04:19:35PM +0100, Johannes Schindelin wrote:
> > On Sat, Mar 08, 2008 at 06:17:26PM +0100, Clemens Buchacher wrote:
> > > One could argue that it would be better to mark the mismatching 
> > > permissions as a conflict.
> > 
> > Right you are.  Your whole "it still is xdl_merge()s fault" point was 
> > just contradicted by your own analysis.  Calling xdl_merge() when the 
> > sha1 does _not_ differ is _a mistake_.  _That_ is the bug.
> 
> Alright, fixed in the appended patch.

I have to admit that I wanted you to fix that patch, instead of me, 
because you were already researching the issue.

>  merge-recursive.c          |    9 +++++++--
>  t/t6031-merge-recursive.sh |   23 +++++++++++++++++++++++
>  2 files changed, 30 insertions(+), 2 deletions(-)
>  create mode 100755 t/t6031-merge-recursive.sh

Looks much better.

> diff --git a/merge-recursive.c b/merge-recursive.c
> index 34e3167..01918a7 100644
> --- a/merge-recursive.c
> +++ b/merge-recursive.c
> @@ -1028,9 +1028,14 @@ static struct merge_file_info merge_file(struct diff_filespec *o,
>  		if (!sha_eq(a->sha1, o->sha1) && !sha_eq(b->sha1, o->sha1))
>  			result.merge = 1;
>  
> -		result.mode = a->mode == o->mode ? b->mode: a->mode;
> +		if (!o->mode) {
> +			if (a->mode != b->mode)
> +				result.clean = 0;
> +			result.mode = b->mode;
> +		} else
> +			result.mode = a->mode == o->mode ? b->mode: a->mode;

So you only set clean = 0 if o->mode == 0, i.e. the file did not exist?  
That was not what I had in mind.  I would have expected that "if (a->mode 
!= b->mode)" to come _before_ the assignment to result.mode, which should 
have been left alone.

The rationale would have been this:

If the modes are different, the merge is not clean.

If the SHA-1s differ, the merge is not clean, and xld_merge() should be 
called.

> -		if (sha_eq(a->sha1, o->sha1))
> +		if (sha_eq(a->sha1, b->sha1) || sha_eq(a->sha1, o->sha1))

Why do you still compare to o->sha1?

/me goes looking in the original source, since the issue and the fix does 
not become apparent from your patch, including the commit message.

Oh, okay.

You are reusing a _different_ case, which just happens to have the same 
outcome.

In a perfect world, this would have a one-line comment above to explain 
issues.

> diff --git a/t/t6031-merge-recursive.sh b/t/t6031-merge-recursive.sh
> new file mode 100755
> index 0000000..7ea371e
> --- /dev/null
> +++ b/t/t6031-merge-recursive.sh
> @@ -0,0 +1,23 @@
> +#!/bin/sh
> +
> +test_description='merge-recursive corner cases'
> +. ./test-lib.sh
> +
> +test_expect_success 'merge empty files with different permission flags' '

The point is not that they are empty.  Maybe you want to fix that message.

> +	: >dummy &&
> +	git add dummy &&
> +	git commit -m "initial commit" &&
> +	git checkout -b a master &&
> +	: >a &&
> +	git add a &&
> +	git commit -m "branch a" &&
> +	git checkout -b b master &&
> +	: >a &&
> +	chmod +x a &&
> +	git add a &&
> +	git commit -m "branch b" &&
> +	git checkout master &&
> +	! (git merge-recursive master -- a b || test $? -ne 1)
> +'
> +
> +test_done
> -- 
> 1.5.4.4.2.gd2fe
> 

Thanks,
Dscho

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH] fix recursive-merge of empty files with different permissions
  2008-03-13 18:50       ` Junio C Hamano
@ 2008-03-13 21:28         ` Johannes Schindelin
  0 siblings, 0 replies; 23+ messages in thread
From: Johannes Schindelin @ 2008-03-13 21:28 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Clemens Buchacher, git

Hi,

On Thu, 13 Mar 2008, Junio C Hamano wrote:

> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> 
> > diff --git a/builtin-merge-file.c b/builtin-merge-file.c
> > index adce6d4..cde4b2c 100644
> > --- a/builtin-merge-file.c
> > +++ b/builtin-merge-file.c
> > @@ -57,7 +57,8 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
> >  
> >  		if (!f)
> >  			ret = error("Could not open %s for writing", filename);
> > -		else if (fwrite(result.ptr, result.size, 1, f) != 1)
> > +		else if (result.size &&
> > +				fwrite(result.ptr, result.size, 1, f) != 1)
> >  			ret = error("Could not write to %s", filename);
> >  		else if (fclose(f))
> >  			ret = error("Could not close %s", filename);
> 
> Lol.  We are dealing with N-byte quantity so we send one record of length
> N and make sure we processed one record, and it does not work when N is
> zero.
> 
> We could instead send N records of size 1 and make sure we processed N
> records to lose the conditional instead, but the patch avoids unnecessary
> call to fread/fwrite so that is good.  Thanks.
> 
> It felt funny because my current bedtime reading happens to be "Zero: The
> Biography of a Dangerous Idea (ISBN 0140296476)".

Heh.

> > diff --git a/xdiff-interface.c b/xdiff-interface.c
> > index bba2364..61dc5c5 100644
> > --- a/xdiff-interface.c
> > +++ b/xdiff-interface.c
> > @@ -152,8 +152,8 @@ int read_mmfile(mmfile_t *ptr, const char *filename)
> >  	if ((f = fopen(filename, "rb")) == NULL)
> >  		return error("Could not open %s", filename);
> >  	sz = xsize_t(st.st_size);
> > -	ptr->ptr = xmalloc(sz);
> > -	if (fread(ptr->ptr, sz, 1, f) != 1)
> > +	ptr->ptr = xmalloc(sz ? sz : 1);
> > +	if (sz && fread(ptr->ptr, sz, 1, f) != 1)
> >  		return error("Could not read %s", filename);
> >  	fclose(f);
> >  	ptr->size = sz;
> 
> Do you need to actually allocate ptr->ptr when sz is zero, instead of
> setting it to NULL, like:
> 
> 	sz = xsize_t(st.st_size);
> 	ptr->size = sz;
>         if (!sz)
>         	ptr->ptr = NULL;
> 	else {
>         	ptr->ptr = xmalloc(sz);
> 		if (fread(ptr->ptr, 1, sz, f) != sz)
> 			return error("Could not read %s", filename);
> 	}
> 	fclose(f);

I was going for the safe option.  In theory, you are right, but I cannot 
really be sure that e.g. a memcpy() with size 0 will not access the source 
pointer at all.

Ciao,
Dscho

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH] merge-recursive: handle file mode changes
  2008-03-13 21:17         ` Johannes Schindelin
@ 2008-03-13 22:47           ` Clemens Buchacher
  2008-03-13 23:40             ` Johannes Schindelin
                               ` (4 more replies)
  2008-03-14 10:07           ` [PATCH] merge-recursive: cause a conflict if file mode does not match Clemens Buchacher
  1 sibling, 5 replies; 23+ messages in thread
From: Clemens Buchacher @ 2008-03-13 22:47 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git, gitster

Handle file mode changes similarly to changes of content. If the file mode
changed in only one branch, keep the changed version. If the file mode
changed in both branches, prompt the user to choose one by reporting a
conflict.

This also fixes a bug which caused the merge to fail if the merged files were
empty.

Signed-off-by: Clemens Buchacher <drizzd@aon.at>
---

Hi,

On Thu, Mar 13, 2008 at 10:17:07PM +0100, Johannes Schindelin wrote:
> If the modes are different, the merge is not clean.

If the mode has only changed in either the head or the remote tree, I believe
we should keep the changed version without conflict - just like we do for
non-overlapping changes of content.

If, however, both files changed in a different way, we report a conflict and
keep the remote version by default. I based this decision on the assumption
that the user is more likely to have acknowledged the head branch, while he may
want to think about whether or not the change in the remote version is ok.

I cleaned up the code a bit and added a comment, so I hope the behavior is
clearer now.

> The point is not that they are empty.  Maybe you want to fix that message.

Indeed.

I am not exactly sure how I should set the result.merge flag. In this context
it seems to have the exact opposite meaning of result.clean. Is that correct?

Regards,
Clemens

 merge-recursive.c          |   21 ++++++++++++++++-----
 t/t6031-merge-recursive.sh |   39 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 55 insertions(+), 5 deletions(-)
 create mode 100755 t/t6031-merge-recursive.sh

diff --git a/merge-recursive.c b/merge-recursive.c
index 34e3167..d8938cc 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -1025,12 +1025,21 @@ static struct merge_file_info merge_file(struct diff_filespec *o,
 			hashcpy(result.sha, b->sha1);
 		}
 	} else {
-		if (!sha_eq(a->sha1, o->sha1) && !sha_eq(b->sha1, o->sha1))
-			result.merge = 1;
-
-		result.mode = a->mode == o->mode ? b->mode: a->mode;
+		/*
+		 * If mode changed in only one branch, keep the changed
+		 * version. Otherwise, keep remote version and create a
+		 * conflict.
+		 */
+		if (a->mode != o->mode && b->mode != o->mode &&
+				a->mode != b->mode) {
+			result.clean = 0;
+			result.mode = b->mode;
+		} else
+			result.mode = o->mode == a->mode ? b->mode : a->mode;
 
-		if (sha_eq(a->sha1, o->sha1))
+		if (sha_eq(a->sha1, b->sha1))
+			hashcpy(result.sha, b->sha1);
+		else if (sha_eq(a->sha1, o->sha1))
 			hashcpy(result.sha, b->sha1);
 		else if (sha_eq(b->sha1, o->sha1))
 			hashcpy(result.sha, a->sha1);
@@ -1062,6 +1071,8 @@ static struct merge_file_info merge_file(struct diff_filespec *o,
 		} else {
 			die("unsupported object type in the tree");
 		}
+
+		result.merge = !result.clean;
 	}
 
 	return result;
diff --git a/t/t6031-merge-recursive.sh b/t/t6031-merge-recursive.sh
new file mode 100755
index 0000000..36cd664
--- /dev/null
+++ b/t/t6031-merge-recursive.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+test_description='merge-recursive: handle file mode'
+. ./test-lib.sh
+
+test_expect_success 'mode change in one branch: keep changed version' '
+	: >file1 &&
+	git add file1 &&
+	git commit -m initial &&
+	git checkout -b a1 master &&
+	: >dummy &&
+	git add dummy &&
+	git commit -m a &&
+	git checkout -b b1 master &&
+	chmod +x file1 &&
+	git add file1 &&
+	git commit -m b1 &&
+	git checkout a1 &&
+	git merge-recursive master -- a1 b1 &&
+	test -x file1
+'
+
+test_expect_success 'mode change in both branches: expect conflict' '
+	git reset --hard HEAD &&
+	git checkout -b a2 master &&
+	: >file2 &&
+	chmod +x file2 &&
+	git add file2 &&
+	git commit -m a2 &&
+	git checkout -b b2 master &&
+	: >file2 &&
+	git add file2 &&
+	git commit -m b2 &&
+	git checkout a2 &&
+	! (git merge-recursive master -- a2 b2 || test $? -ne 1) &&
+	! test -x file2
+'
+
+test_done
-- 
1.5.4.4

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH] merge-recursive: handle file mode changes
  2008-03-13 22:47           ` [PATCH] merge-recursive: handle file mode changes Clemens Buchacher
@ 2008-03-13 23:40             ` Johannes Schindelin
  2008-03-14  9:21               ` [PATCH] merge-recursive: handle file mode and links similarly to file content Clemens Buchacher
  2008-03-14  0:08             ` [PATCH] merge-recursive: handle file mode changes Junio C Hamano
                               ` (3 subsequent siblings)
  4 siblings, 1 reply; 23+ messages in thread
From: Johannes Schindelin @ 2008-03-13 23:40 UTC (permalink / raw)
  To: Clemens Buchacher; +Cc: git, gitster

Hi,

On Thu, 13 Mar 2008, Clemens Buchacher wrote:

> @@ -1062,6 +1071,8 @@ static struct merge_file_info merge_file(struct diff_filespec *o,
>  		} else {
>  			die("unsupported object type in the tree");
>  		}
> +
> +		result.merge = !result.clean;

That is new.  Doesn't this overwrite what has been set in

        } else {
                if (!sha_eq(a->sha1, o->sha1) && !sha_eq(b->sha1, o->sha1))
                        result.merge = 1;

?

Ciao,
Dscho

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH] merge-recursive: handle file mode changes
  2008-03-13 22:47           ` [PATCH] merge-recursive: handle file mode changes Clemens Buchacher
  2008-03-13 23:40             ` Johannes Schindelin
@ 2008-03-14  0:08             ` Junio C Hamano
  2008-03-14  0:12             ` Junio C Hamano
                               ` (2 subsequent siblings)
  4 siblings, 0 replies; 23+ messages in thread
From: Junio C Hamano @ 2008-03-14  0:08 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git

Clemens Buchacher <drizzd@aon.at> writes:

> I am not exactly sure how I should set the result.merge flag. In this context
> it seems to have the exact opposite meaning of result.clean. Is that correct?

My reading of the code is that result.merge is "if a content level merge
has happened", and result.clean is "given that a content level merge has
been attempted, was it done cleanly, or are there conflicts for the user
to fix in the result".  If result.clean is not true, we obviously cannot
store the result in stage #0.

The result.merge flag is used only for reporting purposes; I am not sure
why the non-rename codepath does not pay attention to the result.merge,
though.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH] merge-recursive: handle file mode changes
  2008-03-13 22:47           ` [PATCH] merge-recursive: handle file mode changes Clemens Buchacher
  2008-03-13 23:40             ` Johannes Schindelin
  2008-03-14  0:08             ` [PATCH] merge-recursive: handle file mode changes Junio C Hamano
@ 2008-03-14  0:12             ` Junio C Hamano
  2008-03-14 13:02               ` Clemens Buchacher
  2008-03-14  0:17             ` Jakub Narebski
  2008-03-14 10:15             ` Junio C Hamano
  4 siblings, 1 reply; 23+ messages in thread
From: Junio C Hamano @ 2008-03-14  0:12 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git, gitster

Clemens Buchacher <drizzd@aon.at> writes:

> I am not exactly sure how I should set the result.merge flag. In this context
> it seems to have the exact opposite meaning of result.clean. Is that correct?

This is from the e-mail header of your message:

  Mail-Followup-To: Johannes Schindelin <Johannes.Schindelin@gmx.de>,
   git@vger.kernel.org, gitster@pobox.com

If you are asking people question, do not do this.  You want answers
addressed to you.  Johannes and I may not be interested in learning what
may want to find out, and redirecting answers for you to us is simply
rude.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH] merge-recursive: handle file mode changes
  2008-03-13 22:47           ` [PATCH] merge-recursive: handle file mode changes Clemens Buchacher
                               ` (2 preceding siblings ...)
  2008-03-14  0:12             ` Junio C Hamano
@ 2008-03-14  0:17             ` Jakub Narebski
  2008-03-14 12:56               ` Clemens Buchacher
  2008-03-14 10:15             ` Junio C Hamano
  4 siblings, 1 reply; 23+ messages in thread
From: Jakub Narebski @ 2008-03-14  0:17 UTC (permalink / raw)
  To: git

Clemens Buchacher wrote:

> Handle file mode changes similarly to changes of content. If the file mode
> changed in only one branch, keep the changed version. If the file mode
> changed in both branches, prompt the user to choose one by reporting a
> conflict.

Shouldn't it print "CONFLICT(mode/mode)" then?

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH] merge-recursive: handle file mode and links similarly to file content
  2008-03-13 23:40             ` Johannes Schindelin
@ 2008-03-14  9:21               ` Clemens Buchacher
  2008-03-14 10:13                 ` Clemens Buchacher
  0 siblings, 1 reply; 23+ messages in thread
From: Clemens Buchacher @ 2008-03-14  9:21 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git, gitster

If the file mode or link changed in only one branch, keep the changed
version. If the file mode or link changed differently in both branches,
report a conflict. If this happens, the user is more likely to be aware of
the change in the head branch. Choose the remote version by default, in
order to make the user think about the change.

Signed-off-by: Clemens Buchacher <drizzd@aon.at>
---

On Fri, Mar 14, 2008 at 12:40:05AM +0100, Johannes Schindelin wrote:
> On Thu, 13 Mar 2008, Clemens Buchacher wrote:
> > +		result.merge = !result.clean;
> 
> That is new.  Doesn't this overwrite what has been set in
> 
>         } else {
>                 if (!sha_eq(a->sha1, o->sha1) && !sha_eq(b->sha1, o->sha1))
>                         result.merge = 1;

Yeah, that's no good. I think I understand the meaning of result.merge and
result.clean now.

result.merge indicates that there are changes in both branches, whereas
result.clean indicates that the merge was trivial.

I amended the patch to reflect this.

I also noticed that in case of LINKs or GITLINKs which changed in both
branches, the head version is kept by default. By the same rationale I gave for
the file modes, I think the remote version should be kept instead, in order to
make the user aware of this change.

Regards,
Clemens

 merge-recursive.c          |   34 +++++++++++++++++++++++-----------
 t/t6031-merge-recursive.sh |   39 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 62 insertions(+), 11 deletions(-)
 create mode 100755 t/t6031-merge-recursive.sh

diff --git a/merge-recursive.c b/merge-recursive.c
index 34e3167..36f78a2 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -1025,16 +1025,31 @@ static struct merge_file_info merge_file(struct diff_filespec *o,
 			hashcpy(result.sha, b->sha1);
 		}
 	} else {
-		if (!sha_eq(a->sha1, o->sha1) && !sha_eq(b->sha1, o->sha1))
-			result.merge = 1;
+		/*
+		 * If the file changed in only one branch, keep the changed
+		 * version. If the file changed in both, try to merge
+		 * automatically. If the merge is not trivial, report a
+		 * conflict. In case of conflicting file modes or links, choose
+		 * remote version by default. They can only be merged trivially
+		 * if they are equal.
+		 */
 
-		result.mode = a->mode == o->mode ? b->mode: a->mode;
+		if (a->mode != o->mode && b->mode != o->mode) {
+			result.mode = b->mode;
+			if (a->mode != b->mode)
+				result.clean = 0;
+			result.merge = 1;
+		} else
+			result.mode = o->mode == a->mode ? b->mode : a->mode;
 
 		if (sha_eq(a->sha1, o->sha1))
 			hashcpy(result.sha, b->sha1);
 		else if (sha_eq(b->sha1, o->sha1))
 			hashcpy(result.sha, a->sha1);
-		else if (S_ISREG(a->mode)) {
+		else if (sha_eq(a->sha1, b->sha1)) {
+			hashcpy(result.sha, a->sha1);
+			result.merge = 1;
+		} else if (S_ISREG(a->mode)) {
 			mmbuffer_t result_buf;
 			int merge_status;
 
@@ -1051,14 +1066,11 @@ static struct merge_file_info merge_file(struct diff_filespec *o,
 
 			free(result_buf.ptr);
 			result.clean = (merge_status == 0);
-		} else if (S_ISGITLINK(a->mode)) {
+			result.merge = 1;
+		} else if (S_ISGITLINK(a->mode) || S_ISLNK(a->mode)) {
+			hashcpy(result.sha, b->sha1);
 			result.clean = 0;
-			hashcpy(result.sha, a->sha1);
-		} else if (S_ISLNK(a->mode)) {
-			hashcpy(result.sha, a->sha1);
-
-			if (!sha_eq(a->sha1, b->sha1))
-				result.clean = 0;
+			result.merge = 1;
 		} else {
 			die("unsupported object type in the tree");
 		}
diff --git a/t/t6031-merge-recursive.sh b/t/t6031-merge-recursive.sh
new file mode 100755
index 0000000..36cd664
--- /dev/null
+++ b/t/t6031-merge-recursive.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+test_description='merge-recursive: handle file mode'
+. ./test-lib.sh
+
+test_expect_success 'mode change in one branch: keep changed version' '
+	: >file1 &&
+	git add file1 &&
+	git commit -m initial &&
+	git checkout -b a1 master &&
+	: >dummy &&
+	git add dummy &&
+	git commit -m a &&
+	git checkout -b b1 master &&
+	chmod +x file1 &&
+	git add file1 &&
+	git commit -m b1 &&
+	git checkout a1 &&
+	git merge-recursive master -- a1 b1 &&
+	test -x file1
+'
+
+test_expect_success 'mode change in both branches: expect conflict' '
+	git reset --hard HEAD &&
+	git checkout -b a2 master &&
+	: >file2 &&
+	chmod +x file2 &&
+	git add file2 &&
+	git commit -m a2 &&
+	git checkout -b b2 master &&
+	: >file2 &&
+	git add file2 &&
+	git commit -m b2 &&
+	git checkout a2 &&
+	! (git merge-recursive master -- a2 b2 || test $? -ne 1) &&
+	! test -x file2
+'
+
+test_done
-- 
1.5.4.4

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH] merge-recursive: cause a conflict if file mode does not match
  2008-03-13 21:17         ` Johannes Schindelin
  2008-03-13 22:47           ` [PATCH] merge-recursive: handle file mode changes Clemens Buchacher
@ 2008-03-14 10:07           ` Clemens Buchacher
  1 sibling, 0 replies; 23+ messages in thread
From: Clemens Buchacher @ 2008-03-14 10:07 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git, gitster

Hi,

On Thu, Mar 13, 2008 at 10:17:07PM +0100, Johannes Schindelin wrote:
> > Your patch certainly fixes a bug in git-merge-file. It does not fix the 
> > bug in git-merge-recursive, however. The test script also fails with 
> > your patch.
> 
> Now, _that_ is funny.  I tested before sending, and my test suit runs just 
> fine.

I didn't mean the existing test suite, which is fine with your bugfix, of
course. I was talking about the test which I submitted along with my bugfix.

Regards,
Clemens

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH] merge-recursive: handle file mode and links similarly to file content
  2008-03-14  9:21               ` [PATCH] merge-recursive: handle file mode and links similarly to file content Clemens Buchacher
@ 2008-03-14 10:13                 ` Clemens Buchacher
  0 siblings, 0 replies; 23+ messages in thread
From: Clemens Buchacher @ 2008-03-14 10:13 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, gitster

On Fri, Mar 14, 2008 at 10:21:05AM +0100, Clemens Buchacher wrote:
> @@ -1051,14 +1066,11 @@ static struct merge_file_info merge_file(struct diff_filespec *o,
>  
>  			free(result_buf.ptr);
>  			result.clean = (merge_status == 0);
> -		} else if (S_ISGITLINK(a->mode)) {
> +			result.merge = 1;
> +		} else if (S_ISGITLINK(a->mode) || S_ISLNK(a->mode)) {
> +			hashcpy(result.sha, b->sha1);
>  			result.clean = 0;
> -			hashcpy(result.sha, a->sha1);
> -		} else if (S_ISLNK(a->mode)) {
> -			hashcpy(result.sha, a->sha1);
> -
> -			if (!sha_eq(a->sha1, b->sha1))
> -				result.clean = 0;
> +			result.merge = 1;

To clarify: The above two cases don't need to be handled separately any
more, because equal sha1s are already handled above.

Clemens

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH] merge-recursive: handle file mode changes
  2008-03-13 22:47           ` [PATCH] merge-recursive: handle file mode changes Clemens Buchacher
                               ` (3 preceding siblings ...)
  2008-03-14  0:17             ` Jakub Narebski
@ 2008-03-14 10:15             ` Junio C Hamano
  2008-03-14 12:17               ` Clemens Buchacher
  4 siblings, 1 reply; 23+ messages in thread
From: Junio C Hamano @ 2008-03-14 10:15 UTC (permalink / raw)
  To: Clemens Buchacher; +Cc: git, Johannes Schindelin

Clemens Buchacher <drizzd@aon.at> writes:

> diff --git a/merge-recursive.c b/merge-recursive.c
> index 34e3167..d8938cc 100644
> --- a/merge-recursive.c
> +++ b/merge-recursive.c
> @@ -1025,12 +1025,21 @@ static struct merge_file_info merge_file(struct diff_filespec *o,
>  			hashcpy(result.sha, b->sha1);
>  		}
>  	} else {
> -		if (!sha_eq(a->sha1, o->sha1) && !sha_eq(b->sha1, o->sha1))
> -			result.merge = 1;
> -
> -		result.mode = a->mode == o->mode ? b->mode: a->mode;
> +		/*
> +		 * If mode changed in only one branch, keep the changed
> +		 * version. Otherwise, keep remote version and create a
> +		 * conflict.
> +		 */

Reading the rest of the function, I notice that it consistently favor "a"
over "b", when a conflict cannot be reconciled.

> +		if (a->mode != o->mode && b->mode != o->mode &&
> +				a->mode != b->mode) {
> +			result.clean = 0;
> +			result.mode = b->mode;
> +		} else
> +			result.mode = o->mode == a->mode ? b->mode : a->mode;

I think this is much easier to read:

		if (a->mode == b->mode || a->mode == o->mode)
			result.mode = b->mode;
		else {
			result.mode = a->mode;
			if (b->mode != o->mode) {
				result.clean = 0;
				result.merge = 1;
			}
		}

We keep "b" only if "a" hasn't touched the mode, or it happens to be the
same as "a".  Otherwise we take "a" anyway, but taking "a" when "b" also
touched means we detected an unreconcilable conflict.

> @@ -1062,6 +1071,8 @@ static struct merge_file_info merge_file(struct diff_filespec *o,
>  		} else {
>  			die("unsupported object type in the tree");
>  		}
> +
> +		result.merge = !result.clean;

As pointed out by Dscho, this is too much.  We could mimick the one that
is done for the contents, which is why I have "result.merge = 1" where it
is in the above.

> diff --git a/t/t6031-merge-recursive.sh b/t/t6031-merge-recursive.sh
> new file mode 100755
> index 0000000..36cd664
> --- /dev/null
> +++ b/t/t6031-merge-recursive.sh
> @@ -0,0 +1,39 @@
> +#!/bin/sh
> ...
> +	! (git merge-recursive master -- a2 b2 || test $? -ne 1) &&
> +	! test -x file2
> +'

As we would favor our side in unreconsilable conflicts, the last test
needs to become "test -x file2".

Also we should test ls-files -u output to make sure we have correct stages
in the index.

I've done minor fixups and committed the result.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH] merge-recursive: handle file mode changes
  2008-03-14 10:15             ` Junio C Hamano
@ 2008-03-14 12:17               ` Clemens Buchacher
  2008-03-14 16:01                 ` Junio C Hamano
  0 siblings, 1 reply; 23+ messages in thread
From: Clemens Buchacher @ 2008-03-14 12:17 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Johannes Schindelin

On Fri, Mar 14, 2008 at 03:15:26AM -0700, Junio C Hamano wrote:
> > diff --git a/merge-recursive.c b/merge-recursive.c
> > index 34e3167..d8938cc 100644
> > --- a/merge-recursive.c
> > +++ b/merge-recursive.c
> > @@ -1025,12 +1025,21 @@ static struct merge_file_info merge_file(struct diff_filespec *o,
> >  			hashcpy(result.sha, b->sha1);
> >  		}
> >  	} else {
> > -		if (!sha_eq(a->sha1, o->sha1) && !sha_eq(b->sha1, o->sha1))
> > -			result.merge = 1;
> > -
> > -		result.mode = a->mode == o->mode ? b->mode: a->mode;
> > +		/*
> > +		 * If mode changed in only one branch, keep the changed
> > +		 * version. Otherwise, keep remote version and create a
> > +		 * conflict.
> > +		 */
> 
> Reading the rest of the function, I notice that it consistently favor "a"
> over "b", when a conflict cannot be reconciled.

Indeed. I think "b" should be favored over "a", however.

> > +		if (a->mode != o->mode && b->mode != o->mode &&
> > +				a->mode != b->mode) {
> > +			result.clean = 0;
> > +			result.mode = b->mode;
> > +		} else
> > +			result.mode = o->mode == a->mode ? b->mode : a->mode;
> 
> I think this is much easier to read:
> 
> 		if (a->mode == b->mode || a->mode == o->mode)
> 			result.mode = b->mode;
> 		else {
> 			result.mode = a->mode;
> 			if (b->mode != o->mode) {
> 				result.clean = 0;
> 				result.merge = 1;
> 			}
> 		}
> 
> We keep "b" only if "a" hasn't touched the mode, or it happens to be the
> same as "a".  Otherwise we take "a" anyway, but taking "a" when "b" also
> touched means we detected an unreconcilable conflict.

Yes, but if "b" and "a" both changed in the same way, we should still set
result.merge = 1, because that's more akin to an automatic merge than a
fast-forward merge, IMO.

Clemens

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH] merge-recursive: handle file mode changes
  2008-03-14  0:17             ` Jakub Narebski
@ 2008-03-14 12:56               ` Clemens Buchacher
  0 siblings, 0 replies; 23+ messages in thread
From: Clemens Buchacher @ 2008-03-14 12:56 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: git

On Fri, Mar 14, 2008 at 01:17:10AM +0100, Jakub Narebski wrote:
> > Handle file mode changes similarly to changes of content. If the file mode
> > changed in only one branch, keep the changed version. If the file mode
> > changed in both branches, prompt the user to choose one by reporting a
> > conflict.
> 
> Shouldn't it print "CONFLICT(mode/mode)" then?

I think currently the only way to get a mode conflict is when a file is added
in both branches with different permissions, since we only track the executable
bit.

Clemens

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH] merge-recursive: handle file mode changes
  2008-03-14  0:12             ` Junio C Hamano
@ 2008-03-14 13:02               ` Clemens Buchacher
  0 siblings, 0 replies; 23+ messages in thread
From: Clemens Buchacher @ 2008-03-14 13:02 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Johannes Schindelin, git

On Thu, Mar 13, 2008 at 05:12:39PM -0700, Junio C Hamano wrote:
> This is from the e-mail header of your message:
> 
>   Mail-Followup-To: Johannes Schindelin <Johannes.Schindelin@gmx.de>,
>    git@vger.kernel.org, gitster@pobox.com
> 
> If you are asking people question, do not do this.  You want answers
> addressed to you.  Johannes and I may not be interested in learning what
> may want to find out, and redirecting answers for you to us is simply
> rude.

My apologies. I wasn't aware that was doing that.

Clemens

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH] merge-recursive: handle file mode changes
  2008-03-14 12:17               ` Clemens Buchacher
@ 2008-03-14 16:01                 ` Junio C Hamano
  2008-03-14 17:28                   ` Clemens Buchacher
  0 siblings, 1 reply; 23+ messages in thread
From: Junio C Hamano @ 2008-03-14 16:01 UTC (permalink / raw)
  To: Clemens Buchacher; +Cc: git, Johannes Schindelin

Clemens Buchacher <drizzd@aon.at> writes:

>> Reading the rest of the function, I notice that it consistently favor "a"
>> over "b", when a conflict cannot be reconciled.
>
> Indeed. I think "b" should be favored over "a", however.

Why?

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH] merge-recursive: handle file mode changes
  2008-03-14 16:01                 ` Junio C Hamano
@ 2008-03-14 17:28                   ` Clemens Buchacher
  2008-03-14 17:49                     ` Junio C Hamano
  0 siblings, 1 reply; 23+ messages in thread
From: Clemens Buchacher @ 2008-03-14 17:28 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Johannes Schindelin

On Fri, Mar 14, 2008 at 09:01:06AM -0700, Junio C Hamano wrote:
> Clemens Buchacher <drizzd@aon.at> writes:
> >> Reading the rest of the function, I notice that it consistently favor "a"
> >> over "b", when a conflict cannot be reconciled.
> >
> > Indeed. I think "b" should be favored over "a", however.
> 
> Why?

>From the commit message to the latest version of my patch:
http://marc.info/?l=git&m=120548648727308&w=2

On Fri, Mar 14, 2008 at 10:21:05AM +0100, Clemens Buchacher wrote:
> If the file mode or link changed in only one branch, keep the changed
> version. If the file mode or link changed differently in both branches,
> report a conflict. If this happens, the user is more likely to be aware of
> the change in the head branch. Choose the remote version by default, in
> order to make the user think about the change.

In principle, both decisions are equally right or wrong. However, suggesting
the remote version (i.e., "b") by default gives more incentive to think about
it because the file now changed with respect to the head version (i.e., "a"),
which the user started out with.

Clemens

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH] merge-recursive: handle file mode changes
  2008-03-14 17:28                   ` Clemens Buchacher
@ 2008-03-14 17:49                     ` Junio C Hamano
  0 siblings, 0 replies; 23+ messages in thread
From: Junio C Hamano @ 2008-03-14 17:49 UTC (permalink / raw)
  To: Clemens Buchacher; +Cc: git, Johannes Schindelin

Clemens Buchacher <drizzd@aon.at> writes:

> On Fri, Mar 14, 2008 at 10:21:05AM +0100, Clemens Buchacher wrote:
>> If the file mode or link changed in only one branch, keep the changed
>> version. If the file mode or link changed differently in both branches,
>> report a conflict. If this happens, the user is more likely to be aware of
>> the change in the head branch. Choose the remote version by default, in
>> order to make the user think about the change.
>
> In principle, both decisions are equally right or wrong. However, suggesting
> the remote version (i.e., "b") by default gives more incentive to think about
> it because the file now changed with respect to the head version (i.e., "a"),
> which the user started out with.

This matters only when the conflict is irreconcilable in the work tree,
and as long as we get the most important part right, i.e. marking the path
to be conflicting, that is good enough to make sure that the user does not
commit without thinking.

Besides the change breaks the traditional behaviour of leaving the "a"
side in the work tree.  As you already know, what you have done is as
equally valid as the other side did.  Be assertive and more confident in
what you have done ;-).

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2008-03-14 17:50 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-03-08 17:17 [PATCH] fix recursive-merge of empty files with different permissions Clemens Buchacher
2008-03-08 17:51 ` Johannes Schindelin
2008-03-13 12:52   ` Clemens Buchacher
2008-03-13 15:19     ` Johannes Schindelin
2008-03-13 18:50       ` Junio C Hamano
2008-03-13 21:28         ` Johannes Schindelin
2008-03-13 19:22       ` [PATCH] merge-recursive: cause a conflict if file mode does not match Clemens Buchacher
2008-03-13 21:17         ` Johannes Schindelin
2008-03-13 22:47           ` [PATCH] merge-recursive: handle file mode changes Clemens Buchacher
2008-03-13 23:40             ` Johannes Schindelin
2008-03-14  9:21               ` [PATCH] merge-recursive: handle file mode and links similarly to file content Clemens Buchacher
2008-03-14 10:13                 ` Clemens Buchacher
2008-03-14  0:08             ` [PATCH] merge-recursive: handle file mode changes Junio C Hamano
2008-03-14  0:12             ` Junio C Hamano
2008-03-14 13:02               ` Clemens Buchacher
2008-03-14  0:17             ` Jakub Narebski
2008-03-14 12:56               ` Clemens Buchacher
2008-03-14 10:15             ` Junio C Hamano
2008-03-14 12:17               ` Clemens Buchacher
2008-03-14 16:01                 ` Junio C Hamano
2008-03-14 17:28                   ` Clemens Buchacher
2008-03-14 17:49                     ` Junio C Hamano
2008-03-14 10:07           ` [PATCH] merge-recursive: cause a conflict if file mode does not match Clemens Buchacher

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).