所以我遇到了一个git的问题,当我重新定义或者选择一个特定的提交时,我将获得比该特定提交更多的信息。这个问题在这个问题中得到了很好的概述:
Am I misunderstanding git cherry-pick?
这一切都很好,我明白它正在汲取历史,因为我想要的提交取决于那里的历史。我没有得到的是如何解决它。我真的不希望樱桃选择应用所有这些历史,我更愿意使用该历史来确定线应该去哪里然后引发冲突说它必须做一些有点腥使它适合。
我有什么方法可以做到这一点吗?我找到的唯一方法是我可以通过该提交制作补丁并应用补丁,但我真的希望能够为我的树使用cherry-pick和rebase。
为了说明我的示例,您可以在空目录中保存git存储库,然后将1行文本文件添加到存储库。然后在3个单独的提交中向文件中再添加3行,这样您的文件中将有4个提交和4行。我的文件看起来像:
line 1
line 2
line 3
line 4
现在执行git checkout HEAD~3,这样你只有
line 1
然后调用git cherry-pick HEAD,你就会发生冲突。为什么会发生这种情况,请参阅我上面发布的链接。您的文件将如下所示:
line 1
<<<<<<< HEAD
=======
line 2
line 3
line 4
>>>>>>> 6fe905b... Commit 4
但这很糟糕,因为如果这出现在一个真实的例子中,你的合并冲突就是说Commit 4有比实际在Commit 4中更多的东西。所以有什么方法让我修复它以便樱桃 - 挑选会给我一个更合乎逻辑的合并冲突?在我的现实世界问题即将到来的时候,当我正在做一次改变时,它就出现了。如果我可以解决这个问题,那么我的逻辑是,这个问题的根本原因也应该适用于rebase。
答案 0 :(得分:2)
[注意:编辑后添加diff3
,重新编辑问题;见最底部]
cherry-pick
命令将提交ID的列表作为其参数:
git cherry-pick [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]&lt; commit&gt; ...
但你说你正在使用:
git cherry-pick branch-name commit-hash
这意味着你要求git选择两个 cherries:与命名分支的提示相关联的一个(branch-name
解析的SHA-1 ID),以及与给定commit-hash
相关联的一个。
换句话说,首先运行:
git rev-list --no-walk branch-name commit-hash
rev-list
的输出是cherry-pick
“看到”的效果。
git rebase
做的事情比git cherry-pick
更广泛。通常情况下,人们通过此操作将“分支机构”(这是我刚刚编写的术语)从一个点移动到另一个点:
A - B - C - D - E <-- origin/master
\
K - L <-- local
当你让一个本地分支做一些工作(在K
上提交L
和local
),同时其他人做自己的工作时,会出现这种情况(在主人身上提交D
和E
)并且您决定要在他们的工作之上“重新建立local
分支”,所以您可以执行以下操作:
git fetch
(然后你环顾四周看看提交D
和E
,所以你想让你的本地master
更新:
git checkout master
git merge --ff-only origin/master
(本地主人现在是最新的,现在你决定改变分支local
):
git checkout local
git rebase master
Rebase基本上是一个自动化的“反复樱桃挑选,直到完成,然后更改分支标签”操作。鉴于我在上面提到的提交图,它首先执行一个分离的 - HEAD
git checkout
来提交E
,然后它执行git cherry-pick
提交K
重复提交L
,并且(如果一切顺利)最后调整本地分支标签local
以指向最后一个新挑选的提交:
[开始]
A - B - C - D - E <-- master, origin/master
\
K - L <-- HEAD=local
[第1步,将HEAD
直接设置为E
,然后挑选K
的副本,给予:]
A - B - C - D - E <-- master, origin/master
\ \
\ K' <-- HEAD [detached]
\
K - L <-- local
[第2步,樱桃挑选L
的副本,给予:]
A - B - C - D - E <-- master, origin/master
\ \
\ K'-L' <-- HEAD [detached]
\
K - L <-- local
[完成樱桃采摘序列,移动标签,给予:]
A - B - C - D - E <-- master, origin/master
\ \
\ K'-L' <-- HEAD=local
\
K - L <-- [no label, abandoned]
如果需要,重复的Cherry-pick序列将停止(合并冲突),但如果需要,它会将文件留在.git
目录中以记住它正在做什么以及它已经走了多远,所以修复问题后,您可以运行git rebase --continue
。
基本上,cherry-pick
和rebase
之间的两个巨大差异是:
cherry-pick
提交提交内容时,--no-walk
使用git rev-list
; rebase
遍历提交(虽然rebase
随机播放参数,但您不能只运行git rev-list
以提前查看它们。)cherry-pick
永远不会移动分支标签; rebase
完成后即可完成。问题中用于说明差异问题的新示例略有不同:当您git checkout HEAD~3
然后尝试git cherry-pick HEAD
时,HEAD
将引用ID为{{的提交1}}那时候。但是master~3
会做到这一点。以下是我将cherry-pick master
设置为merge.conflictstyle
的示例,以便您可以查看diff3
正在应用的具体内容:
cherry-pick
有些像$ echo 'line 1' > file && git add file && git commit -m 'add file with 1 line'
[master 72f46c5] add file with 1 line
1 file changed, 1 insertion(+)
create mode 100644 file
$ echo 'line 2' >> file && git add file && git commit -m 'add line 2'
[master 134cdd1] add line 2
1 file changed, 1 insertion(+)
$ echo 'line 3' >> file && git add file && git commit -m 'add line 3'
[master e8634fc] add line 3
1 file changed, 1 insertion(+)
$ echo 'line 4' >> file && git add file && git commit -m 'add line 4'
[master 50810b6] add line 4
1 file changed, 1 insertion(+)
$ git checkout master~3
...
HEAD is now at 72f46c5... add file with 1 line
$ git config merge.conflictstyle diff3
$ git cherry-pick master
error: could not apply 50810b6... add line 4
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and commit the result with 'git commit'
$ cat file
line 1
<<<<<<< HEAD
||||||| parent of 50810b6... add line 4
line 2
line 3
=======
line 2
line 3
line 4
>>>>>>> 50810b6... add line 4
样式足以diff3
(我现在还在考虑这个:-))。
答案 1 :(得分:0)
运行git rebase
和git cherry-pick
的相应结果通常不相同。
运行git rebase
通常会重写历史记录,并且可以显示移动整个分支。这可能是您所看到的不受欢迎的历史的来源。
相反,git cherry-pick
会重置存储库历史记录中其他位置的一个或多个提交的增量。典型的用例是挑选一个提交来创建另一个新提交。我需要了解有关您正在运行的命令的更多具体信息,以了解您可能会对结果感到沮丧。
将多提交主题分支压缩为单个提交的有用命令是git merge --squash
。另一种选择是反转,然后是另一种互动反转。