@@ -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
155155history 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
166166points 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
175223See also
176224--------
0 commit comments