Subject: Re: [PATCH 2/2] replay: document --update-refs and --batch options

From: Siddharth Asthana <[email-masked]>
Date: Tue, 9 Sep 2025 12:06:32 +0530

On 08/09/25 11:30, Christian Couder wrote:
> On Mon, Sep 8, 2025 at 6:36 AM Siddharth Asthana
> <[email-masked]> wrote:
>> Add documentation for the new --update-refs option which performs
>> ref updates directly using Git's ref transaction API, eliminating
>> the need for users to pipe output to git update-ref --stdin.
Hi Christian,

Thanks for the detailed review.
> Most of the time, the documentation should be part of the patch that
> introduces the documented behavior, not in a separate patch.
You are right I will combine them in v2.
>
>> Also document the --batch option which can be used with --update-refs
>> to allow partial failures in ref updates.
> It looks like a --update option was also added by the previous patch.
> Is it documented here too?
>
> Why was this [--update | --update-refs [--batch]] set of options
> selected over other possibilities like for example
> [--update-iteratively | --update-atomically | --update-batch]?
I was trying to provide both simple and advanced modes. --update for 
users who just want "make it work like piping to git update-ref --stdin" 
and --update-refs for those who want control over transaction modes. But 
I see this creates confusion.

Would you prefer a single option like --update-refs with an optional 
mode parameter? Something like --update-refs[=batch] where default is 
atomic?
>
> Also how does this --update-refs option compare to the --update-refs
> option in git rebase? Is it working in the same way?
No, they are different. git rebase --update-refs updates refs that point 
to commits being rebased. --update-refs updates the target branches from 
the replay operation itself. The naming collision is unfortunate should 
I use a different name?
>
>> Signed-off-by: Siddharth Asthana <[email-masked]>
>> ---
>>   Documentation/git-replay.adoc | 62 +++++++++++++++++++++++++++++++----
>>   1 file changed, 56 insertions(+), 6 deletions(-)
>>
>> diff --git a/Documentation/git-replay.adoc b/Documentation/git-replay.adoc
>> index 0b12bf8aa4..cc9f868c2f 100644
>> --- a/Documentation/git-replay.adoc
>> +++ b/Documentation/git-replay.adoc
>> @@ -9,16 +9,17 @@ git-replay - EXPERIMENTAL: Replay commits on a new base, works with bare repos t
>>   SYNOPSIS
>>   --------
>>   [verse]
>> -(EXPERIMENTAL!) 'git replay' ([--contained] --onto <newbase> | --advance <branch>) <revision-range>...
>> +(EXPERIMENTAL!) 'git replay' ([--contained] --onto <newbase> | --advance <branch>) [--update | --update-refs [--batch]] <revision-range>...
> Here --update, --update-refs and --batch are all documented, nice.
>
>>   DESCRIPTION
>>   -----------
>>
>>   Takes ranges of commits and replays them onto a new location. Leaves
>> -the working tree and the index untouched, and updates no references.
>> -The output of this command is meant to be used as input to
>> +the working tree and the index untouched, and by default updates no
>> +references. The output of this command is meant to be used as input to
>>   `git update-ref --stdin`, which would update the relevant branches
>> -(see the OUTPUT section below).
>> +(see the OUTPUT section below). Alternatively, with `--update`, the
>> +refs can be updated directly.
> Here only --update is documented.
>
>>   THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
>>
>> @@ -42,6 +43,24 @@ When `--advance` is specified, the update-ref command(s) in the output
>>   will update the branch passed as an argument to `--advance` to point at
>>   the new commits (in other words, this mimics a cherry-pick operation).
>>
>> +--update::
>> +       Update the relevant refs directly instead of outputting
>> +       update-ref commands. When this option is used, no output is
>> +       produced on successful completion,
> It seems a bit redundant to say both "instead of outputting update-ref
> commands" and then "no output is produced on successful completion".
> Maybe there is a way to reword this to be a bit more concise.
You are right that's redundant. I will reword it.
>
>> and the refs are updated
>> +       immediately. If any ref update fails, the command will exit
>> +       with a non-zero status.
> This doesn't say if the command immediately stops when it fails to
> update a ref, and if the ref updates are atomic or not.
You are right the docs need to be clearer about the behavior 
differences. I will clarify that --update stops immediately on failure 
(like git update-ref --stdin), while --update-refs defaults to atomic mode.
>
>> +--update-refs::
>> +       Update the relevant refs using ref transactions instead of outputting
>> +       update-ref commands. By default, uses atomic mode where all ref updates
>> +       succeed or all fail.
> This seems to imply that --update doesn't update the refs atomically.
That correct --update doesn't use transactions it updates refs one by 
one like `git update-ref --stdin` does. Should I make this clearer in 
the documentation?
>
>> Use with `--batch` to allow partial updates.
> What about --update, when should it be used?
Good point. My thinking was --update for simple cases where you want the 
exact same behavior as piping to `git update-ref --stdin` and 
--update-refs when you want transaction guarantees. But I am starting to 
think this distinction might be confusing users more than helping them.

Would it be cleaner to just have --update-refs with the batch mode 
option and drop --update entirely? The sequential behavior can be 
achieved with --update-refs --batch if someone really needs it.
>
>> +       When this option is used, no output is produced on successful completion.
> Here also it seems a bit redundant to say both "instead of outputting
> update-ref commands" and then "no output is produced on successful
> completion". And maybe there is a way to reword this to be a bit more
> concise.
Yes same redundancy issue. I will fix the wording throughout in v2.
>
>> +--batch::
>> +       Can only be used with `--update-refs`. Enables batch mode for ref
>> +       updates, allowing some refs to be updated successfully even if others
>> +       fail. Failed updates are reported as warnings rather than errors.
> What's the difference with --update? Is it that --update immediately
> stops when a ref update fails?
Yes exactly. --update mimics the behavior of piping to `git update-ref 
--stdin` and it stops immediately on the first failure and doesn't 
update any remaining refs.

--update-refs uses transactions, so in atomic mode all refs are updated 
together or none at all, and in batch mode it can continue processing 
remaining refs even after some fail.
>
>>   <revision-range>::
>>          Range of commits to replay. More than one <revision-range> can
>>          be passed, but in `--advance <branch>` mode, they should have
>> @@ -54,8 +73,9 @@ include::rev-list-options.adoc[]
>>   OUTPUT
>>   ------
>>
>> -When there are no conflicts, the output of this command is usable as
>> -input to `git update-ref --stdin`.  It is of the form:
>> +When there are no conflicts and neither `--update` nor `--update-refs`
>> +is used, the output of this command is usable as input to `git update-ref --stdin`.
>> +It is of the form:
>>
>>          update refs/heads/branch1 ${NEW_branch1_HASH} ${OLD_branch1_HASH}
>>          update refs/heads/branch2 ${NEW_branch2_HASH} ${OLD_branch2_HASH}
>> @@ -66,6 +86,15 @@ the shape of the history being replayed.  When using `--advance`, the
>>   number of refs updated is always one, but for `--onto`, it can be one
>>   or more (rebasing multiple branches simultaneously is supported).
>>
>> +When `--update` is used, no output is produced and the refs are updated
>> +directly using individual ref updates. This is equivalent to piping the normal output to
>> +`git update-ref --stdin`.
> Is it equivalent to `git update-ref --stdin` because both exit as soon
> as a ref update fails?
Yes that is the intention. Both --update and `git update-ref --stdin` 
process refs sequentially and exit on first failure leaving the 
repository in a partially updated state if failure occurs partway through.

The difference is --update does this internally without needing the pipe 
while --update-refs uses proper transactions for better atomicity 
guarantees.
>> +When `--update-refs` is used, no output is produced and the refs are updated
>> +using ref transactions. In atomic mode (default), all ref updates succeed
>> +or all fail. In batch mode (with `--batch`), some updates may succeed while
>> +others fail, with failed updates reported as warnings.