git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH v4 1/2] rerere: wait for MERGE_RR.lock, and let the gc skip it

From
Patrick Steinhardt <ps@pks.im>
Date
Sep 28, 2026, 08:18 UTC
Message-ID
<aroixgCkqbmKErng@pks.im>
In-Reply-To
<8a7a74d6aa359844a49593538ef6178cd1b02031.1789373061.git.gitgitgadget@gmail.com>
On Mon, Sep 14, 2026 at 08:04:20AM +0000, Thomas Bachem via GitGitGadget wrote:
Show 12 quoted lines
> diff --git a/Documentation/git-rerere.adoc b/Documentation/git-rerere.adoc
> index 4e6ab9a27c..4df653367e 100644
> --- a/Documentation/git-rerere.adoc
> +++ b/Documentation/git-rerere.adoc
> @@ -70,7 +70,9 @@ occurred a long time ago.  By default, unresolved conflicts older
>  than 15 days and resolved conflicts older than 60
>  days are pruned.  These defaults are controlled via the
>  `gc.rerereUnresolved` and `gc.rerereResolved` configuration
> -variables respectively.
> +variables respectively.  If another process holds the rerere lock,
> +for example a merge or rebase that is recording a conflict, `gc`
> +does nothing and says so.

Do we maybe want to drop these examples? I don't feel like they add any value.

Show 40 quoted lines
> diff --git a/rerere.c b/rerere.c
> index 3d3bd0db16..7d44f3937c 100644
> --- a/rerere.c
> +++ b/rerere.c
> @@ -33,6 +33,9 @@ static int rerere_enabled = -1;
>  /* automatically update cleanly resolved paths to the index */
>  static int rerere_autoupdate;
>  
> +/* how long to wait for MERGE_RR.lock, in milliseconds */
> +static int rerere_lock_timeout_ms = 1000;
> +
>  #define RR_HAS_POSTIMAGE 1
>  #define RR_HAS_PREIMAGE 2
>  struct rerere_dir {
> @@ -850,6 +853,8 @@ static void git_rerere_config(void)
>  {
>  	repo_config_get_bool(the_repository, "rerere.enabled", &rerere_enabled);
>  	repo_config_get_bool(the_repository, "rerere.autoupdate", &rerere_autoupdate);
> +	repo_config_get_int(the_repository, "rerere.locktimeout",
> +			    &rerere_lock_timeout_ms);
>  	repo_config(the_repository, git_default_config, NULL);
>  }
>  
> @@ -882,12 +887,34 @@ int setup_rerere(struct repository *r, struct string_list *merge_rr, int flags)
>  
>  	if (flags & (RERERE_AUTOUPDATE|RERERE_NOAUTOUPDATE))
>  		rerere_autoupdate = !!(flags & RERERE_AUTOUPDATE);
> -	if (flags & RERERE_READONLY)
> +	if ((flags & RERERE_READONLY) && (flags & RERERE_NOWAIT))
> +		BUG("RERERE_READONLY takes no lock, so RERERE_NOWAIT does not apply");
> +	if (flags & RERERE_READONLY) {
>  		fd = 0;
> -	else
> -		fd = repo_hold_lock_file_for_update(r, &write_lock,
> -						    git_path_merge_rr(r),
> -						    LOCK_DIE_ON_ERROR);
> +	} else {
> +		const char *path = git_path_merge_rr(r);
> +		int lock_flags = LOCK_DIE_ON_ERROR;
> +		long timeout_ms = rerere_lock_timeout_ms;

Here you're using a `long` whereas `rerere_lock_timeout_ms` is an `int`. Of course we'd ideally use a `long` consistently as that's also what `repo_hold_lock_file_for_update_timeout()` accepts. But I guess the reason you didn't is that we don't have `repo_config_get_long()`. So I guess this is good enough for now.

Show 9 quoted lines
> @@ -1211,7 +1238,7 @@ void rerere_gc(struct repository *r, struct string_list *rr)
>  	timestamp_t cutoff_resolve = now - 60 * 86400;
>  	struct strbuf buf = STRBUF_INIT;
>  
> -	if (setup_rerere(r, rr, 0) < 0)
> +	if (setup_rerere(r, rr, RERERE_NOWAIT) < 0)
>  		return;
>  
>  	repo_config_get_expiry_in_days(the_repository, "gc.rerereresolved",

I'm not a 100% sold on this change. There's two different scenarios under which we want to perform garbage collection:

  - As part of auto-maintenance, triggered by Git automatically. Here
    I'm fully aligned that it makes sense to just silently ignore the
    case where we couldn't acquire the lock, as auto-maintenance is done
    on a best-effort basis anyway.
  - As part of `git rerere gc`, which is invoked manually by the user.
    Here I'm less so, as the user has explicitly asked us to garbage
    collect. Sure, we print a warning now, but the exit code does not
    signal that we failed garbage collecting.

So I'd argue that we should discern those two use cases. I think that in the second use case, we'd probably want to use a timeout and if we fail to acquire the lock, we should make `git rerere gc` fail with a non-zero exit code.

Patrick
Previous: Thomas Bachem via GitGitGadgetNext: Thomas Bachem via GitGitGadget
Message 24 of 39 in “rerere: keep a background gc from killing a rebase”
  1. rerere: keep a background gc from killing a rebaseThomas Bachem via GitGitGadget, Sep 2, 2026
  2. Phillip WoodSep 2, 2026
  3. Thomas BachemSep 2, 2026
  4. Phillip WoodSep 3, 2026
  5. Patrick SteinhardtSep 3, 2026
  6. Thomas BachemSep 3, 2026
  7. Patrick SteinhardtSep 3, 2026
  8. Thomas BachemSep 3, 2026
  9. Phillip WoodSep 3, 2026
  10. rerere: keep a background gc from killing a rebaseThomas Bachem via GitGitGadget, Sep 4, 2026
  11. Phillip WoodSep 4, 2026
  12. Thomas BachemSep 4, 2026
  13. Phillip WoodSep 7, 2026
  14. Junio C HamanoSep 4, 2026
  15. Thomas BachemSep 4, 2026
  16. rerere: keep a background gc from killing a rebaseThomas Bachem via GitGitGadget, Sep 4, 2026
  17. Junio C HamanoSep 4, 2026
  18. Thomas BachemSep 5, 2026
  19. Junio C HamanoSep 5, 2026
  20. Thomas BachemSep 6, 2026
  21. Patrick SteinhardtSep 7, 2026
  22. 0/2 rerere: wait for MERGE_RR.lock, and go on at a conflictThomas Bachem via GitGitGadget, Sep 14, 2026
  23. 1/2 rerere: wait for MERGE_RR.lock, and let the gc skip itThomas Bachem via GitGitGadget, Sep 14, 2026
  24. Patrick SteinhardtSep 28, 2026
  25. 2/2 rerere: go on at a conflict when the lock stays busyThomas Bachem via GitGitGadget, Sep 14, 2026
  26. Patrick SteinhardtSep 28, 2026
  27. 0/3 rerere: wait for MERGE_RR.lock, and go on at a conflictThomas Bachem via GitGitGadget, Sep 28, 2026
  28. 1/3 rerere: wait for MERGE_RR.lock before giving upThomas Bachem via GitGitGadget, Sep 28, 2026
  29. 2/3 rerere: add "gc --auto" that skips a held lockThomas Bachem via GitGitGadget, Sep 28, 2026
  30. Patrick SteinhardtSep 30, 2026
  31. Thomas BachemOct 1, 2026
  32. Patrick SteinhardtOct 1, 2026
  33. 3/3 rerere: go on at a conflict when the lock stays busyThomas Bachem via GitGitGadget, Sep 28, 2026
  34. 0/3 rerere: wait for MERGE_RR.lock, and go on at a conflictThomas Bachem via GitGitGadget, Oct 2, 2026
  35. 1/3 rerere: wait for MERGE_RR.lock before giving upThomas Bachem via GitGitGadget, Oct 2, 2026
  36. 2/3 rerere: add "gc --skip-locked" for auto maintenanceThomas Bachem via GitGitGadget, Oct 2, 2026
  37. Patrick SteinhardtOct 9, 2026
  38. 3/3 rerere: go on at a conflict when the lock stays busyThomas Bachem via GitGitGadget, Oct 2, 2026
  39. Patrick SteinhardtOct 9, 2026

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.