我在使用git时遇到了问题,在一次樱桃挑选后的冲突解决过程中。问题涉及对先前提交中git mv
的文件进行的修改。
以下是重现完整命令的示例:
mkdir git_repository && cd git_repository
git init
echo "foo" > myFooFile
git add myFooFile
git commit -m "First commit add myFooFile"
git checkout -b branch-a
rm myFooFile
echo "bar" > myBarFile
git add -A
git commit -m "rm myFooFile add myBarFile"
git checkout master
git mv myFooFile myBarFile
git add -u
git commit -m "git mv myFooFile myBarFile"
现在让我们在branch-a
上进行修改git cherry-pick $(git show-ref branch-a)
>error: could not apply 70c80f3... rm myFooFile add myBarFile
>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'
以下是冲突:
git status
>On branch master
>You are currently cherry-picking commit 70c80f3.
> (fix conflicts and run "git cherry-pick --continue")
> (use "git cherry-pick --abort" to cancel the cherry-pick operation)
>
>Unmerged paths:
> (use "git add <file>..." to mark resolution)
>
> added by us: myBarFile
>
>no changes added to commit (use "git add" and/or "git commit -a")
不幸的是,执行git add myBarFile
然后git cherry-pick --continue
不是解决方案,因为它会创建一个空提交。
在解析期间使用git rm myBarFile
并不是更好,因为它会创建一个从myBarFile中删除foo的提交。
如何正确修复由我们添加的 的挑选冲突,并在我的主分支上获得这3次提交的情况下结束?
myBarFile包含栏?
注意:我知道我可以在git冲突解决期间使用git checkout branch-a -- myBarFile
,但这不是我正在寻找的解决方案,因为我不认为这是做这件事的好方法。
答案 0 :(得分:1)
轻微:不要这样做:
git cherry-pick $(git show-ref branch-a)
请改为:
git cherry-pick branch-a
cherry-pick命令采用标识修订版本甚至修订版本范围的任何内容,如the gitrevisions documentation中所述。 git show-ref
命令输出哈希ID 和的名称,因此这会尝试两次提交提交。 (幸运的是git cherry-pick
非常聪明,可以消除额外的费用。)
没有一种正确的方法可以解决冲突。你可以使用任何你喜欢的东西。这里要记住几件重要的事情:
Cherry-picking本质上是一个三向合并la git merge
,除了不是找到实际的合并基础,Git只使用你正在挑选的提交的父级作为合并base(当然,最后的提交是一个常规的非合并提交)。
Git不跟踪文件名更改。相反,当进行合并操作时 - 包括一个cherry-pick-Git本质上运行两个git diff
命令:
git diff --find-renames <merge-base> HEAD # figure out what we did
git diff --find-renames <merge-base> <other> # figure out what they did
如果结果是合并冲突,Git会在索引中留下所有三个“有趣”的文件 - 但是可能会丢失一两个这样的文件(就像这里的情况一样)。 git status
命令将这些显示为“未合并”,但您可以使用git ls-files --stage
查找完整详细信息。我稍后会详细说明。
此时,您的工作只是在索引中安排您在最终提交时所需的文件,这是合并的结果(或者在本例中为cherry-pick)。这些文件需要处于零阶段,这是正常的,未冲突的文件存在于索引中的位置。第1阶段的任何条目表示合并库中文件的版本,第2阶段的任何条目表示HEAD
提交中的文件版本,第3阶段的任何条目表示另一个提交中的文件版本你正在和(或采摘樱桃)合并。
所以,让我们看看git diff --find-renames
找到了什么,知道合并基础是被挑选的提交的父级。我们可以使用名称branch-a
来识别cherry-pick提交。因此,它的父级是branch-a^
(再次参见gitrevisions文档)。
$ git diff --find-renames branch-a^ HEAD
diff --git a/myFooFile b/myBarFile
similarity index 100%
rename from myFooFile
rename to myBarFile
这是“我们改变了什么”:重命名操作。
$ git diff --find-renames branch-a^ branch-a
diff --git a/myBarFile b/myBarFile
new file mode 100644
index 0000000..5716ca5
--- /dev/null
+++ b/myBarFile
@@ -0,0 +1 @@
+bar
diff --git a/myFooFile b/myFooFile
deleted file mode 100644
index 257cc56..0000000
--- a/myFooFile
+++ /dev/null
@@ -1 +0,0 @@
-foo
这是“他们改变了什么”:删除一个文件,添加另一个文件。
Git现在负责将myFooFile
重命名为myBarFile
(内容为foo
),同时在创建myFooFile
的同时删除myBarFile
内容bar
。
它不可能同时做到,所以我们会发生冲突。同时它可以执行我们所做的重命名,因此它确实在工作树中执行此操作(仅限),使myBarFile
包含foo
。
你想知道:
如何正确修复我们添加的挑选冲突并结束...使用myBarFile包含栏?
所有Git需求都是您在工作树中编写包含所需内容的myBarFile
版本,然后调整索引以使其条目位于零阶段。目前,索引中的内容是:
$ git ls-files --stage
100644 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 2 myBarFile
和myBarFile
包含您不想要的内容。
注意:我知道我可以在git冲突解决期间使用
git checkout branch-a -- myBarFile
...
是:从myBarFile
标识的提交中提取branch-a
的版本,将其写入第0阶段的索引,在第2阶段删除条目,并使所有内容都准备好进行提交。 (作为奖励,它还将文件写入工作树,以便您可以看到它,尽管此时Git实际上并不关心工作树版本。)所以这是一个很好的快速实现方法期望的结果。不过,我们可以看一下另一种方法,它在某些情况下可能会有用:
[但]我不认为这是做这件事的好方法。
Git没有 a (单一)方式。 Git是一个工具。根据您的喜好使用它。如果您希望在未先触摸索引的情况下调整工作树内容,则可以使用git show
提取文件的branch-a
版本:
$ git show branch-a:myBarFile > tmp
$ cat tmp
bar
$ mv tmp myBarFile
$ git add myBarFile
如果我们检查实际的临时区域,我们会发现:
$ git ls-files --stage
100644 5716ca5987cbf97d6bb54920bea6adde242d87e6 0 myBarFile
这就是我们想要的,所以我们现在可以git cherry-pick --continue
或git commit
来完成这个挑选:
$ git cherry-pick --continue
此时,首选编辑器应在包含主题rm myFooFile add myBarFile
的消息文件和其他数据上打开(因为这是您正在挑选的提交)。写出来的结果是:
[master 1837c17] rm myFooFile add myBarFile
Date: Fri Jun 15 22:21:48 2018 -0700
1 file changed, 1 insertion(+), 1 deletion(-)
和git log --oneline
显示您想要的内容:
1837c17 (HEAD -> master) rm myFooFile add myBarFile
a30b874 git mv myFooFile myBarFile
bde7df5 First commit add myFooFile
(注意:我的配置中有log.decorate = auto
。)