让樱桃挑选不带来历史 [英] Make Cherry Pick not bring in history
问题描述
所以我遇到了一个git的问题,当我选择rebase或cherry选择一个特定的提交时,我将获得比该特定提交更多的信息。这个问题在这个问题中很好地概括了:
这一切都很好,我知道它正在酝酿历史,因为我想要的提交取决于那里的历史。我没有得到的是如何解决它。我真的不希望樱桃选择应用所有这些历史,我更愿意用它来利用这段历史找出线路应该去的地方,然后引发冲突,说它必须按顺序做点什么以使其适合。
有没有办法让我这样做?我发现的唯一方法是我可以从该提交中制作一个补丁并应用该补丁,但是我真的希望能够为我的树使用樱桃挑选和重建。
为了说明我的例子,你可以在一个空目录中创建一个git仓库,然后添加一行文本文件到你的仓库。然后在3个独立的提交中添加3行到文件,所以你的文件中将有4个提交和4行。我的档案看起来像:
第1行
第2行
第3行
第4行
现在执行git checkout HEAD〜3,以便只有
第1行
然后调用git cherry-挑头,你会得到一个冲突。为什么会发生这种情况在我上面发布的链接中列出。您的文件将如下所示:
line 1
<<<<<<<<<<<<<<<<< ; HEAD
=======
line 2
line 3
line 4
>>>>>> > 6fe905b ...提交4
但是这很糟糕,因为如果这真的出现了,合并冲突是说第四次提交的内容比第四次提交的内容要多得多。那么我有什么方法可以解决它吗?这样,挑选合适的内容会给我一个更合理的合并冲突?在我现实世界的问题上,这是即将发生的,当我正在做一个rebase时发生。如果我可以解决这个问题,我的逻辑是这个问题的根本原因应该可以解决rebase。 解决方案
[注:编辑后添加 diff3
,重新编辑该问题;看最底部的部分]
cherry-pick
命令使用一个列表作为参数提交ID:
git cherry-pick [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]< commit> ...
但是你说你正在使用:
git cherry-pick分支名称commit-hash
这意味着你要求git选择两个樱桃:一个与命名分支的尖端相关的樱桃(SHA-1 ID branch-name
resolves),以及与给定 commit-hash
关联的那个。
换句话说,先运行它:
git rev-list --no-步骤分支名称提交哈希
来自 当你让一个本地分支做一些工作时(提交 (然后你看看提交 (当地主人现在是最新的,现在你决定改变分支 Rebase基本上是一个自动化的重复樱桃选择直到完成,然后更改分支标签操作。鉴于上面提到的提交图,它首先执行分离 - [开始] [step 1,get 如果需要,重复的樱桃挑选序列将停止(伴随合并冲突),但如果是这样,它会将文件保留在 本质上,两者之间的巨大差异n 在解释diff问题的问题中的新示例稍微打破了:当 rev-list
时,然后尝试是什么
cherry-pick
see有效。
git rebase
可以做更多的事情大于 git cherry-pick
。通常情况下,人们通过这种方式将分支机构(这是我刚刚制作的一个术语)从一点移到另一点: C> A - B - C - D - E < - 原产地/主产地
\
K - L < - 本地
K
和 L on
local
),同时别人自己做了工作(提交 D
和
E
),并且您决定要将您的本地
分支重新定位在他们的工作之上,所以你可以这样做:
git fetch
D
和 E
,所以你想让你的本地 master 最新):
git checkout master
git merge --ff-only origin / master
local
):
git checkout local
git rebase master
HEAD
git checkout
以提交 E
,那么它会执行 K
的 git cherry-pick
,重复提交 L
,并且(如果一切顺利的话)最后调整本地分支标签 local
指向最后一项新的挑选提交:
A - B - C - D - E - - 主,原产地/主产地
\
K - L < - HEAD =当地
HEAD
直接设置为 E
,然后选择一个 K
的副本,给出:]
A - B - C - D - E - - 主,原产地/主产品
\ \
\ K'< - HEAD [分离]
\
K - L < - 本地
<步骤2,选择 L
的副本,给出:]
A - B - C-D -E < - 主,原产地/主产地
\ $
\ K'-L'< - 顶头[分离]
\
K - L < - 本地
<使用樱桃挑选顺序,移动标签, ]
A - B - C - D - E < - master,origin / master
\ \\ \\
\ K'-L'< - HEAD = local
\
K - L < - [no label,abandoned]
.git
目录来记住它正在做什么以及它到底有多远,以便您可以运行 git rebase --continue
在你解决问题后。
cherry-pick
和 rebase
为:
$当询问
git时,
提交提交; cherry-pick
使用 - no-walk
rev-list rebase
散步提交(尽管 rebase
将参数洗牌,因此您不能只运行 git rev -list
以这种方式提前查看它们)。
$ b
$ b HEAD
将引用ID为 master〜3
的提交点。但是 cherry-pick master
可以做到这一点。下面是一个例子,我将 merge.conflictstyle
设置为 diff3
,以便您可以看到<$ c $的具体细节
$ echo'line 1'> c> cherry-pick
档案&& git add file&& git commit -m'用1行添加文件'
[master 72f46c5]用1行添加文件
1个文件改变,1个插入(+)
创建模式100644文件
$ echo'line 2'>>档案&& git add file&& git commit -m'add line 2'
[master 134cdd1] add line 2
1 file changed,1 insertion(+)
$ echo'line 3'>>档案&& git add file&& git commit -m'add line 3'
[master e8634fc] add line 3
1 file changed,1 insertion(+)
$ echo'line 4'>>档案&& git add file&& git commit -m'add line 4'
[master 50810b6] add line 4
1 file changed,1 insertion(+)
$ git checkout master〜3
...
HEAD现在在72f46c5 ...用1行添加文件
$ git config merge.conflictstyle diff3
$ git cherry-pick master
error:could not apply 50810b6 .. 。添加第4行
提示:在解决冲突之后,标记修正的路径
提示:用'git add<路径>'或'git rm<路径>'
提示:和用'git commit'提交结果
$ cat file
line 1
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< HEAD
|||||||父母50810b6 ...添加行4
行2
行3
=======
行2
行3
行4
>>>>>>> 50810b6 ...添加第4行
有些像 diff3
style足够 git config --global
(我仍然在考虑这个:-))。
So I've run into an issue with git where when I rebase or cherry pick a specific commit, I will get much more information than is in that specific commit. That issue is outlined really nicely in this question here:
Am I misunderstanding git cherry-pick?
And that is all well and good, I understand that it is picking up history because the commit I want depends on that history being there. What I don't get is how to get around it. I really don't want cherry pick to apply all of that history, what I would much rather is for it to use that history to figure out where the lines should go and then raise a conflict saying that it had to do something fishy in order to make it fit.
Is there any way for me to do this? The only way I have found is I can make a patch out of that commit and apply the patch, but I really want to be able to use cherry-pick and rebase for my trees.
To illustrate my example, you can iniitalize a git repository in an empty directory then add a text file with 1 line to your repository. Then add 3 more lines to the file in 3 seperate commits, so you will have 4 commits and 4 lines in your file. My file lookes like:
line 1
line 2
line 3
line 4
Now do git checkout HEAD~3 so that you have only
line 1
Then call git cherry-pick HEAD and you will get a conflict. Why this happens is outlined in the link I posted above. Your file will look like this:
line 1
<<<<<<< HEAD
=======
line 2
line 3
line 4
>>>>>>> 6fe905b... Commit 4
But this is bad because if this comes up in a real example, your merge conflict is saying that Commit 4 had Much more stuff than was actually in Commit 4. So is there any way for me to fix it so that cherry-pick will give me a more logical merge conflict? In my real world issue where this is coming up, it's occuring when I am doing a rebase. If I can fix this for cherry-pick, my logic is that the underlying cause for this should be fixable for rebase as well.
[Note: edited to add diff3
, re the latest edit to the question; see bottom-most section]
The cherry-pick
command takes, as its arguments, a list of commit IDs:
git cherry-pick [--edit] [-n] [-m parent-number] [-s] [-x] [--ff] <commit>...
But you say you are using:
git cherry-pick branch-name commit-hash
That means you're asking git to pick two cherries: the one associated with the tip of the named branch (the SHA-1 ID to which branch-name
resolves), and the one associated with the given commit-hash
.
To put it another way, run this first:
git rev-list --no-walk branch-name commit-hash
The output from rev-list
is what cherry-pick
"sees", in effect.
git rebase
does something rather more extensive than git cherry-pick
. Typically, people run this to move a "branch arm" (this is a term I just made up) from one point to another:
A - B - C - D - E <-- origin/master
\
K - L <-- local
This kind of situation arises all the time when you make a local branch to do some work (commits K
and L
on local
), and meanwhile someone else does their own work (commits D
and E
on master) and you decide you want to "re-base your local
branch" on top of their work, so you do something like:
git fetch
(then you look around and see commits D
and E
, so you want to bring your local master
up to date):
git checkout master
git merge --ff-only origin/master
(local master now up to date, now you decide to rebase branch local
):
git checkout local
git rebase master
Rebase is basically an automated "repeatedly cherry-pick until done, then change branch labels" operation. Given the commit graph I drew above, it starts by doing a detached-HEAD
git checkout
to get to commit E
, then it does a git cherry-pick
of commit K
, repeats for commit L
, and (if all goes well) finally adjusts the local branch label local
to point to the last of the new cherry-picked commits:
[start]
A - B - C - D - E <-- master, origin/master
\
K - L <-- HEAD=local
[step 1, get HEAD
set directly to E
and then cherry-pick a copy of K
, giving:]
A - B - C - D - E <-- master, origin/master
\ \
\ K' <-- HEAD [detached]
\
K - L <-- local
[step 2, cherry-pick a copy of L
, giving:]
A - B - C - D - E <-- master, origin/master
\ \
\ K'-L' <-- HEAD [detached]
\
K - L <-- local
[done with cherry pick sequence, move label, giving:]
A - B - C - D - E <-- master, origin/master
\ \
\ K'-L' <-- HEAD=local
\
K - L <-- [no label, abandoned]
The repeated cherry-pick sequence will stop (with a merge conflict) if needed, but if so, it leaves files in the .git
directory to remember what it was doing and how far along it had gotten, so that you can run git rebase --continue
after you fix the problem.
Essentially, the two big differences between cherry-pick
and rebase
are:
cherry-pick
uses--no-walk
when askinggit rev-list
for the commits to pick up;rebase
walks commits (thoughrebase
shuffles arguments around so you can't just rungit rev-list
to see them in advance this way).cherry-pick
never moves branch labels;rebase
does when done.
The new example in the question for illustrating the diff issue is slightly broken: when you git checkout HEAD~3
and then try to git cherry-pick HEAD
, HEAD
will refer to the commit whose ID is master~3
at that point. But cherry-pick master
will do the trick. Here's an example where I set merge.conflictstyle
to diff3
so that you can see the specifics of what cherry-pick
is applying:
$ 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
Some like the diff3
style enough to git config --global
(I'm still considering this myself :-) ).
这篇关于让樱桃挑选不带来历史的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!