git - 从另一个分支 cherry-pick 到特定的提交

标签 git version-control

这可能吗 ?从其他分支 cherry-pick 到主分支的特定提交。
例如:
说,我有两个分支:

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

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

编辑 : 我知道可以通过 rebase 来完成命令,但可以通过 cherry-pick 完成只要?

最佳答案

您在思考 Git 的工作方式方面存在根本性错误。

Is this possible ? Cherry picking from other branch into specific commit of master branch.



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

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

绘制分支

Say, I've two branch:

-> 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 ,两个分支都从它延伸,表明在 E 之前可能有更早的提交。和 H .

请注意,每个提交都会记住其父提交:G 的父提交是 F ,所以我们说 G “点回”到 F . F点回 E , 指向 D , 等等。同样,提交 K点回 J指向 I指向 H .请注意 H ,仅在分支 test 上,也指向 D .

(Commit D 特别有趣:它在两个分支上。这也是 Git 所说的两个分支的 merge 基础。但这不是我们在这里关心的;这只是一个有趣的旁注,在 Git 中,提交可以是同时在多个分支上。)

分支名称,在本例中为 mastertest , 每个指向一个特定的提交。这里的名字master提交点数 G ,和名称 test提交点数 K .这就是我们如何决定哪些提交在哪些分支上:我们开始,就像 Git 一样,使用分支名称来查找分支提示提交。从这些提示提交,我们或 Git 向后工作:我们从任何一个提交,到其父提交,然后到该提交的父提交,依此类推。只有当我们厌倦了跟随 parent (例如,退出 git log ),或者被告知停止时,这个过程才会停止——尽管我们不会在这里看到——或者我们击中了一个根提交,这是一个没有 parent 。您在存储库中所做的第一次提交是根提交,因为没有更早的提交可以用作父提交。 (可以进行额外的 root 提交,但我们不会在这里看到。)

cherry-pick 提交

And now I want to cherry pick a commit (eg: <c3>) from test branch to a <commit2> in master branch.



你可以挑选一个提交,但我用粗斜体(“提交”)的部分是无稽之谈。 cherry-pick 意味着复制提交。该副本是一个新提交,您通常会将其添加到分支中。

由于您的 <c3>是我的 J ,让我们看看如果你使用会发生什么:
git checkout master
git cherry-pick test~1

第一步让你“进入”分支 master ,即您现在添加的新提交将添加到 master , 通过制作名称 master指向他们。

第二步标识提交Jtest的顶端向后走一步.姓名 test标识提交 K :分支名称“意味着”该分支的提示提交。 ~1后缀的意思是“计算一个父级”,所以我们从提交 K 开始提交 J .那就是我们要求 Git 复制的提交。

我们暂时将忽略执行此副本的确切机制,而只查看结果。 Git 进行了一个“类似”的新提交 J ;让我们称这个新提交 J' .与原来的J有几个区别和新副本J' ,目前重要的是副本的父级是 master 的现有提示。 ,即提交 G .所以J'点回 G .

复制完成后,新的 J'永久存储,Git 更新 master指向我们刚刚所做的新提交:
...--D--E--F--G--J'  <-- master
      \
       H--I--J--K   <-- test

请注意,现有提交不会受到影响。这是因为几乎不可能更改任何现有提交。

rebase

I know it can be done via rebase command ...



它不能,这确实很重要。 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分支,与 J'以后F ,然后复制 GG' , 与 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 ,并绘制 master在一条直线上,看起来我们已经插入了 J'之间FG ...但我们没有:我们复制了 GG' .
git rebase command 本质上是一个自动化的、高性能的“cherry pick a lot of commits”命令,最后是一些移动的分支名称。

为什么这一切都很重要

这只是有时很重要,但当它很重要时,它就很重要了。

假设我们从这个开始,这很像以前,除了还有另一个分支:
...--D--E--F--G   <-- master
      \        \
       \        L   <-- develop
        \
         H--I--J--K   <-- test

现在让我们复制 JJ' , 把它放在 F 之后,然后复制 GG'J'G'的父级,并命名为 master记住新提交的哈希 ID G' . (这与我们之前做的 rebase-with-copy 相同;我们只有这个额外的 develop 分支。)
             J'-G'  <-- master
            /
...--D--E--F--G
      \        \
       \        L   <-- develop
        \
         H--I--J--K   <-- test

现在让我们重新绘制它,以减少布局中的奇怪之处:
...--D--E--F--J'-G'  <-- master
      \     \
       \     G--L   <-- develop
        \
         H--I--J--K   <-- test

即使我们让 Git“忘记”了最初的提交 Gmaster赞成 Shiny 的新G'J'作为其父级,原始 G仍然在分支develop .事实上,现在看起来好像G一直在线 develop我们可能是精心挑选的 master从那里。

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

关于git - 从另一个分支 cherry-pick 到特定的提交,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43448971/

相关文章:

git - React native - 要将哪些文件添加到 GIT?

Git 日志 : fatal object [sha1] is corrupted

git - 由于未 merge 的文件,无法更改分支或提交。无法 merge 或 stash 文件,因为我在错误的分支中

svn - 将 Subversion 与 git 连接起来

git - fork GIT 子模块,并更改源 URL。但是 clone 仍然会 pull 旧的源 URL?

Git 保持远程分支(源)清洁

cocoa - 如何并行处理 Cocoa 应用程序和插件?

git - 更好的 git add -p?

python - 同一个类中的同名函数 - 有没有一种优雅的方法来确定调用哪个?

Git:获取当前分支曾经 merge 到的分支列表