Git:拉动重新设计的分支 [英] Git: Pulling a rebased branch

查看:93
本文介绍了Git:拉动重新设计的分支的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

让我描述一下我的情况:



Blond先生和Orange先生正在从事分支机构A的分支机构A的工作,该分支机构负责提交M1。分公司A有两项提交:A1和A2。

  M1 
\
\
A1 - A2

与此同时,Orange先生承诺并在主分支M2和M3。

  M1  -  M2  -  M3 
\
\
A1 - A2

Blond先生从遥控器中拉出来,经过一段时间后决定重新放在主分支上: p>

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

现在A1`和A2`是金先生本地存在的重新提交的提交,并且A1和A2远程存在。 Blond先生推动他的提交,使用 -f 强制改变并重写历史记录。现在远程仓库看起来像这样:

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

但是Orange先生也在A分部工作。他的本地存储库仍然是这样的:

  M1  -  M2  -  M3 
\
\
A1 - A2

Orange先生需要做什么才能与A同步分支在远程存储库?



正常的拉不能工作。 pull -f 会强制从本地远程执行更改吗?我知道删除A的本地版本并将其从远程存储库再次引入将会执行该操作,但这似乎不是实现该目的的好方法。

解决方案

我的建议(或者,如果我是橙先生,我会怎么做)是从 git fetch 开始。现在,我将在回购协议中讨论这个问题,这就是金先生在重新组织之后以及在他运行git push -f之前所做的。

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

一个重要的区别是,我将本地标签 A 指向rev A2,并且指向A2'的远程标签遥控器/原产地/ A (Blond先生反其道而行之,本地标签 A 指向A2'和远程/源/ A 指向A2)。



如果我一直在工作在我的名为A的分支的副本上,我将使用它:

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

(我的本地标签指向A3而不是A2;或者A4或A5等,具体取决于我所应用的更改数量。)否我所要做的就是将我的A3(和A4,如果需要的话)重新贴到A2'上。一种明显的直接方式:

$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ / 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 - 标准输出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'(并且我没有尽管它仍然在我的回购库中,但是需要通过reflogs或类似的方式才能获得A1-A2-A3旧分店的名称。



(如果我的A3需要修改成为A3',当然,交互式底座和GIT AM方法都需要我的工作。)



当然,也可以 git merge (如Gary Fixler的回答),但是这会创建一个合并提交(下面没有数字的M),并保持A1和A2可见,给出:

  M1 ---- M2 ---- M3 
\\\
\ \
A1 - A2 - A3 A1' - A2' - M
\ _______________ /

如果你想保留原来的A1和A2,这是一件好事;如果你想摆脱它们,这是一件坏事。所以做什么取决于你想要的结果是什么。



编辑添加:我更喜欢format-patch方法,因为它会离开我的老当我确定一切都很好时,一个分支名称。假设这一切都正常,并且 ,这是最后几步:

  $ git branch -m a old_A 
$ git branch -m new_A a

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

  $ git branch -D old_A 

或等价地,从分支删除开始,然后将new_A重命名为A.
$ b

(编辑:另见 git rebase --onto 文档,目的是将A3重新贴装到new_A分支上。)


Let me describe my situation:

Mr Blond and Mr Orange are working on branch A that branches out of the master branch on commit M1. Branch A has 2 commits: A1 and A2.

M1  
   \
    \
     A1 - A2

Meanwhile, Mr Orange committed and pushed 2 more commits on the master branch, M2 and M3.

M1  - M2 - M3
   \
    \
     A1 - A2

Mr Blond pulls from the remote, and after a while decides to rebase onto the master branch:

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

Now A1` and A2` are the rebased commits that exist locally at Mr blond's, and A1 and A2 exist remotely. Mr Blond pushes his commits, using -f to force his changes and "rewrite" history. Now the remote repository looks like this:

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

But Mr. Orange worked on the A branch as well. His local repository still looks like this:

M1  - M2 - M3
   \
    \
     A1 - A2

What does Mr. Orange need to do in order to be synchronized with A branch in the remote repository?

A normal pull won't work. Will pull -f force the changes from the remote locally? I know that deleting the local version of A and bringing it again from the remote repository will do the trick but that doesn't seem to be a good way to achieve that.

解决方案

My recommendation (or, "what I would do if I were Mr Orange") is, start with git fetch. Now I'll have this in my repo, which is what Mr Blond had after his rebase and just before he ran "git push -f".

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

The one important difference is, I'll have my local label A pointing to rev A2, and the remote label remotes/origin/A pointing to A2' (Mr Blond had it the other way around, local label A pointing to A2' and remotes/origin/A pointing to A2).

If I've been working on my copy of the branch named "A" I'll have this instead:

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

(with my local label pointing to A3 rather than A2; or A4 or A5, etc, depending on how many changes I have applied.) Now all I have to do is rebase my A3 (and A4 if needed, etc) onto A2'. One obvious direct way:

$ git branch -a
  master
* A
  remotes/origin/master
  remotes/origin/A
$ git branch new_A remotes/origin/A
$ git rebase -i new_A

and then drop revs A1 and A2 entirely, since the modified ones are in new_A as A1' and A2'. Or:

$ git checkout -b new_A remotes/origin/A
$ git format-patch -k --stdout A3..A | git am -3 -k

(the git am -3 -k method is described in the git-format-patch manual page).

These do require figuring out what I have that Mr Blond didn't before he did his rebase, i.e., identifying A1, A2, A3, etc.

If the second approach is successful I end up with:

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

where my branch name new_A points to A3' (my existing A branch still points to the old A3). If I use the first approach and it succeeds, I end up with the same thing, it's just that my existing branch name A will now point to A3' (and I have no name for the old branch with A1-A2-A3, even though it's still in my repo; finding it requires going through reflogs or similar).

(If my A3 needs modification to become A3', both the interactive rebase and the "git am" method will require work by me, of course.)

Of course it's also possible to just git merge (as in the answer by Gary Fixler), but that will create a merge commit ("M" with no number, below) and keep revs A1 and A2 visible, giving:

M1  ---- M2 ---- M3
   \               \
    \               \
     A1 - A2 - A3    A1' - A2' -- M
                 \_______________/

If you want to preserve the original A1 and A2, this is a good thing; if you want to get rid of them, it's a bad thing. So "what to do" depends on "what you want the result to be".

Edit to add: I like the format-patch method better as it leaves my old A branch name around while I make sure everything is good. Assuming it all works and is good, here's the last few steps:

$ git branch -m A old_A
$ git branch -m new_A A

and then, if old_A can be abandoned entirely:

$ git branch -D old_A

or, equivalently, start with the branch delete, then rename new_A to A.

(Edit: see also git rebase --onto documentation, for the goal of rebasing A3, etc., onto the new_A branch.)

这篇关于Git:拉动重新设计的分支的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆