git - 关于 git rebase into 选项的一些问题

标签 git rebase

主分支:

enter image description here

lark 分支:

enter image description here

rebase 后 enter image description here 奇怪了!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

这有一些简单的更改:它在其中创建了一个临时目录 tcd-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~3main~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,同时删除 >cmain_file 末尾开始。

这确实是 Git 所做的:我们现在有一个文件 main_file,而不是两个单独的文件 lark_filemain_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/

相关文章:

git - 在 Android Studio 中压缩 Git 分支提交

使用 Git 部署 PHP。我怎样才能让它更自动化?

混帐 : Merge multiple commits from one branch into another

git - 如果您处于集中式模型并且从不强制执行, git pull --rebase 是否安全?

Git - 重新设置一组分支

Git 从项目分支中删除提交

Git 将一个分支 rebase 到另一个分支之上

git - 如何确定 git merge 是否是错误的方式

windows - Git 为 *.reg 文件显示 "Binary files a... and b... differ"

linux - Debian Wheezy 上的 GitLab 安装失败要求 initctl