83

让我描述一下我的情况:

Blond 先生和 Orange 先生正在处理分支 A,该分支在提交 M1 时从主分支分支出来。分支 A 有 2 个提交:A1 和 A2。

M1  
   \
    \
     A1 - A2

与此同时,Orange 先生在主分支 M2 和 M3 上提交并推送了另外 2 个提交。

M1  - M2 - M3
   \
    \
     A1 - A2

Blond 先生从遥控器中拉出,过了一会儿决定重新设置到 master 分支上:

M1  - M2 - M3
   \         \
    \         \
     A1 - A2   A1` - A2`

现在 A1` 和 A2` 是在 Mr blond's 本地存在的 rebase 提交,并且 A1 和 A2 远程存在。Blond 先生推动他的提交,使用-f强制他的更改和“重写”历史。现在远程存储库如下所示:

M1  - M2 - M3
             \
              \
               A1` - A2`

但奥兰治先生也在 A 分公司工作。他的本地存储库仍然如下所示:

M1  - M2 - M3
   \
    \
     A1 - A2

橙先生需要做什么才能与远程仓库的A分支同步?

正常的拉动是行不通的。pull -f会在本地强制从远程进行更改吗?我知道删除 A 的本地版本并从远程存储库中再次将其带入可以解决问题,但这似乎不是实现这一目标的好方法。

4

4 回答 4

95

如果 Orange 先生不介意丢失他的更改,他可以从服务器获取,然后git checkout A进入他的本地A分支,然后(假设远程被命名为“origin”)git reset --hard origin/A将他的重置A为远程所在的A位置。

如果他担心丢失更改,他可以合并服务器的更改以解决它们(从他自己的A分支,并再次假设远程被命名为“origin”)git merge origin/A。这将在他的和远程的分支之上进行一个新的提交,并将两者A的更改合并在一起。然后可以将其推回遥控器。

于 2013-05-27T13:31:04.630 回答
35

我的建议(或者,“如果我是橙色先生,我会怎么做”)是,从git fetch. 现在我将在我的 repo 中有这个,这是 Blond 先生在他的 rebase 之后和他运行“git push -f”之前所拥有的。

M1  - M2 - M3
   \         \
    \         \
     A1 - A2   A1' - A2'

一个重要的区别是,我的本地标签A指向 rev 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手册页中有描述)。

这些确实需要弄清楚我在 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

然后,如果 old_A 可以完全放弃:

$ git branch -D old_A

或者,等效地,从分支删除开始,然后将 new_A 重命名为 A。

(编辑:另请参阅git rebase --onto文档,以将 A3 等重新定位到 new_A 分支。)

于 2013-05-27T22:26:31.620 回答
20

出于配置目的,我在两个虚拟机上同时开发。结果,我经常在一台机器上进行 rebase,并且需要将更改毫无困难地出现在另一台机器上。

假设我的分支名为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
于 2018-06-27T21:04:30.620 回答
2

TLDR

除非我误解了这个问题,否则奥兰治先生的答案是git pull --rebase

更长的阅读时间

简单案例

如果我们假设 A1 和 A2 所做的更改与 A1' 和 A2' 相同(即使它们的提交哈希值不同),那么 Orange 先生可以不再拥有

M1  - M2 - M3
   \
    \
     A1 - A2

本地拥有

M1  - M2 - M3
             \
              \
               A1` - A2`

通过要么做

git pull --rebase

或者

git branch -d A
git checkout A

一个更有趣的案例

如果我们假设,如上所述,A1 和 A2 所做的更改是相同的,并且 Orange 先生进行了额外的提交,那么他将在本地拥有

M1  - M2 - M3
   \
    \
     A1 - A2 - A3O

和起源将是

M1  - M2 - M3
             \
              \
               A1` - A2`

再说一次,奥兰治先生可以到达

M1  - M2 - M3
             \
              \
               A1` - A2` - A3O

用一个简单的

git pull --rebase

一个更现实的案例

如果我们假设,如上所述,A1 和 A2 所做的更改是相同的,Orange 先生做了一个额外的提交,而 Blonde 先生做了一个额外的提交,那么 Orange 先生将在本地拥有这个

M1  - M2 - M3
   \
    \
     A1 - A2 - A3O

并且,假设 Blonde 先生已经推动,起源将是

M1  - M2 - M3
             \
              \
               A1` - A2` - A3B

奥兰治先生可以到达

M1  - M2 - M3
             \
              \
               A1` - A2` - A3B - A3O

通过做

git pull --rebase

不过,这一次,他可能需要解决冲突。

于 2021-08-05T11:44:28.250 回答