Skip to content

doc: git-rebase: clarify DESCRIPTION section #1949

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

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

jvns
Copy link

@jvns jvns commented Aug 7, 2025

  • Rephrase "duplicates of commits" to clarify that in step 2, rebase is using git patch-id (or the equivalent) to compare commits instead of using the SHA.
  • wrap some text correctly
  • s/git checkout -C/git checkout -B/

cc: "D. Ben Knoble" [email protected]
cc: Phillip Wood [email protected]
cc: Patrick Steinhardt [email protected]
cc: Karthik Nayak [email protected]

Copy link

gitgitgadget bot commented Aug 7, 2025

Welcome to GitGitGadget

Hi @jvns, and welcome to GitGitGadget, the GitHub App to send patch series to the Git mailing list from GitHub Pull Requests.

Please make sure that either:

  • Your Pull Request has a good description, if it consists of multiple commits, as it will be used as cover letter.
  • Your Pull Request description is empty, if it consists of a single commit, as the commit message should be descriptive enough by itself.

You can CC potential reviewers by adding a footer to the PR description with the following syntax:

CC: Revi Ewer <[email protected]>, Ill Takalook <[email protected]>

NOTE: DO NOT copy/paste your CC list from a previous GGG PR's description,
because it will result in a malformed CC list on the mailing list. See
example.

Also, it is a good idea to review the commit messages one last time, as the Git project expects them in a quite specific form:

  • the lines should not exceed 76 columns,
  • the first line should be like a header and typically start with a prefix like "tests:" or "revisions:" to state which subsystem the change is about, and
  • the commit messages' body should be describing the "why?" of the change.
  • Finally, the commit messages should end in a Signed-off-by: line matching the commits' author.

It is in general a good idea to await the automated test ("Checks") in this Pull Request before contributing the patches, e.g. to avoid trivial issues such as unportable code.

Contributing the patches

Before you can contribute the patches, your GitHub username needs to be added to the list of permitted users. Any already-permitted user can do that, by adding a comment to your PR of the form /allow. A good way to find other contributors is to locate recent pull requests where someone has been /allowed:

Both the person who commented /allow and the PR author are able to /allow you.

An alternative is the channel #git-devel on the Libera Chat IRC network:

<newcontributor> I've just created my first PR, could someone please /allow me? https://github.com/gitgitgadget/git/pull/12345
<veteran> newcontributor: it is done
<newcontributor> thanks!

Once on the list of permitted usernames, you can contribute the patches to the Git mailing list by adding a PR comment /submit.

If you want to see what email(s) would be sent for a /submit request, add a PR comment /preview to have the email(s) sent to you. You must have a public GitHub email address for this. Note that any reviewers CC'd via the list in the PR description will not actually be sent emails.

After you submit, GitGitGadget will respond with another comment that contains the link to the cover letter mail in the Git mailing list archive. Please make sure to monitor the discussion in that thread and to address comments and suggestions (while the comments and suggestions will be mirrored into the PR by GitGitGadget, you will still want to reply via mail).

If you do not want to subscribe to the Git mailing list just to be able to respond to a mail, you can download the mbox from the Git mailing list archive (click the (raw) link), then import it into your mail program. If you use GMail, you can do this via:

curl -g --user "<EMailAddress>:<Password>" \
    --url "imaps://imap.gmail.com/INBOX" -T /path/to/raw.txt

To iterate on your change, i.e. send a revised patch or patch series, you will first want to (force-)push to the same branch. You probably also want to modify your Pull Request description (or title). It is a good idea to summarize the revision by adding something like this to the cover letter (read: by editing the first comment on the PR, i.e. the PR description):

Changes since v1:
- Fixed a typo in the commit message (found by ...)
- Added a code comment to ... as suggested by ...
...

To send a new iteration, just add another PR comment with the contents: /submit.

Need help?

New contributors who want advice are encouraged to join [email protected], where volunteers who regularly contribute to Git are willing to answer newbie questions, give advice, or otherwise provide mentoring to interested contributors. You must join in order to post or view messages, but anyone can join.

You may also be able to find help in real time in the developer IRC channel, #git-devel on Libera Chat. Remember that IRC does not support offline messaging, so if you send someone a private message and log out, they cannot respond to you. The scrollback of #git-devel is archived, though.

@gitgitgadget gitgitgadget bot added the new user label Aug 7, 2025
Copy link

gitgitgadget bot commented Aug 7, 2025

There are issues in commit 1992c76:
doc: git-rebase: start with an example
Commit not signed off

Copy link

gitgitgadget bot commented Aug 7, 2025

There are issues in commit 02ae00f:
doc: git rebase: dedup merge conflict discussion
Commit not signed off

Copy link

gitgitgadget bot commented Aug 7, 2025

There are issues in commit 136f0d2:
doc: git rebase: clarify arguments syntax
Commit not signed off

Copy link

gitgitgadget bot commented Aug 7, 2025

There are issues in commit 0b3f224:
doc: git-rebase: move --onto explanation down
Commit not signed off

Copy link

gitgitgadget bot commented Aug 7, 2025

There are issues in commit 82b3419:
doc: git-rebase: update discussion of internals
Commit not signed off

@benknoble
Copy link

/allow

Copy link

gitgitgadget bot commented Aug 7, 2025

User jvns is now allowed to use GitGitGadget.

@jvns
Copy link
Author

jvns commented Aug 8, 2025

/preview

Copy link

gitgitgadget bot commented Aug 8, 2025

Preview email sent as [email protected]

@jvns
Copy link
Author

jvns commented Aug 8, 2025

/submit

Copy link

gitgitgadget bot commented Aug 8, 2025

Submitted as [email protected]

To fetch this version into FETCH_HEAD:

git fetch https://github.com/gitgitgadget/git/ pr-1949/jvns/clarify-rebase-v1

To fetch this version to local tag pr-1949/jvns/clarify-rebase-v1:

git fetch --no-tags https://github.com/gitgitgadget/git/ tag pr-1949/jvns/clarify-rebase-v1

@@ -16,6 +16,26 @@ SYNOPSIS

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Junio C Hamano wrote (reply to this):

"Julia Evans via GitGitGadget" <[email protected]> writes:

> From: Julia Evans <[email protected]>
>
> Start with an example that mirrors the example in the `git-merge` man
> page, to make it easier for folks to understand the difference between a
> rebase and a merge.
>
> Signed-off-by: Julia Evans <[email protected]>
> ---
>  Documentation/git-rebase.adoc | 46 +++++++++++++++--------------------
>  1 file changed, 20 insertions(+), 26 deletions(-)
>
> diff --git a/Documentation/git-rebase.adoc b/Documentation/git-rebase.adoc
> index 956d3048f5a6..fee73623990d 100644
> --- a/Documentation/git-rebase.adoc
> +++ b/Documentation/git-rebase.adoc
> @@ -16,6 +16,26 @@ SYNOPSIS
>  
>  DESCRIPTION
>  -----------
> +Transplant a series of commits onto a different starting point.

It is an excellent idea to start with what it does, before
explaining how you would drive it.

> +For example, assume the following history exists and the current branch is `topic`:

The line is a bit overly long, and the style a bit on the
"description of dry facts" side, which might want to give
a bit more "motivation" to help readers.

Here is my attempt.

    Imagine that you have been working on the `topic` branch in this
    history, and you'd want to "catch up" to the work done on the
    `master` branch.

      *** Illustration of "before" state ***

    You want to transplant the commits you made on `topic` since it
    diverged from `master` (i.e. A, B, and C), on top of the current
    `master`.  You can do so by running `git rebase master` while the
    `topic` branch is checked out.  `git rebase master topic` works
    as a short-cut to `git checkout topic && git rebase master`.

      *** Illustration of "after" state ***

perhaps?  

Note that you lost the mention of `git rebase master topic` syntax
and the explanation that the form being a shorthand for checkout
followed by rebase, which I do not think appear anywhere else in the
document, so my suggested rewrite above resurrects it.

> +------------
> +          A---B---C topic
> +         /
> +    D---E---F---G master
> +------------
> +
> +Then `git rebase master` will find all of the commits since `topic` diverged
> +from `master` and copy the changes in each of those commits on top of the
> +`master` branch.
> +
> +------------
> +                  A'--B'--C' topic
> +                 /
> +    D---E---F---G master
> +------------
> +
>  If `<branch>` is specified, `git rebase` will perform an automatic
>  `git switch <branch>` before doing anything else.  Otherwise
>  it remains on the current branch.
> @@ -58,32 +78,6 @@ that caused the merge failure with `git rebase --skip`.  To check out the
>  original `<branch>` and remove the `.git/rebase-apply` working files, use
>  the command `git rebase --abort` instead.
>  
> -Assume the following history exists and the current branch is "topic":
> -
> -------------
> -          A---B---C topic
> -         /
> -    D---E---F---G master
> -------------
> -
> -From this point, the result of either of the following commands:
> -
> -
> -    git rebase master
> -    git rebase master topic
> -
> -would be:
> -
> -------------
> -                  A'--B'--C' topic
> -                 /
> -    D---E---F---G master
> -------------
> -
> -*NOTE:* The latter form is just a short-hand of `git checkout topic`
> -followed by `git rebase master`. When rebase exits `topic` will
> -remain the checked-out branch.
> -
>  If the upstream branch already contains a change you have made (e.g.,
>  because you mailed a patch which was applied upstream), then that commit
>  will be skipped and warnings will be issued (if the 'merge' backend is

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, "Julia Evans" wrote (reply to this):

On Fri, Aug 8, 2025, at 12:30 PM, Junio C Hamano wrote:
> "Julia Evans via GitGitGadget" <[email protected]> writes:
>
>> From: Julia Evans <[email protected]>
>>
>> Start with an example that mirrors the example in the `git-merge` man
>> page, to make it easier for folks to understand the difference between a
>> rebase and a merge.
>>
>> Signed-off-by: Julia Evans <[email protected]>
>> ---
>>  Documentation/git-rebase.adoc | 46 +++++++++++++++--------------------
>>  1 file changed, 20 insertions(+), 26 deletions(-)
>>
>> diff --git a/Documentation/git-rebase.adoc b/Documentation/git-rebase.adoc
>> index 956d3048f5a6..fee73623990d 100644
>> --- a/Documentation/git-rebase.adoc
>> +++ b/Documentation/git-rebase.adoc
>> @@ -16,6 +16,26 @@ SYNOPSIS
>>  
>>  DESCRIPTION
>>  -----------
>> +Transplant a series of commits onto a different starting point.
>
> It is an excellent idea to start with what it does, before
> explaining how you would drive it.
>
>> +For example, assume the following history exists and the current branch is `topic`:
>
> The line is a bit overly long, and the style a bit on the
> "description of dry facts" side, which might want to give
> a bit more "motivation" to help readers.

I'm very happy to hear that feedback: I thought it was very dry as well, but I copied that part from elsewhere in the man page because I thought that was git's preferred documentation style. I'll work on making it less dry.

> Note that you lost the mention of `git rebase master topic` syntax
> and the explanation that the form being a shorthand for checkout
> followed by rebase, which I do not think appear anywhere else in the
> document, so my suggested rewrite above resurrects it.

That's actually in PATCH 3/5 of this series: I also thought the explanation that the form being a shorthand for checkout followed by rebase was extremely clear so I moved it to be the primary explanation of what `git rebase <upstream> <branch>` does.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Junio C Hamano wrote (reply to this):

"Julia Evans" <[email protected]> writes:

> I'm very happy to hear that feedback: I thought it was very dry as
> well, but I copied that part from elsewhere in the man page
> because I thought that was git's preferred documentation
> style. I'll work on making it less dry.

[administrivia: please wrap your overlong lines; we write for this
hypothetiical reader on an 80-column terminal].

>> Note that you lost the mention of `git rebase master topic` syntax
>> and the explanation that the form being a shorthand for checkout
>> followed by rebase, which I do not think appear anywhere else in the
>> document, so my suggested rewrite above resurrects it.
>
> That's actually in PATCH 3/5 of this series:...

Which I think is too late; both are quite commonly used and useful,
so showing them upfront when the command line examples are first
introduced would be more preferrable.

Thanks.

------------
A'--B'--C' topic
/
D---E---F---G master
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Junio C Hamano wrote (reply to this):

"Julia Evans via GitGitGadget" <[email protected]> writes:

> +If there is a merge conflict during this process, `git rebase` will stop at the
> +first problematic commit and leave conflict markers. If this happens, you can:

By using the numbered enumeration below, we may mislead the readers
that these are the things they have to do in this order, when we
actually are giving them choices.

	If this happens, you can do one of these things:

would be an easy workaround.

> +1. Resolve the conflict. You can use `git diff` to find the markers (<<<<<<)
> +   and make edits to resolve the conflict. For each file you edit, you need to
> +   tell Git that the conflict has been resolved. Typically this would be
> +   done with
> +
> +   git add <filename>
> +
> +   You can then continue the rebasing process with
> +
> +   git rebase --continue

The original (below) does not do a perfect job, but I am afraid that
this increases the chance of misunderstanding by new readers that
they'd run "continue" after marking each confclited fines as "done"
with "git add", by reducing a sentence to a mere "then" in "You can
then continue".

	Typically after resolving all the conflicts in a single
	file, you would tell Git that you are done with this file:

	git add <filename>

	And after dealing with all the conflicted files and telling
	Git that you are done, you would continue the rebasing
	process with

	git rebase --continue

or something?

> +2. Stop the `git rebase` and return your branch to its original state with
> +
> +   git rebase --abort
> +
> +3. Skip the commit that caused the merge conflict with
> +
> +   git rebase --skip

The explanation in the above looks good, and the new organization is
much easier to follow and is definite improvement compared to the
original.

I am not sure how the above how the above formats, though,
especially on a medium that is not monospaced text (e.g., html
rendition, not "git help -m rebase" on terminals).  The prose should
typeset just like the normal text (i.e. your "Transplant a series of
commits" in the previous step that starts the description section),
but the command that the users would type should be typeset in
monospace typewriter.  Have you tried?

Thanks.

@jvns jvns force-pushed the clarify-rebase branch 6 times, most recently from 96fc817 to ad97cd9 Compare August 8, 2025 18:54
@jvns
Copy link
Author

jvns commented Aug 8, 2025

/submit

Copy link

gitgitgadget bot commented Aug 8, 2025

Submitted as [email protected]

To fetch this version into FETCH_HEAD:

git fetch https://github.com/gitgitgadget/git/ pr-1949/jvns/clarify-rebase-v2

To fetch this version to local tag pr-1949/jvns/clarify-rebase-v2:

git fetch --no-tags https://github.com/gitgitgadget/git/ tag pr-1949/jvns/clarify-rebase-v2

git rebase --abort
3. Skip the commit that caused the merge conflict with
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Junio C Hamano wrote (reply to this):

"Julia Evans via GitGitGadget" <[email protected]> writes:

> From: Julia Evans <[email protected]>
>
> This removes the explanation of `git rebase <upstream> <branch>`, since
> it was already explained above that it's shorthand for `git switch
> <branch> && git rebase <upstream>`

We usually do not say "This [commit] does X".  In this particular
case, since the objective is so obvious, we do not necessarily have
to follow the whole "summarize the current state, explain why it is
problematic, and then tell somebody sitting in front of a keyboard
to change the code in this and that way to make it improve" 9 yards;
just tweaking it into

	Remove the redundant explanation of `git ...`, since it was
	already explained earlier.

would be sufficient.

Although the proposed log message does not mention it, I actually
like the other change in this patch, that rephrases the "if you
don't specify...", even better.  The addtional "to rebase onto" does
make the description clearer.

Thanks.

> Signed-off-by: Julia Evans <[email protected]>
> ---
>  Documentation/git-rebase.adoc | 7 +------
>  1 file changed, 1 insertion(+), 6 deletions(-)
>
> diff --git a/Documentation/git-rebase.adoc b/Documentation/git-rebase.adoc
> index a93c616f38b1..e700b92e35ac 100644
> --- a/Documentation/git-rebase.adoc
> +++ b/Documentation/git-rebase.adoc
> @@ -59,12 +59,7 @@ one of these things:
>  
>     git rebase --skip
>  
> -
> -If `<branch>` is specified, `git rebase` will perform an automatic
> -`git switch <branch>` before doing anything else.  Otherwise
> -it remains on the current branch.
> -
> -If `<upstream>` is not specified, the upstream configured in
> +If you don't specify an `<upstream>` to rebase onto, the upstream configured in
>  `branch.<name>.remote` and `branch.<name>.merge` options will be used (see
>  linkgit:git-config[1] for details) and the `--fork-point` option is
>  assumed.  If you are currently not on any branch or if the current

git rebase --skip
If you don't specify an `<upstream>` to rebase onto, the upstream configured in
`branch.<name>.remote` and `branch.<name>.merge` options will be used (see
linkgit:git-config[1] for details) and the `--fork-point` option is
assumed. If you are currently not on any branch or if the current
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Junio C Hamano wrote (reply to this):

"Julia Evans via GitGitGadget" <[email protected]> writes:

> From: Julia Evans <[email protected]>
>
> - make it clearer that we're talking about three steps of a process

A good call.  "First, then, then" does make it clear where each new
step begins.  "First, then, finally" would make it even more obvious
which step concludes the sequence, though.

> - delete a duplicate explanation of how git rebase skips commits with
>   the same textual changes (it's explained in more detail a few lines
>   further down)

OK.

> - move the `ORIG_HEAD` note down so that it doesn't interrupt the
>   discussion of the mechanics.

I thought you moved the "finally we reapply" up, instead of moving
the note down ;-) And when viewed that way, a more direct way to
justify this change is that you made sure these three steps are kept
together.

Again, good change.

> -All changes made by commits in the current branch but that are not
> +Here is a more detailed description of what `git rebase <upstream>` does:
> +
> +First, all changes made by commits in the current branch but that are not
>  in `<upstream>` are saved to a temporary area.  This is the same set
>  of commits that would be shown by `git log <upstream>..HEAD`; or by
>  `git log 'fork_point'..HEAD`, if `--fork-point` is active (see the
>  description on `--fork-point` below); or by `git log HEAD`, if the
>  `--root` option is specified.

If we are ambitious, we may want to rewrite this first step to put
almost no stress on "saving" and "temporary area".  Especially when
you rebase with merge backend, it would be morally a sequence of
cherry-pick, without us having to save anything---we only need to
figure out which commits to replay in what order.

    First, the command figures out changes from which commits to
    replay in what order.  The set of commits are those shown by
    `git log <base>..HEAD`, where <base> is the <upstream> if given,
    or computed fork-point if the `--fork-point` option is active,
    or all commits that lead to `HEAD` if `--root` is given.


> -The current branch is reset to `<upstream>` or `<newbase>` if the
> +Then the current branch is reset to `<upstream>` or `<newbase>` if the
>  `--onto` option was supplied.  This has the exact same effect as
>  `git reset --hard <upstream>` (or `<newbase>`). `ORIG_HEAD` is set
>  to point at the tip of the branch before the reset.

"This has the exact same effect as" made my reading hiccup.

    Then `git reset --hard` rewinds the current branch to the commit
    given by `--onto`, if specified, or to `<upstream>`.

I am not sure if it is worth talking about ORIG_HEAD at this point,
as that is part of what `git reset --hard` does with this step.
Given especially that we have NOTE that says ORIG_HEAD cannot be
relied upon once the replaying of commits begin, mentioning the
value of ORIG_HEAD before the replaying begins does not seem to add
much value to the explanation.

> +Then the commits that were previously saved into the temporary area are
> +reapplied to the current branch, one by one, in order.

Yup.  As I suggested, "Then" -> "Finally".

I do not know how much detail we want to give to readers, and I do
to prefer to tell some white lie in end-user facing documentation if
simplified description helps the initial understanding, so I am not
yet decided if I recommend rewriting these "three step" explanation,
but FYI, the modern rebase machinery works slightly differently:

    First the command figures out what to replay, on which commit,
    and in what order.

    Then the HEAD is detached ("git checkout --detach <onto>") to
    the commit the first change is replayed onto.

    Then the changes are replayed, one by one, in the order.
    Optionally a mergy history can be rebased while retaining
    the topology.

    Finally, the branch being rebased is made to point at the
    resulting HEAD (i.e. equivalent to "git checkout -B <branch>"
    to jump back from the detached HEAD state).

The difference between the simplified procedure and this "replaying
is done while on detached HEAD" procedure gives us a somewhat big
usability improvement, as a rebasing will be recorded in a single
reflog event for the branch getting rebased, no matter how many
commits are on the branch.

Copy link

gitgitgadget bot commented Aug 8, 2025

This patch series was integrated into seen via git@318d132.

@gitgitgadget gitgitgadget bot added the seen label Aug 8, 2025
@@ -16,6 +16,29 @@ SYNOPSIS

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Phillip Wood wrote (reply to this):

Hi Julia

On 09/08/2025 02:14, Julia Evans via GitGitGadget wrote:
> From: Julia Evans <[email protected]>
> > Start with an example that mirrors the example in the `git-merge` man
> page, to make it easier for folks to understand the difference between a
> rebase and a merge.

This is a very welcome improvement which makes it clear what rebasing a branch does. There are other important uses of rebase such as rearranging commits and squashing fixup commits that it would be nice to mention early on in the man page as well. Those do not necessarily change the base of the branch. I wonder if we could add a sentence about that which links to the INTERACTIVE MODE section.

Thanks

Phillip

> Signed-off-by: Julia Evans <[email protected]>
> ---
>   Documentation/git-rebase.adoc | 49 ++++++++++++++++-------------------
>   1 file changed, 23 insertions(+), 26 deletions(-)
> > diff --git a/Documentation/git-rebase.adoc b/Documentation/git-rebase.adoc
> index 956d3048f5a6..449f01fba560 100644
> --- a/Documentation/git-rebase.adoc
> +++ b/Documentation/git-rebase.adoc
> @@ -16,6 +16,29 @@ SYNOPSIS
>   >   DESCRIPTION
>   -----------
> +Transplant a series of commits onto a different starting point.
> +
> +For example, imagine that you have been working on the `topic` branch in this
> +history, and you want to "catch up" to the work done on the `master` branch.
> +
> +------------
> +          A---B---C topic
> +         /
> +    D---E---F---G master
> +------------
> +
> +You want to transplant the commits you made on `topic` since it diverged from
> +`master` (i.e. A, B, and C), on top of the current `master`.  You can do this
> +by running `git rebase master` while the `topic` branch is checked out.  If you
> +want to rebase `topic` while on another branch, `git rebase master topic` is a
> +shortcut for `git checkout topic && git rebase master`.
> +
> +------------
> +                  A'--B'--C' topic
> +                 /
> +    D---E---F---G master
> +------------
> +
>   If `<branch>` is specified, `git rebase` will perform an automatic
>   `git switch <branch>` before doing anything else.  Otherwise
>   it remains on the current branch.
> @@ -58,32 +81,6 @@ that caused the merge failure with `git rebase --skip`.  To check out the
>   original `<branch>` and remove the `.git/rebase-apply` working files, use
>   the command `git rebase --abort` instead.
>   > -Assume the following history exists and the current branch is "topic":
> -
> -------------
> -          A---B---C topic
> -         /
> -    D---E---F---G master
> -------------
> -
> -From this point, the result of either of the following commands:
> -
> -
> -    git rebase master
> -    git rebase master topic
> -
> -would be:
> -
> -------------
> -                  A'--B'--C' topic
> -                 /
> -    D---E---F---G master
> -------------
> -
> -*NOTE:* The latter form is just a short-hand of `git checkout topic`
> -followed by `git rebase master`. When rebase exits `topic` will
> -remain the checked-out branch.
> -
>   If the upstream branch already contains a change you have made (e.g.,
>   because you mailed a patch which was applied upstream), then that commit
>   will be skipped and warnings will be issued (if the 'merge' backend is

Copy link

gitgitgadget bot commented Aug 10, 2025

User Phillip Wood <[email protected]> has been added to the cc: list.

If you don't specify an `<upstream>` to rebase onto, the upstream configured in
`branch.<name>.remote` and `branch.<name>.merge` options will be used (see
linkgit:git-config[1] for details) and the `--fork-point` option is
assumed. If you are currently not on any branch or if the current
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Phillip Wood wrote (reply to this):

Hi Julia

On 09/08/2025 02:14, Julia Evans via GitGitGadget wrote:
> From: Julia Evans <[email protected]>
> > +Here is a more detailed description of what `git rebase <upstream>` does:
> +
> +First, it makes a list of all commits in the current branch that are not in
> +`<upstream>`. This is the same set of commits that would be shown by `git log
> +<upstream>..HEAD`.

The existing text is not quite accurate here, it should really say `git log --cherry-pick --right-only <upstream>...HEAD` as we drop any commits from the branch that have already been cherry-picked to <upstream>.

> You can use `--fork-point` or `--root` to change how this
> +list of commits is constructed.

`--reapply-cherry-picks` also changes how the list is constructed so I think it would be worth adding that option here as well.

Thanks for working on this, it makes the description section much more readable.

Phillip
> +
> +Then it checks out `<upstream>` (or `<newbase>` if the `--onto` option was
> +supplied) with the equivalent of `git switch --detach <upstream>`.
> +
> +Then it replays the commits, one by one, in order. This is similar to running
> +`git cherry-pick <commit>` for each commit. See REBASING MERGES for how merges
> +are handled.
> +
> +Finally, it updates your branch to point to the final commit with the equivalent
> +of `git switch -C <branch>`.
>   >   [NOTE]
> +`ORIG_HEAD` is set to point at the tip of the branch before the rebase.
>   `ORIG_HEAD` is not guaranteed to still point to the previous branch tip
>   at the end of the rebase if other commands that write that pseudo-ref
>   (e.g. `git reset`) are used during the rebase. The previous branch tip,
>   however, is accessible using the reflog of the current branch
>   (i.e. `@{1}`, see linkgit:gitrevisions[7]).
>   > -The commits that were previously saved into the temporary area are
> -then reapplied to the current branch, one by one, in order. Note that
> -any commits in `HEAD` which introduce the same textual changes as a commit
> -in `HEAD..<upstream>` are omitted (i.e., a patch already accepted upstream
> -with a different commit message or timestamp will be skipped).
> -
>   If the upstream branch already contains a change you have made (e.g.,
>   because you mailed a patch which was applied upstream), then that commit
>   will be skipped and warnings will be issued (if the 'merge' backend is

@@ -16,6 +16,29 @@ SYNOPSIS

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Patrick Steinhardt wrote (reply to this):

On Sat, Aug 09, 2025 at 01:14:13AM +0000, Julia Evans via GitGitGadget wrote:
> From: Julia Evans <[email protected]>
> 
> Start with an example that mirrors the example in the `git-merge` man
> page, to make it easier for folks to understand the difference between a
> rebase and a merge.

Makes sense.

> diff --git a/Documentation/git-rebase.adoc b/Documentation/git-rebase.adoc
> index 956d3048f5a6..449f01fba560 100644
> --- a/Documentation/git-rebase.adoc
> +++ b/Documentation/git-rebase.adoc
> @@ -16,6 +16,29 @@ SYNOPSIS
>  
>  DESCRIPTION
>  -----------
> +Transplant a series of commits onto a different starting point.

Nit: while this is one use case for git-rebase(1), I'd claim that
nowadays with interactive rebases there's the other use case where we
don't change the starting point but only edit the range of commits
itself.

So how about this instead:

    Edit a series of commits and optionally transplant it onto a
    different starting point.

We could also make the two different modes a bit more explicit by
pointing out both different use cases directly.

If you agree then we should probably also modernize the description in
the NAME section accordingly.

Patrick

Copy link

gitgitgadget bot commented Aug 11, 2025

User Patrick Steinhardt <[email protected]> has been added to the cc: list.

------------
A'--B'--C' topic
/
D---E---F---G master
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Patrick Steinhardt wrote (reply to this):

On Sat, Aug 09, 2025 at 01:14:14AM +0000, Julia Evans via GitGitGadget wrote:
> diff --git a/Documentation/git-rebase.adoc b/Documentation/git-rebase.adoc
> index 449f01fba560..e30b9535fff1 100644
> --- a/Documentation/git-rebase.adoc
> +++ b/Documentation/git-rebase.adoc
> @@ -39,6 +39,27 @@ shortcut for `git checkout topic && git rebase master`.
>      D---E---F---G master
>  ------------
>  
> +If there is a merge conflict during this process, `git rebase` will stop at the
> +first problematic commit and leave conflict markers. If this happens, you can do
> +one of these things:
> +
> +1. Resolve the conflict. You can use `git diff` to find the markers (<<<<<<)
> +   and make edits to resolve the conflict. For each file you edit, you need to
> +   tell Git that the conflict has been resolved. You can mark the conflict as
> +   resolved with  `git add <filename>`. After resolving all of the conflicts,
> +   you can continue the rebasing process with
> +
> +   git rebase --continue
> +
> +2. Stop the `git rebase` and return your branch to its original state with
> +
> +   git rebase --abort
> +
> +3. Skip the commit that caused the merge conflict with
> +
> +   git rebase --skip
> +
> +
>  If `<branch>` is specified, `git rebase` will perform an automatic
>  `git switch <branch>` before doing anything else.  Otherwise
>  it remains on the current branch.

Yup, this reads a lot nicer.

> @@ -74,13 +95,6 @@ any commits in `HEAD` which introduce the same textual changes as a commit
>  in `HEAD..<upstream>` are omitted (i.e., a patch already accepted upstream
>  with a different commit message or timestamp will be skipped).
>  
> -It is possible that a merge failure will prevent this process from being
> -completely automatic.  You will have to resolve any such merge failure
> -and run `git rebase --continue`.  Another option is to bypass the commit
> -that caused the merge failure with `git rebase --skip`.  To check out the
> -original `<branch>` and remove the `.git/rebase-apply` working files, use
> -the command `git rebase --abort` instead.
> -
>  If the upstream branch already contains a change you have made (e.g.,
>  because you mailed a patch which was applied upstream), then that commit
>  will be skipped and warnings will be issued (if the 'merge' backend is

We lose the bit about `.git/rebase-apply`, but I don't think that's a
bad thing. The user shouldn't have to care how exactly a rebase looks on
disk. All they should need to know is that `git rebase --abort` gets
them out of the state.

Patrick

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Phillip Wood wrote (reply to this):

On 11/08/2025 09:46, Patrick Steinhardt wrote:
> On Sat, Aug 09, 2025 at 01:14:14AM +0000, Julia Evans via GitGitGadget wrote:
>>   >> -It is possible that a merge failure will prevent this process from being
>> -completely automatic.  You will have to resolve any such merge failure
>> -and run `git rebase --continue`.  Another option is to bypass the commit
>> -that caused the merge failure with `git rebase --skip`.  To check out the
>> -original `<branch>` and remove the `.git/rebase-apply` working files, use
>> -the command `git rebase --abort` instead.
>> -
>>   If the upstream branch already contains a change you have made (e.g.,
>>   because you mailed a patch which was applied upstream), then that commit
>>   will be skipped and warnings will be issued (if the 'merge' backend is
> > We lose the bit about `.git/rebase-apply`, but I don't think that's a
> bad thing. The user shouldn't have to care how exactly a rebase looks on
> disk.

Exactly, we don't want to encourage the user to poke about in the state directory. Also ".git/rebase-apply" wont exist unless the user requested the apply backend so mentioning it is misleading (the default is ".git/rebase-merge" these days).

Thanks

Phillip

If you don't specify an `<upstream>` to rebase onto, the upstream configured in
`branch.<name>.remote` and `branch.<name>.merge` options will be used (see
linkgit:git-config[1] for details) and the `--fork-point` option is
assumed. If you are currently not on any branch or if the current
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Patrick Steinhardt wrote (reply to this):

On Sat, Aug 09, 2025 at 01:14:17AM +0000, Julia Evans via GitGitGadget wrote:
> diff --git a/Documentation/git-rebase.adoc b/Documentation/git-rebase.adoc
> index 50c84f138212..c16ee37b46a7 100644
> --- a/Documentation/git-rebase.adoc
> +++ b/Documentation/git-rebase.adoc
> @@ -65,31 +65,31 @@ linkgit:git-config[1] for details) and the `--fork-point` option is
>  assumed.  If you are currently not on any branch or if the current
>  branch does not have a configured upstream, the rebase will abort.
>  
> -All changes made by commits in the current branch but that are not
> -in `<upstream>` are saved to a temporary area.  This is the same set
> -of commits that would be shown by `git log <upstream>..HEAD`; or by
> -`git log 'fork_point'..HEAD`, if `--fork-point` is active (see the
> -description on `--fork-point` below); or by `git log HEAD`, if the
> -`--root` option is specified.
> -
> -The current branch is reset to `<upstream>` or `<newbase>` if the
> -`--onto` option was supplied.  This has the exact same effect as
> -`git reset --hard <upstream>` (or `<newbase>`). `ORIG_HEAD` is set
> -to point at the tip of the branch before the reset.
> +Here is a more detailed description of what `git rebase <upstream>` does:
> +
> +First, it makes a list of all commits in the current branch that are not in
> +`<upstream>`. This is the same set of commits that would be shown by `git log
> +<upstream>..HEAD`. You can use `--fork-point` or `--root` to change how this
> +list of commits is constructed.
> +
> +Then it checks out `<upstream>` (or `<newbase>` if the `--onto` option was
> +supplied) with the equivalent of `git switch --detach <upstream>`.
> +
> +Then it replays the commits, one by one, in order. This is similar to running
> +`git cherry-pick <commit>` for each commit. See REBASING MERGES for how merges
> +are handled.
> +
> +Finally, it updates your branch to point to the final commit with the equivalent
> +of `git switch -C <branch>`.

Would it make sense to convert this into a bulleted list to further
highlight this multi-step process?

>  [NOTE]
> +`ORIG_HEAD` is set to point at the tip of the branch before the rebase.
>  `ORIG_HEAD` is not guaranteed to still point to the previous branch tip
>  at the end of the rebase if other commands that write that pseudo-ref
>  (e.g. `git reset`) are used during the rebase. The previous branch tip,
>  however, is accessible using the reflog of the current branch
>  (i.e. `@{1}`, see linkgit:gitrevisions[7]).

This information feels somewhat contradictory. Should we maybe say
something like this:

    When starting the rebase, `ORIG_HEAD` is set to point to at the tip
    of the to-be-rebased branch. As `ORIG_HEAD` may be modified by
    various operations during the rebase, it is not guaranteed to still
    point to this branch at the end of the rebase. The previous branch
    tip, however, is accessible using the reflog of the current branch
    (i.e. `@{1}`, see linkgit:gitrevisions[7]).

Note that I'm also dropping the reference to "pseudo-ref". ORIG_HEAD is
not a pseudo-ref, as we have clarified in 6fd8037564
(Documentation/glossary: redefine pseudorefs as special refs,
2024-05-15).

Patrick

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Ben Knoble wrote (reply to this):

> Le 11 août 2025 à 04:46, Patrick Steinhardt <[email protected]> a écrit :
> 
> On Sat, Aug 09, 2025 at 01:14:17AM +0000, Julia Evans via GitGitGadget wrote:
>> diff --git a/Documentation/git-rebase.adoc b/Documentation/git-rebase.adoc
>> index 50c84f138212..c16ee37b46a7 100644
>> --- a/Documentation/git-rebase.adoc
>> +++ b/Documentation/git-rebase.adoc
>> @@ -65,31 +65,31 @@ linkgit:git-config[1] for details) and the `--fork-point` option is
>> assumed.  If you are currently not on any branch or if the current
>> branch does not have a configured upstream, the rebase will abort.
>> 
>> -All changes made by commits in the current branch but that are not
>> -in `<upstream>` are saved to a temporary area.  This is the same set
>> -of commits that would be shown by `git log <upstream>..HEAD`; or by
>> -`git log 'fork_point'..HEAD`, if `--fork-point` is active (see the
>> -description on `--fork-point` below); or by `git log HEAD`, if the
>> -`--root` option is specified.
>> -
>> -The current branch is reset to `<upstream>` or `<newbase>` if the
>> -`--onto` option was supplied.  This has the exact same effect as
>> -`git reset --hard <upstream>` (or `<newbase>`). `ORIG_HEAD` is set
>> -to point at the tip of the branch before the reset.
>> +Here is a more detailed description of what `git rebase <upstream>` does:
>> +
>> +First, it makes a list of all commits in the current branch that are not in
>> +`<upstream>`. This is the same set of commits that would be shown by `git log
>> +<upstream>..HEAD`. You can use `--fork-point` or `--root` to change how this
>> +list of commits is constructed.
>> +
>> +Then it checks out `<upstream>` (or `<newbase>` if the `--onto` option was
>> +supplied) with the equivalent of `git switch --detach <upstream>`.
>> +
>> +Then it replays the commits, one by one, in order. This is similar to running
>> +`git cherry-pick <commit>` for each commit. See REBASING MERGES for how merges
>> +are handled.
>> +
>> +Finally, it updates your branch to point to the final commit with the equivalent
>> +of `git switch -C <branch>`.
> 
> Would it make sense to convert this into a bulleted list to further
> highlight this multi-step process?

Nit: ordered list, perhaps? Unless we don’t use those in our manuals (away from documentation at the moment). 

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Patrick Steinhardt wrote (reply to this):

On Mon, Aug 11, 2025 at 08:29:42AM -0400, Ben Knoble wrote:
> 
> > Le 11 août 2025 à 04:46, Patrick Steinhardt <[email protected]> a écrit :
> > 
> > On Sat, Aug 09, 2025 at 01:14:17AM +0000, Julia Evans via GitGitGadget wrote:
> >> diff --git a/Documentation/git-rebase.adoc b/Documentation/git-rebase.adoc
> >> index 50c84f138212..c16ee37b46a7 100644
> >> --- a/Documentation/git-rebase.adoc
> >> +++ b/Documentation/git-rebase.adoc
> >> @@ -65,31 +65,31 @@ linkgit:git-config[1] for details) and the `--fork-point` option is
> >> assumed.  If you are currently not on any branch or if the current
> >> branch does not have a configured upstream, the rebase will abort.
> >> 
> >> -All changes made by commits in the current branch but that are not
> >> -in `<upstream>` are saved to a temporary area.  This is the same set
> >> -of commits that would be shown by `git log <upstream>..HEAD`; or by
> >> -`git log 'fork_point'..HEAD`, if `--fork-point` is active (see the
> >> -description on `--fork-point` below); or by `git log HEAD`, if the
> >> -`--root` option is specified.
> >> -
> >> -The current branch is reset to `<upstream>` or `<newbase>` if the
> >> -`--onto` option was supplied.  This has the exact same effect as
> >> -`git reset --hard <upstream>` (or `<newbase>`). `ORIG_HEAD` is set
> >> -to point at the tip of the branch before the reset.
> >> +Here is a more detailed description of what `git rebase <upstream>` does:
> >> +
> >> +First, it makes a list of all commits in the current branch that are not in
> >> +`<upstream>`. This is the same set of commits that would be shown by `git log
> >> +<upstream>..HEAD`. You can use `--fork-point` or `--root` to change how this
> >> +list of commits is constructed.
> >> +
> >> +Then it checks out `<upstream>` (or `<newbase>` if the `--onto` option was
> >> +supplied) with the equivalent of `git switch --detach <upstream>`.
> >> +
> >> +Then it replays the commits, one by one, in order. This is similar to running
> >> +`git cherry-pick <commit>` for each commit. See REBASING MERGES for how merges
> >> +are handled.
> >> +
> >> +Finally, it updates your branch to point to the final commit with the equivalent
> >> +of `git switch -C <branch>`.
> > 
> > Would it make sense to convert this into a bulleted list to further
> > highlight this multi-step process?
> 
> Nit: ordered list, perhaps? Unless we don’t use those in our manuals
> (away from documentation at the moment). 

Ah, I actually wanted to propose using an ordered list, not bulleted list.
Thanks for correcting me.

Patrick

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, "Julia Evans" wrote (reply to this):

> Would it make sense to convert this into a bulleted list to further
> highlight this multi-step process?

I like this idea. I think we can combine this with Phillip's point about
"--reapply-cherry-picks" to expand the list a little more and remove the
paragraph at the end about how duplicate commits are skipped. ("If the upstream
branch already contains a change you have made...") I think probably the diagram
can be removed too, I'm not sure how much value it's adding.

1. Make a list of all commits in the current branch that are not in
   `<upstream>`. This is the same set of commits that would be shown by `git log
   <upstream>..HEAD`. You can use `--fork-point` or `--root` to change how this
   list of commits is constructed.
2. Check whether any of those commits are duplicates of commits already
   in `<upstream>`, remove them from the list, and print out a warning about
   each removed commit. You can use `--reapply-cherry-picks` to include
   duplicate commits.
3. Check out `<upstream>` (or `<newbase>` if the `--onto` option was
   supplied) with the equivalent of `git checkout --detach <upstream>`.
4. Replay the commits, one by one, in order. This is similar to running
   `git cherry-pick <commit>` for each commit. See REBASING MERGES for how merges
   are handled.
5. Update your branch to point to the final commit with the equivalent
   of `git switch -C <branch>`.

I imagine actually #1 and #2 happen concurrently, but I split them up because
it felt unwieldy to explain them both the same point.

>
>>  [NOTE]
>> +`ORIG_HEAD` is set to point at the tip of the branch before the rebase.
>>  `ORIG_HEAD` is not guaranteed to still point to the previous branch tip
>>  at the end of the rebase if other commands that write that pseudo-ref
>>  (e.g. `git reset`) are used during the rebase. The previous branch tip,
>>  however, is accessible using the reflog of the current branch
>>  (i.e. `@{1}`, see linkgit:gitrevisions[7]).
>
> This information feels somewhat contradictory. Should we maybe say
> something like this:
>
>     When starting the rebase, `ORIG_HEAD` is set to point to at the tip
>     of the to-be-rebased branch. As `ORIG_HEAD` may be modified by
>     various operations during the rebase, it is not guaranteed to still
>     point to this branch at the end of the rebase. The previous branch
>     tip, however, is accessible using the reflog of the current branch
>     (i.e. `@{1}`, see linkgit:gitrevisions[7]).
>
> Note that I'm also dropping the reference to "pseudo-ref". ORIG_HEAD is
> not a pseudo-ref, as we have clarified in 6fd8037564
> (Documentation/glossary: redefine pseudorefs as special refs,
> 2024-05-15).

I like that! Also very happy to remove the word "pseudo-ref".

- Julia

@@ -16,6 +16,29 @@ SYNOPSIS

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Karthik Nayak wrote (reply to this):

"Julia Evans via GitGitGadget" <[email protected]> writes:

> From: Julia Evans <[email protected]>
>
> Start with an example that mirrors the example in the `git-merge` man
> page, to make it easier for folks to understand the difference between a
> rebase and a merge.
>

Happy to see these changes.

> Signed-off-by: Julia Evans <[email protected]>
> ---
>  Documentation/git-rebase.adoc | 49 ++++++++++++++++-------------------
>  1 file changed, 23 insertions(+), 26 deletions(-)
>
> diff --git a/Documentation/git-rebase.adoc b/Documentation/git-rebase.adoc
> index 956d3048f5a6..449f01fba560 100644
> --- a/Documentation/git-rebase.adoc
> +++ b/Documentation/git-rebase.adoc
> @@ -16,6 +16,29 @@ SYNOPSIS
>
>  DESCRIPTION
>  -----------
> +Transplant a series of commits onto a different starting point.
> +
> +For example, imagine that you have been working on the `topic` branch in this
> +history, and you want to "catch up" to the work done on the `master` branch.
> +
> +------------
> +          A---B---C topic
> +         /
> +    D---E---F---G master
> +------------
> +
> +You want to transplant the commits you made on `topic` since it diverged from
> +`master` (i.e. A, B, and C), on top of the current `master`.  You can do this
> +by running `git rebase master` while the `topic` branch is checked out.  If you
> +want to rebase `topic` while on another branch, `git rebase master topic` is a
> +shortcut for `git checkout topic && git rebase master`.
> +

Nit: now that `git-switch(1)` is no longer experimental, we should start
recommending it over `git-checkout(1)` as necessary. So perhaps, we
could s/checkout/switch here?

[snip]

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Ben Knoble wrote (reply to this):

> Le 11 août 2025 à 05:29, Karthik Nayak <[email protected]> a écrit :
> 
> "Julia Evans via GitGitGadget" <[email protected]> writes:
>> 
>> Signed-off-by: Julia Evans <[email protected]>
>> ---
>> Documentation/git-rebase.adoc | 49 ++++++++++++++++-------------------
>> 1 file changed, 23 insertions(+), 26 deletions(-)
>> 
>> diff --git a/Documentation/git-rebase.adoc b/Documentation/git-rebase.adoc
>> index 956d3048f5a6..449f01fba560 100644
>> --- a/Documentation/git-rebase.adoc
>> +++ b/Documentation/git-rebase.adoc
>> @@ -16,6 +16,29 @@ SYNOPSIS
>> 
>> DESCRIPTION
>> -----------
>> +Transplant a series of commits onto a different starting point.
>> +
>> +For example, imagine that you have been working on the `topic` branch in this
>> +history, and you want to "catch up" to the work done on the `master` branch.
>> +
>> +------------
>> +          A---B---C topic
>> +         /
>> +    D---E---F---G master
>> +------------
>> +
>> +You want to transplant the commits you made on `topic` since it diverged from
>> +`master` (i.e. A, B, and C), on top of the current `master`.  You can do this
>> +by running `git rebase master` while the `topic` branch is checked out.  If you
>> +want to rebase `topic` while on another branch, `git rebase master topic` is a
>> +shortcut for `git checkout topic && git rebase master`.
>> +
> 
> Nit: now that `git-switch(1)` is no longer experimental, we should start
> recommending it over `git-checkout(1)` as necessary. So perhaps, we
> could s/checkout/switch here?

Junio previously recommended checkout (a prior version used switch): I suspect because checkout will detach head without extra syntax (where switch will not)?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Phillip Wood wrote (reply to this):

On 11/08/2025 10:13, Karthik Nayak wrote:
> "Julia Evans via GitGitGadget" <[email protected]> writes:
>> +
>> +You want to transplant the commits you made on `topic` since it diverged from
>> +`master` (i.e. A, B, and C), on top of the current `master`.  You can do this
>> +by running `git rebase master` while the `topic` branch is checked out.  If you
>> +want to rebase `topic` while on another branch, `git rebase master topic` is a
>> +shortcut for `git checkout topic && git rebase master`.
>> +
> > Nit: now that `git-switch(1)` is no longer experimental, we should start
> recommending it over `git-checkout(1)` as necessary. So perhaps, we
> could s/checkout/switch here?

Junio has already expressed a preference for "checkout" here c.f. <[email protected]>. I think that is technically correct as "topic" can be a commitish and "git switch <object-id>" fails without "--detach". Also rebase does not do any of the extra checks that "git switch" does before switching branches (I'm not saying that is necessarily a good thing).

Thanks

Phillip

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Karthik Nayak wrote (reply to this):

Ben Knoble <[email protected]> writes:

>> Le 11 août 2025 à 05:29, Karthik Nayak <[email protected]> a écrit :
>>
>> "Julia Evans via GitGitGadget" <[email protected]> writes:
>>>
>>> Signed-off-by: Julia Evans <[email protected]>
>>> ---
>>> Documentation/git-rebase.adoc | 49 ++++++++++++++++-------------------
>>> 1 file changed, 23 insertions(+), 26 deletions(-)
>>>
>>> diff --git a/Documentation/git-rebase.adoc b/Documentation/git-rebase.adoc
>>> index 956d3048f5a6..449f01fba560 100644
>>> --- a/Documentation/git-rebase.adoc
>>> +++ b/Documentation/git-rebase.adoc
>>> @@ -16,6 +16,29 @@ SYNOPSIS
>>>
>>> DESCRIPTION
>>> -----------
>>> +Transplant a series of commits onto a different starting point.
>>> +
>>> +For example, imagine that you have been working on the `topic` branch in this
>>> +history, and you want to "catch up" to the work done on the `master` branch.
>>> +
>>> +------------
>>> +          A---B---C topic
>>> +         /
>>> +    D---E---F---G master
>>> +------------
>>> +
>>> +You want to transplant the commits you made on `topic` since it diverged from
>>> +`master` (i.e. A, B, and C), on top of the current `master`.  You can do this
>>> +by running `git rebase master` while the `topic` branch is checked out.  If you
>>> +want to rebase `topic` while on another branch, `git rebase master topic` is a
>>> +shortcut for `git checkout topic && git rebase master`.
>>> +
>>
>> Nit: now that `git-switch(1)` is no longer experimental, we should start
>> recommending it over `git-checkout(1)` as necessary. So perhaps, we
>> could s/checkout/switch here?
>
> Junio previously recommended checkout (a prior version used switch): I suspect because checkout will detach head without extra syntax (where switch will not)?

I totally missed that, that makes sense!

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Karthik Nayak wrote (reply to this):

Phillip Wood <[email protected]> writes:

> On 11/08/2025 10:13, Karthik Nayak wrote:
>> "Julia Evans via GitGitGadget" <[email protected]> writes:
>>> +
>>> +You want to transplant the commits you made on `topic` since it diverged from
>>> +`master` (i.e. A, B, and C), on top of the current `master`.  You can do this
>>> +by running `git rebase master` while the `topic` branch is checked out.  If you
>>> +want to rebase `topic` while on another branch, `git rebase master topic` is a
>>> +shortcut for `git checkout topic && git rebase master`.
>>> +
>>
>> Nit: now that `git-switch(1)` is no longer experimental, we should start
>> recommending it over `git-checkout(1)` as necessary. So perhaps, we
>> could s/checkout/switch here?
>
> Junio has already expressed a preference for "checkout" here c.f.
> <[email protected]>. I think that is technically correct as
> "topic" can be a commitish and "git switch <object-id>" fails without
> "--detach". Also rebase does not do any of the extra checks that "git
> switch" does before switching branches (I'm not saying that is
> necessarily a good thing).
>

I missed that, but since we do mention that `topic` is a branch, it
still makes sense to use 'git switch'. But either way this is okay.

> Thanks
>
> Phillip

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Junio C Hamano wrote (reply to this):

Karthik Nayak <[email protected]> writes:

>>> Nit: now that `git-switch(1)` is no longer experimental, we should start
>>> recommending it over `git-checkout(1)` as necessary. So perhaps, we
>>> could s/checkout/switch here?

Besides, the reason why it is no longer experimental is *not*
because it has proved to be so much better than "checkout" and the
users are encouraged to use it.

It is no longer experimental only because it and its set of options
are now engraved in users' mustle memory deep enough that we can no
longer change it without disrupting users.  We were hoping to
improve its end-user experience relative to "checkout", and allowed
it to deviate from the precendent that was set by "git checkout",
and that was the reason why "this is experimental. UI and behaviour
is subject to change" label was on it.

The experiment unfortunately was not a great success.  There were
only a few meaningful differences invented during the experiment.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, "D. Ben Knoble" wrote (reply to this):

On Tue, Aug 12, 2025 at 5:11 AM Karthik Nayak <[email protected]> wrote:
>
> Phillip Wood <[email protected]> writes:
>
> > On 11/08/2025 10:13, Karthik Nayak wrote:
> >> "Julia Evans via GitGitGadget" <[email protected]> writes:
> >>> +
> >>> +You want to transplant the commits you made on `topic` since it diverged from
> >>> +`master` (i.e. A, B, and C), on top of the current `master`.  You can do this
> >>> +by running `git rebase master` while the `topic` branch is checked out.  If you
> >>> +want to rebase `topic` while on another branch, `git rebase master topic` is a
> >>> +shortcut for `git checkout topic && git rebase master`.
> >>> +
> >>
> >> Nit: now that `git-switch(1)` is no longer experimental, we should start
> >> recommending it over `git-checkout(1)` as necessary. So perhaps, we
> >> could s/checkout/switch here?
> >
> > Junio has already expressed a preference for "checkout" here c.f.
> > <[email protected]>. I think that is technically correct as
> > "topic" can be a commitish and "git switch <object-id>" fails without
> > "--detach". Also rebase does not do any of the extra checks that "git
> > switch" does before switching branches (I'm not saying that is
> > necessarily a good thing).
> >
>
> I missed that, but since we do mention that `topic` is a branch, it
> still makes sense to use 'git switch'. But either way this is okay.

In the general case, it may not be a branch though. (Of course, that's
too confusing a detail for this section anyway.)

-- 
D. Ben Knoble

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Junio C Hamano wrote (reply to this):

"D. Ben Knoble" <[email protected]> writes:

>> > Junio has already expressed a preference for "checkout" here c.f.
>> > <[email protected]>. I think that is technically correct as
>> > "topic" can be a commitish and "git switch <object-id>" fails without
>> > "--detach".

I wanted the new documentation text to use what was already used in
the parts of the document that are not touched; otherwise we end up
with text that uses checkout in some places and switch in others,
which would invite confusions among uninitiated readers, who
rightfully would wonder what criteria were used to decide which one
among these two different commands to use.  And teaching that these
two commands are quasi-equivalent with possibly subtle differences
is not what the documentation of "git rebase" needs to do---it is a
distraction.

I do not mind a new proposal to do a documentation sweep, aiming for
Git 3.0 timeframe, to examine all mentions of "git checkout" in the
documentation and replace them with "git switch" or "git restore"
when appropriate (there are of course ones that are not for obvious
reasons, like the ones in "git checkout" documentation itself, and
possibly in "git switch" and "git restore" documentation pages that
may say things like "'git switch X' is similar to 'git checkout Y'").

But let's leave that outside this topic.

Thanks.

Copy link

gitgitgadget bot commented Aug 11, 2025

User Karthik Nayak <[email protected]> has been added to the cc: list.

@jvns
Copy link
Author

jvns commented Aug 11, 2025

/submit

Copy link

gitgitgadget bot commented Aug 11, 2025

Submitted as [email protected]

To fetch this version into FETCH_HEAD:

git fetch https://github.com/gitgitgadget/git/ pr-1949/jvns/clarify-rebase-v5

To fetch this version to local tag pr-1949/jvns/clarify-rebase-v5:

git fetch --no-tags https://github.com/gitgitgadget/git/ tag pr-1949/jvns/clarify-rebase-v5

@@ -16,6 +16,32 @@ SYNOPSIS

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Junio C Hamano wrote (reply to this):

"Julia Evans via GitGitGadget" <[email protected]> writes:

> From: Julia Evans <[email protected]>
>
> - Start with an example that mirrors the example in the `git-merge` man
>   page, to make it easier for folks to understand the difference between
>   a rebase and a merge.
> - Mention that rebase can combine or reorder commits

The new comment added by this second point looks somewhat out of
place.  With this patch as-is, the text talks only about the best
case of the basic usage, tell the reader to go elsewhere if they are
not interested in learning the basic usage, and then switches back
to the basic usage topic and talks about conflict resolution.

It may be easier to read if you covered the fact that there are two
major use cases upfront, perhaps like:

    DESCRIPTION
    -----------
    Transplant a series of commits onto a different starting point.
    You can also use `git rebase` to reorder or combine commits: see
    INTERACTIVE MODE below for how to do that.

    For example, imagine ...

jvns added 4 commits August 11, 2025 17:07
- Start with an example that mirrors the example in the `git-merge` man
  page, to make it easier for folks to understand the difference between
  a rebase and a merge.
- Mention that rebase can combine or reorder commits

Signed-off-by: Julia Evans <[email protected]>
Previously there were two explanations, this combines them both into a
single explanation.

Signed-off-by: Julia Evans <[email protected]>
Remove duplicate explanation of `git rebase <upstream> <branch>` which
is already explained above.

Signed-off-by: Julia Evans <[email protected]>
There's a very clear explanation with examples of using --onto which is
currently buried in the very long DESCRIPTION section. This moves it to
its own section, so that we can reference the explanation from the
`--onto` option by name.

Signed-off-by: Julia Evans <[email protected]>
Copy link

gitgitgadget bot commented Aug 11, 2025

On the Git mailing list, Junio C Hamano wrote (reply to this), regarding 5ab235b (outdated):

"Julia Evans via GitGitGadget" <[email protected]> writes:

> From: Julia Evans <[email protected]>
>
> - make it clearer that we're talking about a multistep process
> - give a more technically accurate description how rebase works with the
>   merge backend.
> - condense the explanation of how git rebase skips commits with the same
>   textual changes into a single bullet point and remove the explanatory
>   diagram. Lots of things which are more complicated are already being
>   explained without a diagram.
> - remove the explanation of how exactly `--fork-point` and `--root`
>   work since that information is in the OPTIONS section
> - put all discussion of `ORIG_HEAD` inside the note
>
> Signed-off-by: Julia Evans <[email protected]>
> ---
>  Documentation/git-rebase.adoc | 66 ++++++++++++-----------------------
>  1 file changed, 23 insertions(+), 43 deletions(-)
>
> diff --git a/Documentation/git-rebase.adoc b/Documentation/git-rebase.adoc
> index 750f5e67e4c3..b4e5519d2839 100644
> --- a/Documentation/git-rebase.adoc
> +++ b/Documentation/git-rebase.adoc
> @@ -68,51 +68,31 @@ linkgit:git-config[1] for details) and the `--fork-point` option is
>  assumed.  If you are currently not on any branch or if the current
>  branch does not have a configured upstream, the rebase will abort.
>  
> -All changes made by commits in the current branch but that are not
> -in `<upstream>` are saved to a temporary area.  This is the same set
> -of commits that would be shown by `git log <upstream>..HEAD`; or by
> -`git log 'fork_point'..HEAD`, if `--fork-point` is active (see the
> -description on `--fork-point` below); or by `git log HEAD`, if the
> -`--root` option is specified.
> -
> -The current branch is reset to `<upstream>` or `<newbase>` if the
> -`--onto` option was supplied.  This has the exact same effect as
> -`git reset --hard <upstream>` (or `<newbase>`). `ORIG_HEAD` is set
> -to point at the tip of the branch before the reset.



> +Here is a more detailed description of what `git rebase <upstream>` does:

Were there a sketchy description given elsewhere already?  I
personally feel that giving too much details here would not
necessarily help readers' understanding.  I'd prefer to see an
introduction read more like "The command conceptually does these
things in the following order", and leave the level of description
also to match that introduction.  It may be just me, but when
somebody says "here is a detailed description", I would expect it to
contain little or no white lies mixed in, even for simplicity.

But of course others may have different opinions ;-)

> +1. Make a list of all commits in the current branch that are not in
> +   `<upstream>`. This is the same set of commits that would be shown by `git log
> +   <upstream>..HEAD`. You can use `--fork-point` or `--root` to change how this
> +   list of commits is constructed.

Didn't somebody mention "git log --cherry-pick <upstream>..HEAD"?
If omission of it is for simplicity, that is fine, but that is
another reason why we do not want to say "more detaild description".

Also, shouldn't there be step #0 that says "If the <branch> to rebase
is given, check out that branch and make it current", for the HEAD
in this description to work correctly?

> +2. Check whether any of those commits are duplicates of commits already
> +   in `<upstream>`, remove them from the list, and print out a warning about
> +   each removed commit. You can use `--reapply-cherry-picks` to include
> +   duplicate commits.

This is done as part of #1 above as part of a single invocation of
revision walk (i.e. a loop in sequencer.c:sequencer_make_script()
that calls get_revision() repeatedly).

> +3. Check out `<upstream>` (or `<newbase>` if the `--onto` option was
> +   supplied) with the equivalent of `git checkout --detach <upstream>`.
> +4. Replay the commits, one by one, in order. This is similar to running
> +   `git cherry-pick <commit>` for each commit. See REBASING MERGES for how merges
> +   are handled.
> +5. Update your branch to point to the final commit with the equivalent
> +   of `git switch -C <branch>`.

In step #3, you switched to <upstream> with "git checkout"; here you
use "git switch".  Uninitiated readers would wonder what criteria
were used to decide which one among these two different commands to
use in steps #3 and #5, even though either would work fine.  Because
this page is not where readers come to learn about the equivalence
of these two commands that are not essential to learning "git
rebase", it is better, so once you started with "git checkout", to
stick to it throughout to reduce the mental burden to first-time
learners.

Thanks.

@jvns jvns force-pushed the clarify-rebase branch 2 times, most recently from c3c3826 to 9c7f271 Compare August 11, 2025 21:40
@jvns
Copy link
Author

jvns commented Aug 11, 2025

/submit

Copy link

gitgitgadget bot commented Aug 11, 2025

Submitted as [email protected]

To fetch this version into FETCH_HEAD:

git fetch https://github.com/gitgitgadget/git/ pr-1949/jvns/clarify-rebase-v6

To fetch this version to local tag pr-1949/jvns/clarify-rebase-v6:

git fetch --no-tags https://github.com/gitgitgadget/git/ tag pr-1949/jvns/clarify-rebase-v6

Copy link

gitgitgadget bot commented Aug 11, 2025

On the Git mailing list, Junio C Hamano wrote (reply to this):

"Julia Evans via GitGitGadget" <[email protected]> writes:

>  * move "You can also use git rebase to reorder or combine commits:" to the
>    beginning
>  * replace "detailed description" with "simplified description" -- I thought
>    that I could write something that was relatively readable and also
>    accurate, but as usual Git has proven me wrong :). I tried to leave in
>    the details that I think seem relevant to using git: for example git
>    checkout --detach is relevant because it explains why git reflog works
>    well after a rebase.
>  * replace the git switch with git checkout that I'd missed previously
>
> I didn't use the git log --cherry-pick option in the explanation because I
> had personally never heard of that option before today, and I don't want
> people to have to read the git log man page to be able to understand the
> explanation. I also left out --reapply-cherry-picks just because I don't
> understand the use case so I couldn't evaluate how likely it is to be
> relevant to the person reading.

I agree with the above decision to leave unnecessary implementation
details out, and I also agree with the decision to talk about
rebasing done on the detached HEAD.  I will find out if I agree with
the remainder of details that are kept (and left out) later by
reading the patches ;-)

Thanks.

If you don't specify an `<upstream>` to rebase onto, the upstream configured in
`branch.<name>.remote` and `branch.<name>.merge` options will be used (see
linkgit:git-config[1] for details) and the `--fork-point` option is
assumed. If you are currently not on any branch or if the current
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Junio C Hamano wrote (reply to this):

"Julia Evans via GitGitGadget" <[email protected]> writes:

> +Here is a simplified description of what `git rebase <upstream>` does:

Now this is a "this is roughly how it works", we can afford to give
a simplified picture that may not exactly match the implementation,
which is great freedom to have while writing documentation for first
time users.

> +1. Make a list of all new commits on your current branch since it branched
> +   off from `<upstream>`. This is the same set of commits that would be shown
> +   by `git log  <upstream>..HEAD`. You can use `--fork-point` or  `--root` to
> +   change how this list of commits is constructed.
> +2. Check whether any of those commits are duplicates of commits already
> +   in `<upstream>` and remove them from the list.

So, I do not mind #2 described as a separate step.  Conceptually, it
is between "create a list of all commits in the range and filter out
what have already been applied" and "create a list of all commits
that are not in the upstream yet".  We may be able to rephrase "all
new commits on your current branch" somewhat to make it unnecessary
to describe #2, though.  If we are willing to stop talking about
"This is the same set of ...", then the description becomes very
simple:

    Make a list of all commits on your current branch since it
    branched off from `<upstream>` that do not have equivalent
    change in `<upstream>`.

> +3. Check out `<upstream>` with the equivalent of `git checkout --detach <upstream>`.

The line is getting overly long here and a few lines below.  If your
editor has the feature, tell it to auto-wrap at around 66-72 column.

> +4. Replay the commits, one by one, in order. This is similar to running
> +   `git cherry-pick <commit>` for each commit. See REBASING MERGES for how merges
> +   are handled.
> +5. Update your branch to point to the final commit with the equivalent
> +   of `git checkout -C <branch>`.

Force-create-branch while checking out is `git checkout -B
<branch>`, not -C.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, "Julia Evans" wrote (reply to this):

> So, I do not mind #2 described as a separate step.  Conceptually, it
> is between "create a list of all commits in the range and filter out
> what have already been applied" and "create a list of all commits
> that are not in the upstream yet".  We may be able to rephrase "all
> new commits on your current branch" somewhat to make it unnecessary
> to describe #2, though.  If we are willing to stop talking about
> "This is the same set of ...", then the description becomes very
> simple:

To me it feels relevant that `git rebase` is using two separate mechanisms to
compare commits: the sha and (I think?) what `git patch-id` does. As a user
it feels like an important distinction because normally when I look at my git
commits I only use the sha (via something like `git log --graph`) to see what
the new commits on a branch are.

Maybe the second part can be rephrased like this to emphasize that it's using a
different mechanism than the SHA:

> 2. Check whether any of those commits contain the same changes (according to
   `git patch-id`) as a commit already in `<upstream>` and remove them from
   the list.


> The line is getting overly long here and a few lines below.  If your
> editor has the feature, tell it to auto-wrap at around 66-72 column.

Will fix, and I'll add a pre-commit hook to check for that.

> Force-create-branch while checking out is `git checkout -B
> <branch>`, not -C.

Will fix.

- make it clearer that we're talking about a multistep process
- give a more technically accurate description how rebase works with the
  merge backend.
- condense the explanation of how git rebase skips commits with the same
  textual changes into a single bullet point and remove the explanatory
  diagram. Lots of things which are more complicated are already being
  explained without a diagram.
- remove the explanation of how exactly `--fork-point` and `--root`
  work since that information is in the OPTIONS section
- put all discussion of `ORIG_HEAD` inside the note

Signed-off-by: Julia Evans <[email protected]>
Copy link

gitgitgadget bot commented Aug 12, 2025

This patch series was integrated into seen via git@50183bd.

@jvns
Copy link
Author

jvns commented Aug 12, 2025

/submit

Copy link

gitgitgadget bot commented Aug 12, 2025

Submitted as [email protected]

To fetch this version into FETCH_HEAD:

git fetch https://github.com/gitgitgadget/git/ pr-1949/jvns/clarify-rebase-v7

To fetch this version to local tag pr-1949/jvns/clarify-rebase-v7:

git fetch --no-tags https://github.com/gitgitgadget/git/ tag pr-1949/jvns/clarify-rebase-v7

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants