让我描述一下我的情况:

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文档。)

08-27 06:40