@@ -154,23 +154,71 @@ topic origin/master`, the history of remote-tracking branch
154
154
`origin/master` may have been rewound and rebuilt, leading to a
155
155
history of this shape:
156
156
157
- o---B1
157
+ o---B2
158
158
/
159
- ---o---o---B2 --o---o---o---B (origin/master)
159
+ ---o---o---B1 --o---o---o---B (origin/master)
160
160
\
161
- B3
161
+ B0
162
162
\
163
- Derived (topic)
163
+ D0---D1---D (topic)
164
164
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
166
166
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
170
186
171
187
$ fork_point=$(git merge-base --fork-point origin/master topic)
188
+
189
+ will find B0, and
190
+
172
191
$ git rebase --onto origin/master $fork_point topic
173
192
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
+
174
222
175
223
See also
176
224
--------
0 commit comments