让我来描述我的情况:
Blond先生和Orange先生正在研究分支A,它在提交M1的主分支上分支出来。分支A有2个提交:A1和A2。
M1
\
\
A1 - A2
与此同时,奥兰治先生承诺并在主分公司M2和M3上再提交2次。
M1 - M2 - M3
\
\
A1 - A2
布朗先生从遥控器拉出来,过了一会儿决定重新进入主分支:
M1 - M2 - M3
\ \
\ \
A1 - A2 A1` - A2`
现在A1`和A2`是在金色先生本地存在的重新提交,A1和A2远程存在。金发先生推动他的提交,使用-f强制他的改变并“重写”历史。现在远程存储库看起来像这样:
M1 - M2 - M3
\
\
A1` - A2`
但奥兰治先生也在A分公司工作。他的本地存储库仍然如下所示:
M1 - M2 - M3
\
\
A1 - A2
Orange先生需要做什么才能与远程存储库中的A分支同步?
正常拉动不起作用。请拉-f强制远程本地的更改?我知道删除本地版本的A并从远程存储库再次提供它将会起到作用,但这似乎并不是实现这一目标的好方法。
我的建议(或者,“如果我是奥兰治先生,我会做什么”)是从git fetch
开始的。现在我将在我的回购中拥有这个,这就是金发先生在他的篮板之后以及在他执行“git push -f”之前所拥有的。
M1 - M2 - M3
\ \
\ \
A1 - A2 A1' - A2'
一个重要的区别是,我将我的本地标签A
指向rev A2,远程标签remotes/origin/A
指向A2'(金色先生反过来,当地标签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,因为修改后的转换器在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的旧分支的名称,甚至虽然它仍然在我的回购中;找到它需要通过reflogs或类似的)。
(如果我的A3需要修改成为A3',当然,交互式rebase和“git am”方法都需要我的工作。)
当然也可以只使用git merge
(如Gary Fixler的答案),但这将创建一个合并提交(“M”没有数字,下面)并保持转速A1和A2可见,给出:
M1 ---- M2 ---- M3
\ \
\ \
A1 - A2 - A3 A1' - A2' -- M
\_______________/
如果你想保留原来的A1和A2,这是一件好事;如果你想摆脱它们,这是一件坏事。所以“做什么”取决于“你想要的结果是什么”。
编辑添加:我更喜欢格式补丁方法,因为它保留了我的旧A分支名称,同时我确保一切都很好。假设一切正常并且很好,这是最后几步:
$ git branch -m A old_A
$ git branch -m new_A A
然后,如果old_A可以完全放弃:
$ git branch -D old_A
或者,等效地,从分支删除开始,然后将new_A重命名为A.
(编辑:另请参阅git rebase --onto
文档,了解将A3等转换为new_A分支的目标。)
如果奥兰治先生不介意失去他的变化,他可以从服务器上取,然后git checkout A2
进入他当地的A2
分支,然后(假设遥控器被命名为“起源”)git reset --hard origin/A2
将他的A2
重置到遥控器的A2
所在地是。
如果他担心丢失更改,他可以合并服务器的更改以解决它们(从他自己的A2
分支,并再次假设远程被命名为“origin”)与git merge origin/A2
。这将使得他和远程的A2
分支之上的新提交与两者的变化合并在一起。然后可以将其推回遥控器。
我在两台虚拟机上同时开发,用于配置目的。因此,我经常在一台机器上进行改装,并且需要更改才能毫无困难地出现在另一台机器上。
假设我的分支名为feature/my-feature-branch
。完成第一个VM上的rebase后,我在第二个VM上进行git fetch。出现以下消息:
$ git status
On branch feature/my-feature-branch
Your branch and 'origin/feature/my-feature-branch' have diverged,
and have 21 and 24 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
好吧,不要做一个git pull,因为那么你经过一番无聊之后就会陷入毫无意义的合并提交。
相反,跑
git rebase -i origin/feature/my-feature-branch
弹出文本编辑器后,删除所有提交,并用以下内容替换它(这样就可以完成rebase而不保留任何提交)。
exec echo test
如果你确实有需要保留的提交,那么这些可以在这里应用。在任何一种情况下,rebase都将完成,现在两台机器再次同步,如下所示:
$ git pull
Already up-to-date.
$ git push
Everything up-to-date