diff mbox series

rerere: enable by default

Message ID xmqqfsxvxjj2.fsf@gitster.g (mailing list archive)
State New, archived
Headers show
Series rerere: enable by default | expand

Commit Message

Junio C Hamano June 6, 2021, 12:30 p.m. UTC
By default, the rerere machinery has been disabled since a bug in
the machinery could screw up the end user's data at the most
stressful time during the end user's workday (i.e. during conflict
resolution).

It however has been in wide use without causing much trouble (other
than, obviously, replaying a broken conflict resolution that was
recorded earlier when the user made a mismerge), and it is about
time to enable it by default.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 Documentation/config/rerere.txt |  5 ++---
 rerere.c                        | 12 +++---------
 t/t2030-unresolve-info.sh       |  3 +++
 3 files changed, 8 insertions(+), 12 deletions(-)

Comments

brian m. carlson June 7, 2021, 12:56 a.m. UTC | #1
On 2021-06-06 at 12:30:25, Junio C Hamano wrote:
> By default, the rerere machinery has been disabled since a bug in
> the machinery could screw up the end user's data at the most
> stressful time during the end user's workday (i.e. during conflict
> resolution).
> 
> It however has been in wide use without causing much trouble (other
> than, obviously, replaying a broken conflict resolution that was
> recorded earlier when the user made a mismerge), and it is about
> time to enable it by default.

Yes, I think this makes sense.  I've been using it for quite a while
without problems and I'm usually quite good at breaking things, and if
we can make the user experience better, which I think rerere does,
that's definitely a good thing.
Ævar Arnfjörð Bjarmason June 7, 2021, 9:50 a.m. UTC | #2
On Sun, Jun 06 2021, Junio C Hamano wrote:

> By default, the rerere machinery has been disabled since a bug in
> the machinery could screw up the end user's data at the most
> stressful time during the end user's workday (i.e. during conflict
> resolution).

What was that bug & in what commit was it fixed? Makes sense to note
that here.

> It however has been in wide use without causing much trouble (other
> than, obviously, replaying a broken conflict resolution that was
> recorded earlier when the user made a mismerge), and it is about
> time to enable it by default.
>
> Signed-off-by: Junio C Hamano <gitster@pobox.com>
> ---
>  Documentation/config/rerere.txt |  5 ++---
>  rerere.c                        | 12 +++---------
>  t/t2030-unresolve-info.sh       |  3 +++
>  3 files changed, 8 insertions(+), 12 deletions(-)
>
> diff --git a/Documentation/config/rerere.txt b/Documentation/config/rerere.txt
> index 40abdf6a6b..45e97fc0fa 100644
> --- a/Documentation/config/rerere.txt
> +++ b/Documentation/config/rerere.txt
> @@ -7,6 +7,5 @@ rerere.enabled::
>  	Activate recording of resolved conflicts, so that identical
>  	conflict hunks can be resolved automatically, should they be
>  	encountered again.  By default, linkgit:git-rerere[1] is
> -	enabled if there is an `rr-cache` directory under the
> -	`$GIT_DIR`, e.g. if "rerere" was previously used in the
> -	repository.
> +	enabled, but this configuration can be set to 'false' to
> +	turn it off.
> diff --git a/rerere.c b/rerere.c
> index d83d58df4f..83e740d730 100644
> --- a/rerere.c
> +++ b/rerere.c
> @@ -18,8 +18,7 @@
>  #define THREE_STAGED 2
>  void *RERERE_RESOLVED = &RERERE_RESOLVED;
>  
> -/* if rerere_enabled == -1, fall back to detection of .git/rr-cache */
> -static int rerere_enabled = -1;
> +static int rerere_enabled = 1; /* default to true */
>  
>  /* automatically update cleanly resolved paths to the index */
>  static int rerere_autoupdate;
> @@ -852,16 +851,11 @@ static GIT_PATH_FUNC(git_path_rr_cache, "rr-cache")
>  
>  static int is_rerere_enabled(void)
>  {
> -	int rr_cache_exists;
> -
>  	if (!rerere_enabled)
>  		return 0;
>  
> -	rr_cache_exists = is_directory(git_path_rr_cache());
> -	if (rerere_enabled < 0)
> -		return rr_cache_exists;
> -
> -	if (!rr_cache_exists && mkdir_in_gitdir(git_path_rr_cache()))
> +	if (!is_directory(git_path_rr_cache()) &&
> +	    mkdir_in_gitdir(git_path_rr_cache()))
>  		die(_("could not create directory '%s'"), git_path_rr_cache());
>  	return 1;
>  }
> diff --git a/t/t2030-unresolve-info.sh b/t/t2030-unresolve-info.sh
> index be6c84c52a..8c571ddf92 100755
> --- a/t/t2030-unresolve-info.sh
> +++ b/t/t2030-unresolve-info.sh
> @@ -46,6 +46,7 @@ prime_resolve_undo () {
>  }
>  
>  test_expect_success setup '
> +	git config rerere.enabled false &&
>  	mkdir fi &&
>  	printf "a\0a" >binary &&
>  	git add binary &&
> @@ -127,6 +128,8 @@ test_expect_success 'unmerge with plumbing' '
>  '
>  
>  test_expect_success 'rerere and rerere forget' '
> +	# from here on, use rerere.
> +	git config rerere.enabled true &&
>  	mkdir .git/rr-cache &&
>  	prime_resolve_undo &&
>  	echo record the resolution &&

It seems strange to disable it at the very beginning, but then not have
any test until you turn it on actually rely on that except that "mkdir"
in the second hunk, i.e. this on top works:
	
	diff --git a/t/t2030-unresolve-info.sh b/t/t2030-unresolve-info.sh
	index 8c571ddf92..7195ded9f9 100755
	--- a/t/t2030-unresolve-info.sh
	+++ b/t/t2030-unresolve-info.sh
	@@ -46,7 +46,6 @@ prime_resolve_undo () {
	 }
	 
	 test_expect_success setup '
	-	git config rerere.enabled false &&
	 	mkdir fi &&
	 	printf "a\0a" >binary &&
	 	git add binary &&
	@@ -130,7 +129,6 @@ test_expect_success 'unmerge with plumbing' '
	 test_expect_success 'rerere and rerere forget' '
	 	# from here on, use rerere.
	 	git config rerere.enabled true &&
	-	mkdir .git/rr-cache &&
	 	prime_resolve_undo &&
	 	echo record the resolution &&
	 	git rerere &&

So the only impact of that rerere.enabled=false early is to make sure
we're not creating the .git/rr-cache.

Those tests will fail if we turned on rerere.autoUpdate=true there, so
isn't it a better test coverage to assert that even with
rerere.enabled=true we don't impact these merge resolutions in the
earlier tests?

It also seems to make sense to change the main rerere tests to assert
that we have the default set to this new value, i.e.:
	
	diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh
	index 9f8c76dffb..f319f08852 100755
	--- a/t/t4200-rerere.sh
	+++ b/t/t4200-rerere.sh
	@@ -89,8 +89,8 @@ test_expect_success 'activate rerere, old style (conflicting merge)' '
	 '
	 
	 test_expect_success 'rerere.enabled works, too' '
	+	test_path_is_dir .git/rr-cache &&
	 	rm -rf .git/rr-cache &&
	-	git config rerere.enabled true &&
	 	git reset --hard &&
	 	test_must_fail git merge first &&
	 
	@@ -100,8 +100,8 @@ test_expect_success 'rerere.enabled works, too' '
	 '
	 
	 test_expect_success 'set up rr-cache' '
	+	test_path_is_dir .git/rr-cache &&
	 	rm -rf .git/rr-cache &&
	-	git config rerere.enabled true &&
	 	git reset --hard &&
	 	test_must_fail git merge first &&
	 	sha1=$(perl -pe "s/	.*//" .git/MERGE_RR) &&
	@@ -668,7 +668,6 @@ test_expect_success 'test simple stage 1 handling' '
	 	(
	 		cd stage_1_handling &&
	 
	-		git config rerere.enabled true &&
	 		git checkout A^0 &&
	 		test_must_fail git merge B^0
	 	)

As an aside: This pre-dates your change here, but I thought the config
reading in rerere.c was a bit odd, why do we call the one-off config
reading functions when we're about to iterate over the whole set anyway?
Turns out we did it the way I'd expect before 633e5ad326 (rerere.c:
replace `git_config()` with `git_config_get_*()` family, 2014-08-07).
Junio C Hamano June 7, 2021, 9:51 a.m. UTC | #3
"brian m. carlson" <sandals@crustytoothpaste.net> writes:

> On 2021-06-06 at 12:30:25, Junio C Hamano wrote:
>> By default, the rerere machinery has been disabled since a bug in
>> the machinery could screw up the end user's data at the most
>> stressful time during the end user's workday (i.e. during conflict
>> resolution).
>> 
>> It however has been in wide use without causing much trouble (other
>> than, obviously, replaying a broken conflict resolution that was
>> recorded earlier when the user made a mismerge), and it is about
>> time to enable it by default.
>
> Yes, I think this makes sense.  I've been using it for quite a while
> without problems and I'm usually quite good at breaking things, and if
> we can make the user experience better, which I think rerere does,
> that's definitely a good thing.

I agree in principle, but new tests added by topics in flight need
to get prepared for the change.  There are, for example, misguided
checks that insist that the standard error stream out of "git merge"
must be absolutely empty, which will break when rerere machinery
starts reporting that it prepared the preimage so that it can record
the resolution.  Not just rerere, but such a test is brittle and
will break when other inner parts of the system starts reporting
more (e.g. progress) to the standard error stream.

I'd prefer to see these tests cleaned up in the right way (as
opposed to setting rerere.enabled to false upfront, which hides
these suboptimal tests) before this change to enable rerere by
default lands, so it may need a sizeable preparatory work.

Thanks.
Andrei Rybak June 7, 2021, 10:34 a.m. UTC | #4
On 06/06/2021 14:30, Junio C Hamano wrote:
> By default, the rerere machinery has been disabled since a bug in
> the machinery could screw up the end user's data at the most
> stressful time during the end user's workday (i.e. during conflict
> resolution).
> 
> It however has been in wide use without causing much trouble (other
> than, obviously, replaying a broken conflict resolution that was
> recorded earlier when the user made a mismerge), and it is about
> time to enable it by default.
> 
> Signed-off-by: Junio C Hamano <gitster@pobox.com>
> ---
>   Documentation/config/rerere.txt |  5 ++---
>   rerere.c                        | 12 +++---------
>   t/t2030-unresolve-info.sh       |  3 +++
>   3 files changed, 8 insertions(+), 12 deletions(-)
> 
> diff --git a/Documentation/config/rerere.txt b/Documentation/config/rerere.txt
> index 40abdf6a6b..45e97fc0fa 100644
> --- a/Documentation/config/rerere.txt
> +++ b/Documentation/config/rerere.txt
> @@ -7,6 +7,5 @@ rerere.enabled::
>   	Activate recording of resolved conflicts, so that identical
>   	conflict hunks can be resolved automatically, should they be
>   	encountered again.  By default, linkgit:git-rerere[1] is
> -	enabled if there is an `rr-cache` directory under the
> -	`$GIT_DIR`, e.g. if "rerere" was previously used in the
> -	repository.
> +	enabled, but this configuration can be set to 'false' to

At the moment, backticks are used more often than single quotes
for formatting of boolean values in documentation:

     $ git grep -oE "\`(false|true)\`" -- Documentation/*.txt Documentation/config/*.txt | wc -l
     121
     $ git grep -oE "'(false|true)'" -- Documentation/*.txt Documentation/config/*.txt | wc -l
     53

> +	turn it off.
Junio C Hamano June 7, 2021, 11:05 a.m. UTC | #5
Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> On Sun, Jun 06 2021, Junio C Hamano wrote:
>
>> By default, the rerere machinery has been disabled since a bug in
>> the machinery could screw up the end user's data at the most
>> stressful time during the end user's workday (i.e. during conflict
>> resolution).
>
> What was that bug & in what commit was it fixed? Makes sense to note
> that here.

There is no such bug ;-).

Writing buggy code, not thinking about it carefully enough and
jumping up and down yelling this shiny new toy must be merged down
immediately is something we see on this list from others, but it is
the total opposite of how I operate.  I just am extra cautious and
even after I am reasonably sure the code would not break, I prefer
to have volunteers to opt into testing.

> 	@@ -130,7 +129,6 @@ test_expect_success 'unmerge with plumbing' '
> 	 test_expect_success 'rerere and rerere forget' '
> 	 	# from here on, use rerere.
> 	 	git config rerere.enabled true &&
> 	-	mkdir .git/rr-cache &&
> 	 	prime_resolve_undo &&
> 	 	echo record the resolution &&
> 	 	git rerere &&
>
> So the only impact of that rerere.enabled=false early is to make sure
> we're not creating the .git/rr-cache.

Not really.  Unresolve is about recording the initial conflict in
the index, so it is far easier to see its effect if you do not
enable rerere, when you are manually debugging these earlier tests.

And later test do check how it works with rerere enabled, but the
way the original sequence of tests enable it is with the "mkdir".
I.e. "if rerere.enabled is not set either way, presence of the
directory means it is already enabled".  The new test sequence
uses the configuration variable explicitly, because in the new world
order, the presence of the directory does not mean a thing.
Ævar Arnfjörð Bjarmason June 7, 2021, 12:56 p.m. UTC | #6
On Mon, Jun 07 2021, Junio C Hamano wrote:

> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
>
>> On Sun, Jun 06 2021, Junio C Hamano wrote:
>>
>>> By default, the rerere machinery has been disabled since a bug in
>>> the machinery could screw up the end user's data at the most
>>> stressful time during the end user's workday (i.e. during conflict
>>> resolution).
>>
>> What was that bug & in what commit was it fixed? Makes sense to note
>> that here.
>
> There is no such bug ;-).
>
> Writing buggy code, not thinking about it carefully enough and
> jumping up and down yelling this shiny new toy must be merged down
> immediately is something we see on this list from others, but it is
> the total opposite of how I operate.  I just am extra cautious and
> even after I am reasonably sure the code would not break, I prefer
> to have volunteers to opt into testing.

Thanks. I misread that, and was (perhaps mis-)remembering the previous
thread about this discussing some past bugs...

>> 	@@ -130,7 +129,6 @@ test_expect_success 'unmerge with plumbing' '
>> 	 test_expect_success 'rerere and rerere forget' '
>> 	 	# from here on, use rerere.
>> 	 	git config rerere.enabled true &&
>> 	-	mkdir .git/rr-cache &&
>> 	 	prime_resolve_undo &&
>> 	 	echo record the resolution &&
>> 	 	git rerere &&
>>
>> So the only impact of that rerere.enabled=false early is to make sure
>> we're not creating the .git/rr-cache.
>
> Not really.  Unresolve is about recording the initial conflict in
> the index, so it is far easier to see its effect if you do not
> enable rerere, when you are manually debugging these earlier tests.
>
> And later test do check how it works with rerere enabled, but the
> way the original sequence of tests enable it is with the "mkdir".
> I.e. "if rerere.enabled is not set either way, presence of the
> directory means it is already enabled".  The new test sequence
> uses the configuration variable explicitly, because in the new world
> order, the presence of the directory does not mean a thing.

I mean you added "from here on, use rerere", but if I instrument the
tests to set rerere.enabled=false they also pass, sans the .git/rr-cache
directory being created.

So we weren't "using rerere", we were just writing the data on the side.

We *do* get a failure in test #3, "rm records reset clears", if we set
rerere.autoUpdate=true. So it seems to me that what those first tests
would benefit more from not having the addition of your
rerere.enabled=false line early on.

After all it's more interesting to test that the merge resolution is not
different in any way under rerere.enabled=true & rerere.autoUpdate=false
than to not write the rr-cache data at all. It seems like having just
one test with rerere.enabled=false & "I did not write .git/rr-cache"
would make for better coverage.

I.e. this on top works:
	
	diff --git a/t/t2030-unresolve-info.sh b/t/t2030-unresolve-info.sh
	index 8c571ddf92..b010f504b0 100755
	--- a/t/t2030-unresolve-info.sh
	+++ b/t/t2030-unresolve-info.sh
	@@ -46,11 +46,12 @@ prime_resolve_undo () {
	 }
	 
	 test_expect_success setup '
	-	git config rerere.enabled false &&
	 	mkdir fi &&
	 	printf "a\0a" >binary &&
	 	git add binary &&
	+	! test_path_is_dir .git/rr-cache &&
	 	test_commit initial fi/le first &&
	+	test_path_is_dir .git/rr-cache &&
	 	git branch side &&
	 	git branch another &&
	 	printf "a\0b" >binary &&
	@@ -128,9 +129,6 @@ test_expect_success 'unmerge with plumbing' '
	 '
	 
	 test_expect_success 'rerere and rerere forget' '
	-	# from here on, use rerere.
	-	git config rerere.enabled true &&
	-	mkdir .git/rr-cache &&
	 	prime_resolve_undo &&
	 	echo record the resolution &&
	 	git rerere &&
	@@ -156,7 +154,6 @@ test_expect_success 'rerere and rerere forget' '
	 
	 test_expect_success 'rerere and rerere forget (subdirectory)' '
	 	rm -fr .git/rr-cache &&
	-	mkdir .git/rr-cache &&
	 	prime_resolve_undo &&
	 	echo record the resolution &&
	 	(cd fi && git rerere) &&

As an aside when testing this I found that I could make it segfault by
not doing the mkdir() in setup_rerere() and without:

	diff --git a/rerere.c b/rerere.c
	index 83e740d730..06fb86d5b7 100644
	--- a/rerere.c
	+++ b/rerere.c
	@@ -731,7 +731,10 @@ static void do_rerere_one_path(struct index_state *istate,
	 	/* Has the user resolved it already? */
	 	if (variant >= 0) {
	 		if (!handle_file(istate, path, NULL, NULL)) {
	-			copy_file(rerere_path(id, "postimage"), path, 0666);
	+			const char *dst = rerere_path(id, "postimage");
	+			if (copy_file(dst, path, 0666))
	+				die_errno(_("could not copy '%s' to '%s'"),
	+					  path, dst);
	 			id->collection->status[variant] |= RR_HAS_POSTIMAGE;
	 			fprintf_ln(stderr, _("Recorded resolution for '%s'."), path);
	 			free_rerere_id(rr_item);
	

I.e. we make the hard assumption that the directory has been created,
and don't check the return value(s) of various subsequent file copying
etc. So there's a rare segfault in the wild if the "setup_rerere()"
races with something that removes the .git/rr-cache (perhaps git-gc will
remove it entirely?).
Felipe Contreras June 7, 2021, 4:41 p.m. UTC | #7
Junio C Hamano wrote:
> By default, the rerere machinery has been disabled since a bug in
> the machinery could screw up the end user's data at the most
> stressful time during the end user's workday (i.e. during conflict
> resolution).
> 
> It however has been in wide use without causing much trouble (other
> than, obviously, replaying a broken conflict resolution that was
> recorded earlier when the user made a mismerge), and it is about
> time to enable it by default.

That is a good diea.

> Signed-off-by: Junio C Hamano <gitster@pobox.com>

But did you really come up with it all by yourself?

Could perhaps this mail [1] sent 5 days prior have anything to do with it?

> If the defaults make your life hard, then shouldn't we change the
> defaults?

> But, if we are already on this topic... who wants rerere disabled by
> default?

Cheers.

[1] https://lore.kernel.org/git/60b61089ba63d_e40ca20894@natae.notmuch/
diff mbox series

Patch

diff --git a/Documentation/config/rerere.txt b/Documentation/config/rerere.txt
index 40abdf6a6b..45e97fc0fa 100644
--- a/Documentation/config/rerere.txt
+++ b/Documentation/config/rerere.txt
@@ -7,6 +7,5 @@  rerere.enabled::
 	Activate recording of resolved conflicts, so that identical
 	conflict hunks can be resolved automatically, should they be
 	encountered again.  By default, linkgit:git-rerere[1] is
-	enabled if there is an `rr-cache` directory under the
-	`$GIT_DIR`, e.g. if "rerere" was previously used in the
-	repository.
+	enabled, but this configuration can be set to 'false' to
+	turn it off.
diff --git a/rerere.c b/rerere.c
index d83d58df4f..83e740d730 100644
--- a/rerere.c
+++ b/rerere.c
@@ -18,8 +18,7 @@ 
 #define THREE_STAGED 2
 void *RERERE_RESOLVED = &RERERE_RESOLVED;
 
-/* if rerere_enabled == -1, fall back to detection of .git/rr-cache */
-static int rerere_enabled = -1;
+static int rerere_enabled = 1; /* default to true */
 
 /* automatically update cleanly resolved paths to the index */
 static int rerere_autoupdate;
@@ -852,16 +851,11 @@  static GIT_PATH_FUNC(git_path_rr_cache, "rr-cache")
 
 static int is_rerere_enabled(void)
 {
-	int rr_cache_exists;
-
 	if (!rerere_enabled)
 		return 0;
 
-	rr_cache_exists = is_directory(git_path_rr_cache());
-	if (rerere_enabled < 0)
-		return rr_cache_exists;
-
-	if (!rr_cache_exists && mkdir_in_gitdir(git_path_rr_cache()))
+	if (!is_directory(git_path_rr_cache()) &&
+	    mkdir_in_gitdir(git_path_rr_cache()))
 		die(_("could not create directory '%s'"), git_path_rr_cache());
 	return 1;
 }
diff --git a/t/t2030-unresolve-info.sh b/t/t2030-unresolve-info.sh
index be6c84c52a..8c571ddf92 100755
--- a/t/t2030-unresolve-info.sh
+++ b/t/t2030-unresolve-info.sh
@@ -46,6 +46,7 @@  prime_resolve_undo () {
 }
 
 test_expect_success setup '
+	git config rerere.enabled false &&
 	mkdir fi &&
 	printf "a\0a" >binary &&
 	git add binary &&
@@ -127,6 +128,8 @@  test_expect_success 'unmerge with plumbing' '
 '
 
 test_expect_success 'rerere and rerere forget' '
+	# from here on, use rerere.
+	git config rerere.enabled true &&
 	mkdir .git/rr-cache &&
 	prime_resolve_undo &&
 	echo record the resolution &&