我的建议是(或者,如果我是Mr Orange的话,我会这样做),从git fetch
开始。现在我将拥有这个库,这就是Mr Blond在他的变基之后并且在运行"git push -f"之前所拥有的。
M1 - M2 - M3
\ \
\ \
A1 - A2 A1' - A2'
唯一重要的区别是,我的本地标签 A
指向 rev A2,而远程标签 remotes/origin/A
指向 A2'(Mr Blond 的情况相反,本地标签 A
指向 A2',remotes/origin/A
指向 A2)。
如果我一直在处理名为“A”的分支的副本,则会有以下内容:
M1 ---- M2 ---- M3
\ \
\ \
A1 - A2 - A3 A1' - A2'
(我的本地标签指向A3,而不是A2;或者A4或A5等,这取决于我应用了多少更改。)现在我所要做的就是将我的A3(如果需要,还有A4等)变基到A2'。一个明显的直接方式:
$ git branch -a
master
* A
remotes/origin/master
remotes/origin/A
$ git branch new_A remotes/origin/A
$ git rebase -i new_A
然后完全删除A1和A2的版本,因为已经修改的版本现在是新版本A1'和A2',存储在new_A中。或者:
$ git checkout -b new_A remotes/origin/A
$ git format-patch -k --stdout A3..A | git am -3 -k
(git am -3 -k
方法在 git-format-patch
手册页中描述。)
这些需要弄清楚我在 Mr Blond 进行 rebase
之前拥有什么,即识别 A1、A2、A3 等。
如果第二种方法成功,最终会得到:
M1 ---- M2 ---- M3
\ \
\ \
A1 - A2 - A3 A1' - A2' - A3'
我的分支名 new_A
指向 A3'(我的现有分支 A
仍指向旧的 A3)。如果我使用第一种方法并成功了,最后结果是一样的,只是我的现有分支名 A
现在将指向 A3'(而我没有名称来标识具有 A1-A2-A3 的旧分支,尽管它仍然在我的仓库中;查找它需要通过 reflogs 或类似方式进行)。
(如果我的 A3 需要修改才能成为 A3',那么交互式变基和 "git am" 方法都需要我自己做出调整。)
当然,也可以直接使用 git merge
(如 Gary Fixler 的答案所示),但这将创建一个合并提交(下面是没有编号的"M"),并保留修订版 A1 和 A2,显示如下:
M1 ---- M2 ---- M3
\ \
\ \
A1 - A2 - A3 A1' - A2' -- M
\_______________/
如果你想保留原始的A1和A2,这是一件好事;如果你想摆脱它们,那就不好了。因此,“该怎么做”取决于“你想得到什么结果”。
编辑添加:我更喜欢使用format-patch方法,因为在确保一切都很好之前,它会保留我的旧A分支名称。 假设所有东西都能工作并且是好的,以下是最后几个步骤:
$ git branch -m A old_A
$ git branch -m new_A A
然后,如果旧的A完全可以被放弃:
$ git branch -D old_A
或者等价地,从分支删除开始,然后将新的A重命名为A。
(编辑:另请参阅git rebase --onto
文档,以将A3等重新定位到新的A分支的目标。)
--
和hard
之间没有空格 - 我花了一会儿时间才找到答案,因为它恰好包裹在这两个词之间,但不要改变原来的意思。 - qbolecorigin/A
而不是origin/A2
,因为A2
是指一个提交而不是一个分支。 - Khouri Giordanogit reset
之前使用git fetch
从远程下载更改,是这样吗? - Ferran Maylinch