这可能吗? Cherry从其他分支中挑选到master分支的特定提交。 例如: 说,我有两个分支:
-> master : <commit1>, <commit2>, <commit3>
-> test: <c1>, <c2>, <c3>, <c4>
现在我想从<c3>
分支到主分支中的test
挑选一个提交(例如:<commit2>
)。
修改:我知道可以通过rebase
命令完成,但是只能通过cherry-pick
完成吗?
答案 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
,两个分支都扩展了,提示可能在E
和H
之前提交了早期的提交。
请注意,每个提交都会记住其父提交:G
的父级为F
,因此我们说G
&#34;指回&# 34;到F
。 F
指向E
,指向D
,依此类推。同样,提交K
点回J
,指向I
,指向H
。请注意H
仅在分支test
, 上指向D
。
(提交D
特别有趣:它位于两个分支。它也是Git称之为两个分支的合并基础。但是& #39;这不是我们关心的问题;它只是一个有趣的旁注,在Git中,提交可以同时在多个分支上。)
分支名称,在本例中为master
和test
,每个都指向一个特定的提交。此处,名称master
指向提交G
,名称test
指向提交K
。这就是我们如何决定哪些提交在哪些分支上:我们开始,就像Git一样,使用分支名称来查找分支 tip 提交。从那些提交提交中,我们 - 或Git - 向后工作:我们从任何一个提交,到其父提交,然后到该提交的父级,依此类推。这个过程只有当我们厌倦了跟随父母(例如,退出git log
)或被告知停止时才会停止 - 我们在这里看不到 - 或者我们点击 root < / em> commit,这是一个使用 no 父级的提交。您在存储库中进行的第一次提交是根提交,因为它没有可以用作父级的早期提交。 (它可以进行额外的root提交,但我们再次在这里看不到。)
现在我想从主分支中的测试分支 到
<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
,则看起来像我们已插入master
在J'
和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)
您将重新编写存储库历史记录,这不是建议的。
如果需要将主分支推送到远程存储库,则必须强制推送主分支。如果其他人已经签入了主分支,那么他们的主分支将通过这样做而失效。
答案 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)
如果您想更改现有提交,可以将rebase
与cherry-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时必须手动选择单个提交进行编辑。