如何解决 "added by us" git cherry-pick 冲突?
How to resolve "added by us" git cherry-pick conflict?
我 运行 遇到了 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"
现在让我们对 b运行ch-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 的提交。
如何正确解决 cherry-pick 冲突由我们添加并最终导致我得到这 3 个提交在我的主人 b运行ch ?
- rm myFooFile 添加 myBarFile
- git mv myFooFile myBarFile
- 首先提交添加 myFooFile
myBarFile 包含 bar ?
注意:我知道我可以在 git 冲突解决期间使用 git checkout branch-a -- myBarFile
但这不是我正在寻找的解决方案,因为我认为这不是 git 方式这样做。
未成年人:不要这样做:
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 没有找到实际的合并基础,只是使用提交的父级您正在挑选合并基础(当然,最终提交是常规的非合并提交)。
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 会在索引中保留所有三个 "interesting" 文件——但可能会丢失一两个这样的文件(就像这里的情况一样)。 git status
命令将这些显示为 "unmerged",但您可以使用 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
这是"what we changed": 重命名操作。
$ 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
这是"what they changed":删除一个文件,添加另一个。
Git 现在负责将 myFooFile
重命名为 myBarFile
(内容为 foo
),同时在创建时删除 myFooFile
myBarFile
内容为 bar
.
不可能两者都做,所以我们发生了冲突。同时它 可以 进行我们所做的重命名,所以它确实在工作树中(仅)进行了重命名,留下 myBarFile
包含 foo
.
你想知道:
How to properly fix the cherry-pick conflict added by us and end-up ... With myBarFile containing bar ?
所有 Git 需要的是您向工作树写入包含您想要的内容的 myBarFile
版本,然后调整索引以便条目它处于零阶段。目前,索引中的内容是:
$ git ls-files --stage
100644 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 2 myBarFile
和myBarFile
有您不想要的内容。
Note: I known that I could use git checkout branch-a -- myBarFile
during git conflict resolution ...
是:从 branch-a
标识的提交中提取 myBarFile
的版本,在第 0 阶段将其写入索引,在第 2 阶段删除条目,并为提交做好一切准备. (作为奖励,它还将文件写入工作树,以便您可以看到它,尽管此时 Git 实际上并不关心工作树版本。)所以这是一个很好的快速方法达到你想要的结果的方法。不过,我们可以看看另一种方法,它在某些情况下可能会有用:
[but] I don't think it's the git way of doing it.
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
)。
我 运行 遇到了 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"
现在让我们对 b运行ch-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 的提交。
如何正确解决 cherry-pick 冲突由我们添加并最终导致我得到这 3 个提交在我的主人 b运行ch ?
- rm myFooFile 添加 myBarFile
- git mv myFooFile myBarFile
- 首先提交添加 myFooFile
myBarFile 包含 bar ?
注意:我知道我可以在 git 冲突解决期间使用 git checkout branch-a -- myBarFile
但这不是我正在寻找的解决方案,因为我认为这不是 git 方式这样做。
未成年人:不要这样做:
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 没有找到实际的合并基础,只是使用提交的父级您正在挑选合并基础(当然,最终提交是常规的非合并提交)。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 会在索引中保留所有三个 "interesting" 文件——但可能会丢失一两个这样的文件(就像这里的情况一样)。
git status
命令将这些显示为 "unmerged",但您可以使用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
这是"what we changed": 重命名操作。
$ 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
这是"what they changed":删除一个文件,添加另一个。
Git 现在负责将 myFooFile
重命名为 myBarFile
(内容为 foo
),同时在创建时删除 myFooFile
myBarFile
内容为 bar
.
不可能两者都做,所以我们发生了冲突。同时它 可以 进行我们所做的重命名,所以它确实在工作树中(仅)进行了重命名,留下 myBarFile
包含 foo
.
你想知道:
How to properly fix the cherry-pick conflict added by us and end-up ... With myBarFile containing bar ?
所有 Git 需要的是您向工作树写入包含您想要的内容的 myBarFile
版本,然后调整索引以便条目它处于零阶段。目前,索引中的内容是:
$ git ls-files --stage
100644 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 2 myBarFile
和myBarFile
有您不想要的内容。
Note: I known that I could use
git checkout branch-a -- myBarFile
during git conflict resolution ...
是:从 branch-a
标识的提交中提取 myBarFile
的版本,在第 0 阶段将其写入索引,在第 2 阶段删除条目,并为提交做好一切准备. (作为奖励,它还将文件写入工作树,以便您可以看到它,尽管此时 Git 实际上并不关心工作树版本。)所以这是一个很好的快速方法达到你想要的结果的方法。不过,我们可以看看另一种方法,它在某些情况下可能会有用:
[but] I don't think it's the git way of doing it.
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
)。