这可能吗 ?从其他分支 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 中,提交可以是同时在多个分支上。)分支名称,在本例中为
master
和 test
, 每个指向一个特定的提交。这里的名字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
指向他们。第二步标识提交
J
从test
的顶端向后走一步.姓名 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
,然后复制 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
,并绘制 master
在一条直线上,看起来我们已经插入了 J'
之间F
和 G
...但我们没有:我们复制了 G
至 G'
.git rebase
command 本质上是一个自动化的、高性能的“cherry pick a lot of commits”命令,最后是一些移动的分支名称。为什么这一切都很重要
这只是有时很重要,但当它很重要时,它就很重要了。
假设我们从这个开始,这很像以前,除了还有另一个分支:
...--D--E--F--G <-- master
\ \
\ L <-- develop
\
H--I--J--K <-- test
现在让我们复制
J
至 J'
, 把它放在 F
之后,然后复制 G
至 G'
与 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“忘记”了最初的提交
G
在 master
赞成 Shiny 的新G'
有 J'
作为其父级,原始 G
仍然在分支develop
.事实上,现在看起来好像G
一直在线 develop
我们可能是精心挑选的 master
从那里。这里的关键是你可以复制提交并忘记原件在那里,但如果是这样,你必须确保你真的忘记了它们。 如果这些原件在别处是已知的——通过你自己存储库中的另一个分支,或者(更糟糕的)
git push
ed 到另一个存储库 - 如果这是您想要的,您必须让所有其他用户使用新版本。您无法更改原件,您只能将它们复制到新的并让每个用户切换到新的。
关于git - 从另一个分支 cherry-pick 到特定的提交,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43448971/