Skip to content

Commit 03d4bc1

Browse files
committed
Merge branch 'jc/merge-base-fork-point-doc' into maint
Clarify and enhance documentation for "merge-base --fork-point", as it was clear what it computed but not why/what for. * jc/merge-base-fork-point-doc: merge-base --fork-point doc: clarify the example and failure modes
2 parents ce73209 + 6d1700b commit 03d4bc1

File tree

1 file changed

+56
-8
lines changed

1 file changed

+56
-8
lines changed

Documentation/git-merge-base.txt

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -154,23 +154,71 @@ topic origin/master`, the history of remote-tracking branch
154154
`origin/master` may have been rewound and rebuilt, leading to a
155155
history of this shape:
156156

157-
o---B1
157+
o---B2
158158
/
159-
---o---o---B2--o---o---o---B (origin/master)
159+
---o---o---B1--o---o---o---B (origin/master)
160160
\
161-
B3
161+
B0
162162
\
163-
Derived (topic)
163+
D0---D1---D (topic)
164164

165-
where `origin/master` used to point at commits B3, B2, B1 and now it
165+
where `origin/master` used to point at commits B0, B1, B2 and now it
166166
points at B, and your `topic` branch was started on top of it back
167-
when `origin/master` was at B3. This mode uses the reflog of
168-
`origin/master` to find B3 as the fork point, so that the `topic`
169-
can be rebased on top of the updated `origin/master` by:
167+
when `origin/master` was at B0, and you built three commits, D0, D1,
168+
and D, on top of it. Imagine that you now want to rebase the work
169+
you did on the topic on top of the updated origin/master.
170+
171+
In such a case, `git merge-base origin/master topic` would return the
172+
parent of B0 in the above picture, but B0^..D is *not* the range of
173+
commits you would want to replay on top of B (it includes B0, which
174+
is not what you wrote; it is a commit the other side discarded when
175+
it moved its tip from B0 to B1).
176+
177+
`git merge-base --fork-point origin/master topic` is designed to
178+
help in such a case. It takes not only B but also B0, B1, and B2
179+
(i.e. old tips of the remote-tracking branches your repository's
180+
reflog knows about) into account to see on which commit your topic
181+
branch was built and finds B0, allowing you to replay only the
182+
commits on your topic, excluding the commits the other side later
183+
discarded.
184+
185+
Hence
170186

171187
$ fork_point=$(git merge-base --fork-point origin/master topic)
188+
189+
will find B0, and
190+
172191
$ git rebase --onto origin/master $fork_point topic
173192

193+
will replay D0, D1 and D on top of B to create a new history of this
194+
shape:
195+
196+
o---B2
197+
/
198+
---o---o---B1--o---o---o---B (origin/master)
199+
\ \
200+
B0 D0'--D1'--D' (topic - updated)
201+
\
202+
D0---D1---D (topic - old)
203+
204+
A caveat is that older reflog entries in your repository may be
205+
expired by `git gc`. If B0 no longer appears in the reflog of the
206+
remote-tracking branch `origin/master`, the `--fork-point` mode
207+
obviously cannot find it and fails, avoiding to give a random and
208+
useless result (such as the parent of B0, like the same command
209+
without the `--fork-point` option gives).
210+
211+
Also, the remote-tracking branch you use the `--fork-point` mode
212+
with must be the one your topic forked from its tip. If you forked
213+
from an older commit than the tip, this mode would not find the fork
214+
point (imagine in the above sample history B0 did not exist,
215+
origin/master started at B1, moved to B2 and then B, and you forked
216+
your topic at origin/master^ when origin/master was B1; the shape of
217+
the history would be the same as above, without B0, and the parent
218+
of B1 is what `git merge-base origin/master topic` correctly finds,
219+
but the `--fork-point` mode will not, because it is not one of the
220+
commits that used to be at the tip of origin/master).
221+
174222

175223
See also
176224
--------

0 commit comments

Comments
 (0)