Cherry-pick来自其他分支的特定提交

时间:2017-04-17 09:42:10

标签: git version-control

这可能吗? Cherry从其他分支中挑选到master分支的特定提交。 例如: 说,我有两个分支:

 -> master : <commit1>, <commit2>, <commit3>
 -> test: <c1>, <c2>, <c3>, <c4>

现在我想从<c3>分支到主分支中的test挑选一个提交(例如:<commit2>)。

修改:我知道可以通过rebase命令完成,但是只能通过cherry-pick完成吗?

4 个答案:

答案 0 :(得分:12)

你对Git的工作方式有一个根本性的错误。

  

这可能吗? Cherry从其他分支机构挑选到主分支的特定提交。

否:Git 无法更改任何提交。您可以添加新提交,并且您可以复制现有提交以从中进行新提交,即添加新提交,该提交是现有提交的副本(据推测,副本中至少有一个不同的东西)。后者是git cherry-pick所做的。

您还可以更改任何分支名称为您记住的特定提交哈希ID。

绘制分支

  

说,我有两个分支:

-> master : <commit1>, <commit2>, <commit3>
-> test: <c1>, <c2>, <c3>, <c4>

这不是绘制分支的好方法。这是一个更好的方法:

...--D--E--F--G   <-- master
      \
       H--I--J--K   <-- test

此处的提交E对应于您的<commit1>,我只使用单个字母来缩短它们。同样,F与您的<commit2>类似,J就像您的<c3>。我还包括了另一个早期的提交D,两个分支都扩展了,提示可能在EH之前提交了早期的提交。

请注意,每个提交都会记住其提交:G的父级为F,因此我们说G&#34;指回&# 34;到FF指向E,指向D,依此类推。同样,提交K点回J,指向I,指向H。请注意H仅在分支test 上指向D

(提交D特别有趣:它位于两个分支。它也是Git称之为两个分支的合并基础。但是& #39;这不是我们关心的问题;它只是一个有趣的旁注,在Git中,提交可以同时在多个分支上。)

分支名称,在本例中为mastertest,每个都指向一个特定的提交。此处,名称master指向提交G,名称test指向提交K。这就是我们如何决定哪些提交在哪些分支上:我们开始,就像Git一样,使用分支名称来查找分支 tip 提交。从那些提交提交中,我们 - 或Git - 向后工作:我们从任何一个提交,到其父提交,然后到该提交的父级,依此类推。这个过程只有当我们厌倦了跟随父母(例如,退出git log)或被告知停止时才会停止 - 我们在这里看不到 - 或者我们点击 root < / em> commit,这是一个使用 no 父级的提交。您在存储库中进行的第一次提交是根提交,因为它没有可以用作父级的早期提交。 (它可以进行额外的root提交,但我们再次在这里看不到。)

Cherry-picking提交

  

现在我想从主分支中的测试分支 <c3> 中选择一个提交(例如:<commit2>)。 / p>

可以挑选一个提交,但我用粗体斜体(&#34;提交&#34;)的部分是无稽之谈。采摘樱桃意味着复制提交。该副本是 new 提交,您通常会将其添加到分支。

由于您的<c3>是我的J,因此,如果您使用以下内容,请查看会发生什么:

git checkout master
git cherry-pick test~1

第一步让你&#34; on&#34;分支master,即您现在添加的新提交将添加到master,方法是将名称master指向它们。

第二步通过从J的提示向后退一步来识别提交test。名称test标识提交K:分支名称&#34;表示&#34;该分支的提示提交。 ~1后缀表示&#34;倒数一个父级&#34;,因此我们从提交K转移到提交J。这就是我们要求Git复制的提交。

我们暂时忽略了执行此副本的确切机制,只看结果。 Git做了一个新的提交,就像&#34;喜欢&#34; J;让我们调用这个新的提交J'。原始J和新副本J'之间存在一些差异,目前最重要的一点是副本的是{{{ 1}},即提交master。因此G指向J'

复制完成后,永久存储新的G,Git会更新J'以指向我们刚刚提交的新提交:

master

请注意,不会影响现有提交。这是因为它确实不可能来改变任何现有的提交。

衍合

  

我知道可以通过...--D--E--F--G--J' <-- master \ H--I--J--K <-- test 命令...

完成

无法,这确实很重要。 rebase的作用不是 modify 提交。相反,它制作副本 - 可能是很多副本。

让我们考虑rebase上有D-E-F-G序列的情况,并且您希望复制master并在后插入 J之前的 F。也就是说,即使这是不可能的,你也希望得到这个:

G

不可能的原因是...--D--E--F--J'-G <-- master \ H--I--J--K <-- test 无法更改G已经指回G。但是,如果我们这样做了呢?

F

换句话说,如果我们将 J'-G' <-- new-master / ...--D--E--F--G <-- old-master \ H--I--J--K <-- test 复制到 J分支上J'new-master来自{{1}然后将J'复制到F,将G复制到G'之后?我们可以使用G'执行此操作,我们只需先选择两个提交,J'然后git cherry-pick,然后J一个新的分支:

G

并且,假设一旦我们完成了这项操作,我们完全删除旧的git checkout -b new-master master~1 # make the new-master branch at F git cherry-pick test~1 # copy J to J' git cherry-pick master # copy G to G' 名称,并调用新的master,如下所示:

master

现在,如果我们停止绘制已放弃的原始 J'-G' <-- master / ...--D--E--F--G [abandoned] \ H--I--J--K <-- test ,并以直线绘制G,则看起来像我们已插入masterJ'F之间......但我们没有:我们将G复制到G

G'命令本质上是一个自动化的,强大的&#34;樱桃选择很多提交&#34;命令,后面跟着一些分支名称移动到最后。

为什么这一切都很重要

这有时只会很重要,但是当它重要时,重要的是很多

我们假设我们从这开始,这很像以前,除了另外一个分支:

git rebase

现在让我们将...--D--E--F--G <-- master \ \ \ L <-- develop \ H--I--J--K <-- test 复制到J,然后将其J'复制,然后将F复制到G G' }作为J'的父级,并使名称G'记住新提交master的哈希ID。 (这与我们以前做过的rebase-with-copy相同;我们只有这个额外的G'分支。)

develop

现在让我们重新绘制一下,这样布局就不那么古怪了:

             J'-G'  <-- master
            /
...--D--E--F--G
      \        \
       \        L   <-- develop
        \
         H--I--J--K   <-- test

即使我们让Git忘了&#34;忘了&#34; ...--D--E--F--J'-G' <-- master \ \ \ G--L <-- develop \ H--I--J--K <-- test 上的原始提交G支持以master作为其父级的新G',原始J'仍位于分支{{1}上}}。事实上,现在好像G 总是develop上,我们可能会从那里把它挑选到G

这里的关键点是你可以复制提交并忘记原件是否在那里,但如果是这样,你必须确保真的忘记它们。如果那些原件在其他地方已知 - 通过您自己的存储库中的另一个分支,或者(更糟)develop到另一个存储库 - 您必须让所有其他用户使用新版本,如果这是您想要的。您无法更改原件,您只能将它们复制到新原件并让每个用户切换到新的原件。

答案 1 :(得分:1)

您将重新编写存储库历史记录,这不是建议的。

  • 首先,在master分支的必要提交中创建一个新分支。
  • 结帐新分行。
  • Cherry从测试中选择必要的提交 分支到新的分支。
  • Checkout master branch。
  • Rebase master分支 进入新的分支。

如果需要将主分支推送到远程存储库,则必须强制推送主分支。如果其他人已经签入了主分支,那么他们的主分支将通过这样做而失效。

答案 2 :(得分:0)

是的,您可以使用git cherry-pick <commit from test branch>将更改应用于master分支。

要从主分支上选择从测试分支到提交(不是最新)的提交,您可以使用以下方式:

git checkout <a commit on master you want to cherry pick>
git cherry-pick <a commit from test branch>
git rebase --onto HEAD <the commit you used in step1> master

答案 3 :(得分:0)

如果您想更改现有提交,可以将rebasecherry-pick结合使用。

GIT_SEQUENCE_EDITOR='sed -i s/^pick/edit/' git rebase -i <commit2>
git cherry-pick -n <c3>
git commit --amend -C HEAD
git rebase --continue

首先运行rebase来选择master上的提交进行编辑。然后它应用来自其他提交的更改,修改master上的提交,并完成rebase。当然,这并不是更改提交,但它会创建一个新的提交,其中包含<commit2><c3>的更改。

使用GIT_SEQUENCE_EDITOR只是避免在启动rebase时必须手动选择单个提交进行编辑。