我是Git的新手。
我创建了一个新的分支new_branch
。我已经在不同的分支old_branch
中完成了所有更改和提交。现在,我想通过git cherry-pick
从分支old_branch
选择一些提交到new_branch
。为此,我首先需要知道该分支中有哪些提交,然后选择它们并与new_branch
合并。
我该怎么做?
git checkout new_branch
git log old_branch
日志将在old_branch中显示每个提交,并在提交消息上方显示一个长字符串,如"cf5e845a13866239eb87f2593d6edc6e273decc5"。这是提交哈希。然后你可以进行
git cherry-pick <commit hash>
对于你想要的每一个承诺。我建议按照时间顺序来做(从底部开始计算日志)。
有很多方法可以实现这一点,下面是提交列表的两种方法:
git log --cherry new_branch..old_branch --oneline
将显示old_branch
中无法从old_branch
访问的所有提交。
或者另一种方式:
git checkout old_branch
git cherry new_branch --abbrev=6 -v
它将显示old_branch
中的提交(没有引入相同更改的提交),并将标记提交以指示它们是否具有-
,或者尚未在new_branch
中选择"+"。例如:
+2bdcd1 1st commit (Has not been cherry picked)
-8de6cc 2nd Commit (Has been cherry picked)
+8ac1ee 3nd Commit (Has not been cherry picked)
在任何一种情况下,您都可以使用
git cherry-pick <commit>
尽管在第二种情况下您希望签出"new_branch"。
@naomi给出的方法会很好地工作,但有一种更简单的方法。您的old_branch
分支从其他分支上的某个提交开始,如下所示:
A --- B --- C --- D <-- devel (let's say it's branch devel, anyway)
E - F - G - H <-- old_branch
您已经创建了一个分支new_branch
,它来自某个提交(可能是B、C或D),并且您想要挑选一些提交E、F、G和/或H(可能是一个更长的提交字符串,但这应该说明一些事情)。
通常,如果你想把一个未发布的工作序列(也许old_branch
就是这样一个序列)放在最新的(提交D)之上"移动它",你只需要做:
$ git checkout old_branch # get onto old_branch
$ git rebase devel # and rebase it onto commit D in "devel"
它所做的是制作E到H提交的"副本",并在"D"之后添加每个副本。然后,它剥离标签old_branch
(用于命名commit H),并将其粘贴到H的副本上,给出以下内容:
A --- B --- C --- D <-- devel
E' - F' - G' - H' <-- old_branch
E - F - G - H [abandoned, see footnote]
你想要的是选择一些提交,比如说C(无论你在上面创建了new_branch
),并做同样的事情,但而不是"剥离标签"old_branch
。此外,您需要选择E、F、G和H中的哪一个。完成后,您希望添加标签new_branch
。这其实很容易。不是在提交C处创建分支new_branch
,而是在提交H处创建它,old_branch
:的头
$ git checkout old_branch; git checkout -b new_branch
现在new_branch
和old_branch
在内容方面是相同的,但具有不同的名称。
现在,您可以简单地将rebase -i
(交互式,让您选择)new_branch
放到您想要的点上。我在这里一直假设提交C
,我一直假设它距离名为devel
的分支提示后退了一步,所以我将使用它运行:
$ git rebase -i --onto devel~1 devel new_branch
在您选择rebase -i
允许的方式(并解决删除某些提交和git rebase --continue
在解决后继续的任何冲突)后,您将得到这样的结果,这取决于您执行的提交和删除的提交。我假设你删除F,但保留其余部分:
A --- B --- C --- D <-- devel
E' - G' - H' <-- new_branch
E - F - G - H <-- old_branch
实际上,只需两个命令就可以完成这一切(与上面的3相比),因为git branch
可以在与old_branch
相同的点创建new_branch
。此外,您可能希望将rebase -i
添加到任何分支的尖端上,也就是说,与其将--onto devel~1
重新定基,不如将其重新定基到(的尖端)devel
上。在这种情况下,您根本不需要--onto
部件:
$ git branch new_branch old_branch
$ git rebase -i devel new_branch
这里的结果几乎和以前一样,只是现在提交E’从D而不是C:
A --- B --- C --- D <-- devel
E' - G' - H' <-- new_branch
E - F - G - H <-- old_branch
这基本上就是我在修改未发布的更改时所做的。如果我在(比如)分支revise
上,我将其重命名为revise-0
,在同一位置创建一个新的revise
,然后rebase -i
并稍微清理一下。经过一次之后,我可能会决定再次修改它,所以我将revise
重命名为revise-1
,并在与revise-1
相同的位置创建一个新的revise
,然后再次创建rebase -i
,等等。如果我想要它们,我所有的旧刺都还在,直到我决定不想要它们;然后我删除所有-0-1-2。。。姓名。
脚注:上面标记为"已放弃"的提交仍然存在——它们通过reflog保留以防止垃圾收集——但最终reflog条目过期,它们在git gc
中消失。在那之前,它们大多是不可见的:例如,git log --all
和gitk --all
不会显示它们。您可以使用--reflog
运行这些命令,但即使在没有分支标签的情况下,它们仍然有点难以找到。我喜欢把它们挂一段时间,因此上面有多个分支名称的工作流。