Reading the git rebase
and git merge-base
man documentation:
After working on the topic branch created with git checkout -b topic origin/master, the history of remote-tracking branch origin/master may have been rewound and rebuilt, leading to a history of this shape:
o---B1 / ---o---o---B2--o---o---o---B (origin/master) \ B3 \ Derived (topic)
where origin/master used to point at commits B3, B2, B1 and now it points at B, and your topic branch was started on top of it back when origin/master was at B3. This mode uses the reflog of origin/master to find B3 as the fork point, so that the topic can be rebased on top of the updated origin/master by:
$ fork_point=$(git merge-base --fork-point origin/master topic) $ git rebase --onto origin/master $fork_point topic
$fork_point
will ( if I understand it correctly ) be the commit object B3
, and, thus the commits B3..topic
will be rebased onto to origin/master
branch.
Q1 Why is it useful to omit the B3
commit? The commits of the topic
branch are built on top of the B3
commit, so omitting it would mean that its modifications would then be missing in the story of the origin/master
branch. Rebasing the B3
commit and the topic
branch would lead to a cleaner history, wouldn't it?
Q2 Can someone link / briefly describe practical use cases of the --fork-point
option in the git workflow?
It's basically like you're tacking on your changes to the existing master branch, rather than trying to inject your commits chronologically into the master branch that already exists.
You are correct that $fork_point
will be B3
.
I believe the intent here is to omit B3
as "not your commit".
I think the diagram the Git folks drew here is not so good. Here's how I would redraw and rewrite it without changing it too much (though I'd probably just re-letter each commit anyway).
You begin by cloning (or otherwise updating to) some (origin
) repository whose graph ends in commit B3
, and you create a topic branch and make some commit(s):
...--o---F---B3 <-- origin/master
\
G <-- topic
Over time, with additional git fetch
-es and git commit
s, your commit graph now looks like this:
...--o---F---B3--B2--B1 <-- origin/master
\
G---H---I <-- topic
But, suddenly, after another git fetch
, your own commit graph now looks like this:
o---B1' <-- origin/foo
/
...o---F---B2'-o---o---o---B <-- origin/master
\
B3--G---H---I <-- topic
That is, Git would now think that commit B3 belongs on your topic branch, when in fact, your work begins with commit G
. The people who own the repository named origin
have, in effect, declared that commit B3
is terrible and should be thrown away. (They kept a copy of B2
as B2'
on their master
, and one of B1
as B1'
on their foo
.)
If you simply git rebase
, you will copy original commit B3
to new copy B3'
(while also copying G-H-I
):
o---B1' <-- origin/foo
/
...o---F---B2'-o---o---o---B <-- origin/master
\
B3'-G'--H'--I' <-- topic
but you would instead prefer:
o---B1' <-- origin/foo
/
...o---F---B2'-o---o---o---B <-- origin/master
\
G'--H'--I <-- topic
For git rebase
to do this, you must instruct Git to locate commit B3
. Your reflog for origin/master
has all of F
, B3
, B2
, and B1
in it (under at least one reflog entry, including in this case origin/master@{1}
), while your own topic
has F
and B3
, but not B2
nor B1
, in it as well. Therefore --fork-point
chooses B3
as the newest (tip-most) shared commit, rather than F
.
The key sentence / idea in here is that the upstream repository writers intended to discard commit B3
entirely.
(How you are supposed to know this for certain is a bit of a mystery. It may not be obvious that B2'
and B1'
are copies, if the rebasing required, e.g., discarding a file that should never have been committed—and was in B1
, which is why B1
was also discarded. The fact that this file is now omitted in B2'
and B3'
makes them not-patch-equivalent, hence not obviously copies.)
(Note that your own master
also still points to B3
!)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With