Subject: Re: [PATCH v2 5/5] doc: git-rebase: update discussion of internals

From: Junio C Hamano <[email-masked]>
Date: Fri, 08 Aug 2025 14:54:13 -0700

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

> From: Julia Evans <[email-masked]>
>
> - 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.