-
Notifications
You must be signed in to change notification settings - Fork 202
rerere: wait for MERGE_RR.lock, and go on at a conflict #2214
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,3 +10,17 @@ rerere.enabled:: | |
| enabled if there is an `rr-cache` directory under the | ||
| `$GIT_DIR`, e.g. if "rerere" was previously used in the | ||
| repository. | ||
|
|
||
| rerere.lockTimeout:: | ||
| The length of time, in milliseconds, to wait for the rerere | ||
| lock when another process holds it, typically a background | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Patrick Steinhardt wrote on the Git mailing list (how to reply to this email): On Mon, Sep 14, 2026 at 08:04:21AM +0000, Thomas Bachem via GitGitGadget wrote:
> diff --git a/rerere.c b/rerere.c
> index 7d44f3937c..a996d39159 100644
> --- a/rerere.c
> +++ b/rerere.c
> @@ -900,18 +902,26 @@ int setup_rerere(struct repository *r, struct string_list *merge_rr, int flags)
> * Another process may hold the lock for a while, e.g.
> * "git rerere gc" while it prunes rr-cache, so wait for
> * it instead of dying right away. The gc itself never
> - * waits: skipping one of its runs costs nothing.
> + * waits: skipping one of its runs costs nothing. A
> + * command that stops at a conflict must not die here
> + * either, so it warns and goes on without rerere.
> */
> if (flags & RERERE_NOWAIT) {
> lock_flags = 0;
> timeout_ms = 0;
> }
> + if (flags & RERERE_SKIP_LOCKED)
> + lock_flags = 0;
> fd = repo_hold_lock_file_for_update_timeout(r, &write_lock,
> path, lock_flags,
> timeout_ms);
> if (fd < 0) {
> warning_errno(_("skipping rerere, "
> "unable to create '%s.lock'"), path);
> + if (flags & RERERE_SKIP_LOCKED)
> + advise(_("run \"git rerere\" before resolving "
> + "the conflict to record or replay "
> + "its resolution"));
> return -1;
> }
> }
Should this use `advise_if_enabled()`?
Patrick |
||
| `git rerere gc`. Value 0 means not to wait at all; -1 means | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Patrick Steinhardt wrote on the Git mailing list (how to reply to this email): On Mon, Sep 28, 2026 at 11:58:21AM +0000, Thomas Bachem via GitGitGadget wrote:
> diff --git a/Documentation/git-rerere.adoc b/Documentation/git-rerere.adoc
> index 4e6ab9a27c..da7a1d093e 100644
> --- a/Documentation/git-rerere.adoc
> +++ b/Documentation/git-rerere.adoc
> @@ -63,14 +63,17 @@ Print paths with conflicts that have not been autoresolved by rerere.
> This includes paths whose resolutions cannot be tracked by rerere,
> such as conflicting submodules.
>
> -'gc'::
> +'gc' [--auto]::
>
> Prune records of conflicted merges that
> 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. With `--auto`, which `git maintenance run
> +--auto` and `git gc --auto` pass, `gc` does nothing while another
> +process holds the rerere lock. Without it, `gc` waits for the lock
> +as long as `rerere.lockTimeout` allows and then fails.
It's a bit weird to have git-rerere(1) document who calls it. We may
want to document why specifically this is useful though.
> diff --git a/builtin/rerere.c b/builtin/rerere.c
> index a056cb791b..2a8871df41 100644
> --- a/builtin/rerere.c
> +++ b/builtin/rerere.c
> @@ -56,16 +57,21 @@ int cmd_rerere(int argc,
> struct repository *repo UNUSED)
> {
> struct string_list merge_rr = STRING_LIST_INIT_DUP;
> - int autoupdate = -1, flags = 0;
> + int autoupdate = -1, auto_flag = 0, flags = 0;
>
> struct option options[] = {
> OPT_SET_INT(0, "rerere-autoupdate", &autoupdate,
> N_("register clean resolutions in index"), 1),
> + OPT_BOOL(0, "auto", &auto_flag,
> + N_("skip gc while another process holds the lock")),
> OPT_END(),
> };
Thinking about this a bit... I know it was my suggestion, but I wonder
whether "auto" is misnamed. We don't let any heuristics kick in like we
typically do for other commands like `git pack-refs --auto`, we only
know to skip garbage collection if the lock is taken. So there is a bit
of a mismatch here.
How about we instead call this "--skip-locked"? We could even mark it as
a hidden option and not even document it, as it feels very specific to
how git-maintenance(1) wants to invoke it. If so, we could maybe remove
it again at a later point.
An alternative could be to instead call `rerere_gc()` directly, and if
so we wouldn't have to add this flag at all. But that may result in some
bigger changes, so I'll leave it up to you to decide.
> argc = parse_options(argc, argv, prefix, options, rerere_usage, 0);
>
> + if (auto_flag && (argc < 1 || strcmp(argv[0], "gc")))
> + die(_("the option '%s' requires '%s'"), "--auto", "gc");
> +
> repo_config(the_repository, git_xmerge_config, NULL);
>
> if (autoupdate == 1)
Oh dear, this is a mess. The file could really use a refactoring to use
proper subcommands.
But anyway, that's certainly outside the scope of this patch series.
PatrickThere was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thomas Bachem wrote on the Git mailing list (how to reply to this email): Hi Patrick,
On 30/09/2026 17:00, Patrick Steinhardt wrote:
> It's a bit weird to have git-rerere(1) document who calls it. We may
> want to document why specifically this is useful though.
I'll take that out of git-rerere(1) again. I'd keep the last sentence
of the rerere.lockTimeout entry, since that is where I say what each
command does when the time is up, but name the two commands there
instead of the option:
"A `git rerere gc` run by `git maintenance run --auto` or
`git gc --auto` does not wait and does nothing while the lock is held."
> How about we instead call this "--skip-locked"? We could even mark it as
> a hidden option and not even document it, as it feels very specific to
> how git-maintenance(1) wants to invoke it. If so, we could maybe remove
> it again at a later point.
I'll take both, the name and hiding it.
Patch 3 has a RERERE_SKIP_LOCKED flag for the conflict-time callers.
I'll rename that one to RERERE_WARN_LOCKED so it doesn't look like the
option's flag, which stays RERERE_NOWAIT.
> An alternative could be to instead call `rerere_gc()` directly, and if
> so we wouldn't have to add this flag at all. But that may result in some
> bigger changes, so I'll leave it up to you to decide.
I tried it. It is six lines in builtin/gc.c, but rerere_gc() dies when
it can't take the lock. A manual or scheduled "git maintenance run"
then dies with the lockfile's message and exit code 128, where it now
reports "task 'rerere-gc' failed" and exits with 1. The rerere-gc
tests in t7900 fail too, since their helper looks for the
"git rerere gc" child. So I'd keep the option for this series. Say if
you'd rather have the direct call.
I'll wait a day or two for other comments before I send v6.
Thanks,
ThomasThere was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Patrick Steinhardt wrote on the Git mailing list (how to reply to this email): On Thu, Oct 01, 2026 at 10:08:16AM +0200, Thomas Bachem wrote:
> Hi Patrick,
>
> On 30/09/2026 17:00, Patrick Steinhardt wrote:
> > It's a bit weird to have git-rerere(1) document who calls it. We may
> > want to document why specifically this is useful though.
>
> I'll take that out of git-rerere(1) again. I'd keep the last sentence
> of the rerere.lockTimeout entry, since that is where I say what each
> command does when the time is up, but name the two commands there
> instead of the option:
>
> "A `git rerere gc` run by `git maintenance run --auto` or
> `git gc --auto` does not wait and does nothing while the lock is held."
>
> > How about we instead call this "--skip-locked"? We could even mark it as
> > a hidden option and not even document it, as it feels very specific to
> > how git-maintenance(1) wants to invoke it. If so, we could maybe remove
> > it again at a later point.
>
> I'll take both, the name and hiding it.
>
> Patch 3 has a RERERE_SKIP_LOCKED flag for the conflict-time callers.
> I'll rename that one to RERERE_WARN_LOCKED so it doesn't look like the
> option's flag, which stays RERERE_NOWAIT.
>
> > An alternative could be to instead call `rerere_gc()` directly, and if
> > so we wouldn't have to add this flag at all. But that may result in some
> > bigger changes, so I'll leave it up to you to decide.
>
> I tried it. It is six lines in builtin/gc.c, but rerere_gc() dies when
> it can't take the lock. A manual or scheduled "git maintenance run"
> then dies with the lockfile's message and exit code 128, where it now
> reports "task 'rerere-gc' failed" and exits with 1. The rerere-gc
> tests in t7900 fail too, since their helper looks for the
> "git rerere gc" child. So I'd keep the option for this series. Say if
> you'd rather have the direct call.
Ah, right, that makes sense. Let's keep the hidden option in that case.
Thanks!
Patrick |
||
| to wait indefinitely. Default is 1000 (i.e., wait for 1 | ||
| second). When the time is up, a command that stops at a | ||
| conflict, such as `git merge` or `git rebase`, prints a | ||
| warning and goes on without rerere; run `git rerere` before | ||
| resolving the conflict to record it after all. Any other | ||
| command fails, as it does for any other lock it cannot take. | ||
| A `git rerere gc` run by `git maintenance run --auto` or | ||
| `git gc --auto` does not wait and does nothing while the lock | ||
| is held. | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Patrick Steinhardt wrote on the Git mailing list (how to reply to this email):