Git:拉一个重新分支

问题描述 投票:43回答:3

让我来描述我的情况:

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 push rebase pull
3个回答
25
投票

我的建议(或者,“如果我是奥兰治先生,我会做什么”)是从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分支的目标。)


45
投票

如果奥兰治先生不介意失去他的变化,他可以从服务器上取,然后git checkout A2进入他当地的A2分支,然后(假设遥控器被命名为“起源”)git reset --hard origin/A2将他的A2重置到遥控器的A2所在地是。

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


2
投票

我在两台虚拟机上同时开发,用于配置目的。因此,我经常在一台机器上进行改装,并且需要更改才能毫无困难地出现在另一台机器上。

假设我的分支名为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
© www.soinside.com 2019 - 2024. All rights reserved.