主分支:
lark 分支:
rebase 后 奇怪了!lark_file 在哪里?嗯,应该有三个文件(init、main_file、lark_file),对吧?
创建环境的脚本。
#!/bin/env bash
git init
touch init
git add -- .
git commit -am init
echo a >> main_file
git add --all
git commit -am 'main a'
echo b >> main_file
git commit -am 'main b'
echo c >> main_file
git commit -am 'main c'
echo d >> main_file
git commit -am 'main d'
echo e >> main_file
git commit -am 'main e'
git checkout HEAD~5
git checkout -B lark
echo a >> lark_file
git add --all
git commit -am 'lark a'
echo b >> lark_file
git commit -am 'lark b'
echo c >> lark_file
git commit -am 'lark c'
echo d >> lark_file
git commit -am 'lark d'
echo e >> lark_file
git commit -am 'lark e'
echo f >> lark_file
git commit -am 'lark f'
最佳答案
TL;DR:由于 rebase 的重命名检测,Git 正在将更改应用于错误的文件。 (不需要 --onto
标志来获得此效果。您只需要有一个 diff,其中 Git 会生成错误/不正确的重命名。)
长
首先,让我稍微修改一下您的重现器,以便每个人都可以使用它:
$ cat repro.sh
#! /bin/sh -e
mkdir t
cd t
git init
touch init
git add -- .
git commit -am init
echo a >> main_file
git add --all
git commit -am 'main a'
echo b >> main_file
git commit -am 'main b'
git tag tag-onto
echo c >> main_file
git commit -am 'main c'
echo d >> main_file
git commit -am 'main d'
echo e >> main_file
git commit -am 'main e'
git checkout HEAD~5
git checkout -B lark
echo a >> lark_file
git add --all
git commit -am 'lark a'
echo b >> lark_file
git commit -am 'lark b'
echo c >> lark_file
git commit -am 'lark c'
echo d >> lark_file
git commit -am 'lark d'
echo e >> lark_file
git commit -am 'lark e'
echo f >> lark_file
git commit -am 'lark f'
git rebase --onto tag-onto HEAD~3
这有一些简单的更改:它在其中创建了一个临时目录 t
和 cd
-s,以便我们可以在完成后删除临时目录,这样重现器脚本本身就不会卡在存储库中。更有用的是,它将最后一个 git rebase 更改为:
git rebase --onto tag-onto HEAD~3
也就是说,我们删除最后的 HEAD
(这会毫无意义地生成一个分离的 HEAD),并且我们使用标签 tag-onto
作为 --到我们要复制
目标上。lark d
提交的
运行此脚本会重现该问题:
$ ./repro.sh
[much output snipped]
CONFLICT (content): Merge conflict in main_file
error: could not apply 1a3193f... lark d
Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply 1a3193f... lark d
这里的设置是,我们尝试将提交 lark~2
挑选到提交 tag-onto
(master~3
或 main~3
取决于您的初始分支)。
我们需要认识到的是,gitcherry-pick
是一种git merge
。它进行三向 merge , merge 基础是精心挑选的提交的父级。这意味着它运行两个 git diff
,从父级 lark~3
到当前提交 HEAD
,以及从父级 lark~3
提交 lark~2
。让我们看看这两个差异中的第一个:
$ git diff lark~3 HEAD
diff --git a/lark_file b/main_file
similarity index 66%
rename from lark_file
rename to main_file
index de98044..422c2b7 100644
--- a/lark_file
+++ b/main_file
@@ -1,3 +1,2 @@
a
b
-c
这表示我们应该重命名该文件:现在应该将其命名为 main_file
,而不是 lark_file
。
第二个差异当然显示了您在提交 lark d
中添加的内容:
$ git diff lark~3 lark~2
diff --git a/lark_file b/lark_file
index de98044..d68dd40 100644
--- a/lark_file
+++ b/lark_file
@@ -1,3 +1,4 @@
a
b
c
+d
因此 Git 决定我们需要将 lark_file
重命名为 main_file
并在末尾添加 d
,同时删除 >c
从 main_file
末尾开始。
这确实是 Git 所做的:我们现在有一个文件 main_file
,而不是两个单独的文件 lark_file
和 main_file
,我们看到冲突。我的是 diff3
风格而不是 merge
风格,所以它有更多信息:
$ cat main_file
a
b
<<<<<<< HEAD:main_file
||||||| parent of 1a3193f... lark d:lark_file
c
=======
c
d
>>>>>>> 1a3193f... lark d:lark_file
Git 根据 Git 规则正确运行。
Git merge 规则时不时地会产生意外,这就是为什么您必须始终检查任何 merge 结果的原因。这包括 cherry-pick 结果,即 merge 结果。
关于git - 关于 git rebase into 选项的一些问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70374543/