让我描述一下我的情况:
Blond先生和Orange先生正在分支A上工作,该分支在提交M1时从主分支分支出来。分支A有2个提交:A1和A2。
M1
\
\
A1 - A2
同时,Orange先生在主分支M2和M3上提交并推送了另外2个提交。
M1 - M2 - M3
\
\
A1 - A2
金发碧眼的先生从远程拉过来,过了一会儿决定改用master分支:
M1 - M2 - M3
\ \
\ \
A1 - A2 A1` - A2`
现在,A1和A2是重新定位的提交,它们位于金发碧眼先生的本地,而A1和A2则远程存在。金发碧眼的先生使用 -f 来强制提交所做的更改并“重写”历史记录。现在,远程存储库如下所示:
M1 - M2 - M3
\
\
A1` - A2`
但是奥兰治先生也曾在A分支工作。他的本地存储库仍如下所示:
M1 - M2 - M3
\
\
A1 - A2
为了与远程存储库中的A分支同步,Orange先生需要做什么?
正常拉力将不起作用。 pull -f 是否会强制从本地远程进行更改?我知道删除A的本地版本并将其从远程存储库中重新导入将达到目的,但这似乎并不是实现此目的的好方法。
最佳答案
我的建议(或“如果我是奥兰治先生,我该怎么办”)是从git fetch
开始。现在,我将在回购中使用它,这是金发碧眼的先生在改组后和运行“git push -f”之前的内容。
M1 - M2 - M3
\ \
\ \
A1 - A2 A1' - A2'
一个重要的区别是,我将本地标签
A
指向版本A2,将远程标签remotes/origin/A
指向A2'(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
然后完全删除revs A1和A2,因为修改后的版本分别在new_A中作为A1'和A2'。要么:
$ 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
方法)。这些确实需要弄清楚金发先生在做
rebase
之前我没有的东西,即识别A1,A2,A3等。如果第二种方法成功,我将得到:
M1 ---- M2 ---- M3
\ \
\ \
A1 - A2 - A3 A1' - A2' - A3'
我的分支名称
new_A
指向A3'(我现有的A
分支仍指向旧的A3)。如果我使用第一种方法并且成功了,我将得到相同的结果,只是我现有的分支名称A
现在将指向A3'(而且对于A1-A2-A3的旧分支,我也没有名称,即使尽管它仍在我的存储库中;要找到它需要通过reflog或类似内容)。(当然,如果我的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
然后,如果old_A可以完全放弃:
$ git branch -D old_A
或者等效地,从删除分支开始,然后将new_A重命名为A。
(编辑:有关将A3等重新部署到new_A分支的目标,另请参见
git rebase --onto
文档。)