这个 Git 变基尝试有什么问题?

What is wrong with this Git rebasing attempt?

我正在尝试学习如何使用 Git "by the book"。与多个开发人员一起处理一个项目,我们共享相同的 "origin" 遥控器。我正在一个与本地 git 存储库不同的工作区开发我的代码。

让我们称我的分支为 br_ysap。我对我的代码进行了更改,并试图将它们引入我的分支,并最终引入 master 分支。自从我上次同步内容后,远程 master 已更新。所以,我想将我的分支变基到当前的主分支,然后应用我的更新、提交和推送。

这是我正在做的事情和回应:

> git clone ...

> git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean

> git checkout br_ysap
Branch br_ysap set up to track remote branch br_ysap from origin.
Switched to a new branch 'br_ysap'

> git rebase master
First, rewinding head to replay your work on top of it...
Applying: SOME-COMMIT-COMMENT
Using index info to reconstruct a base tree...
M       Main/Init.c
M       Main/Main.c
A       Service/Service_1.c
A       Service/Service_2.c
M       build_options.mk
Falling back to patching base and 3-way merge...
Auto-merging build_options.mk
Auto-merging Service/Service_3.c
CONFLICT (content): Merge conflict in Service/Service_3.c
Auto-merging Main/Main.c
CONFLICT (content): Merge conflict in Main/Main.c
Auto-merging Main/Init.c
CONFLICT (content): Merge conflict in Main/Init.c
Failed to merge in the changes.
Patch failed at 0001 SOME-COMMIT-COMMENT
The copy of the patch that failed is found in:
   c:/local_repo/.git/rebase-apply/patch

When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".

过去的某个时候,Service_2.c 被重命名为 Service_3.c

现在,我在 Main.cInit.cService_3.c 上收到 "conflict" 条消息。接下来,我正在解决冲突。查看当前状态:

> git status
rebase in progress; onto fcd827a
You are currently rebasing branch 'br_ysap' on 'fcd827a'.
  (fix conflicts and then run "git rebase --continue")
  (use "git rebase --skip" to skip this patch)
  (use "git rebase --abort" to check out the original branch)

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   build_options.mk

Unmerged paths:
  (use "git reset HEAD <file>..." to unstage)
  (use "git add <file>..." to mark resolution)

        both modified:   Main/Init.c
        both modified:   Main/Main.c
        both modified:   Service/Service_3.c

所以,我现在将工作 space 中的 3 个文件复制到 git 目录(这不是使用合并工具,而是将新的更新引入代码)。

> cp ../dev-tree/Main/Init.c         Main/Init.c
> cp ../dev-tree/Main/Main.c         Main/Main.c
> cp ../dev-tree/Service/Service_3.c Service/Service_3.c

this tutorial 之后,我将暂存文件:

> git add Main/Init.c Main/Main.c Service/Service_3.c

> git status
rebase in progress; onto fcd827a
You are currently rebasing branch 'br_ysap' on 'fcd827a'.
  (all conflicts fixed: run "git rebase --continue")

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   Main/Init.c
        modified:   Service/Service_3.c
        modified:   build_options.mk

问题一:Main/Main.c怎么了?怎么没了?

接下来,按照说明,我继续变基:

> git rebase --continue
Applying: SOME-COMMIT-COMMENT
Applying: SOME-COMMIT-COMMENT - review update
Using index info to reconstruct a base tree...
M       Main/Init.c
Falling back to patching base and 3-way merge...
Auto-merging Main/Init.c
CONFLICT (content): Merge conflict in Main/Init.c
Failed to merge in the changes.
Patch failed at 0002 SOME-COMMIT-COMMENT - review update
The copy of the patch that failed is found in:
   c:/local_repo/.git/rebase-apply/patch

When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".

问题2:为什么Main/Init.c还是有冲突?我用更新的版本覆盖了文件吗?

检查状态、复制文件、添加和检查状态:

> git status
rebase in progress; onto fcd827a
You are currently rebasing branch 'br_ysap' on 'fcd827a'.
  (fix conflicts and then run "git rebase --continue")
  (use "git rebase --skip" to skip this patch)
  (use "git rebase --abort" to check out the original branch)

Unmerged paths:
  (use "git reset HEAD <file>..." to unstage)
  (use "git add <file>..." to mark resolution)

        both modified:   Main/Init.c

no changes added to commit (use "git add" and/or "git commit -a")

> cp ../dev-tree/Main/Init.c Main/Init.c

> git add Main/Init.c

> git status
rebase in progress; onto fcd827a
You are currently rebasing branch 'br_ysap' on 'fcd827a'.
  (all conflicts fixed: run "git rebase --continue")

nothing to commit, working directory clean

应该准备好完成变基了,不是吗?嗯:

> git rebase --continue
Applying: SOME-COMMIT-COMMENT - review update
No changes - did you forget to use 'git add'?
If there is nothing left to stage, chances are that something else
already introduced the same changes; you might want to skip this patch.

When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".

> git status
rebase in progress; onto fcd827a
You are currently rebasing branch 'br_ysap' on 'fcd827a'.
  (all conflicts fixed: run "git rebase --continue")

nothing to commit, working directory clean

问题3:什么给的???没有,我没忘记git add,谢谢。

当我尝试提交并推送分支时,什么也没做:

> git push origin br_ysap:br_ysap
Everything up-to-date

问题 4:这个 rebase 过程有什么问题?


更新 1: 根据 @torek 的描述,提示我缺少最后的提交步骤,我尝试执行 rebase --skip。不幸的是,结果出乎意料且压倒性的:

> git rebase --skip
Applying: ANOTHER_COMMENT
Using index info to reconstruct a base tree...
A       Application/App_3.c
M       CSP/Driver_1.h
M       CSP/Driver_1.c
A       CSP/Driver_2.h
M       CSP/Chip.h
M       Common/Con_1.c
M       Diags/Con_2.c
M       Diags/Makefile
M       Main/Init.c
M       Main/Main.c
M       Main/Makefile
M       OS/Makefile
A       Service/Service_4.h
A       Service/Service_5.h
A       Service/Service_2.c
<stdin>:592: trailing whitespace.
//   $Id$
<stdin>:122074: trailing whitespace.
#define SOME_MOACRO_1
<stdin>:123643: trailing whitespace.
#define SOME_MOACRO_2
<stdin>:128989: trailing whitespace.
#define SOME_MOACRO_3
<stdin>:134620: trailing whitespace.
#define SOME_MOACRO_4
warning: squelched 9 whitespace errors
warning: 14 lines add whitespace errors.
Falling back to patching base and 3-way merge...
Auto-merging Service/Service_3.c
CONFLICT (content): Merge conflict in Service/Service_3.c
Auto-merging OS/Makefile
CONFLICT (content): Merge conflict in OS/Makefile
Auto-merging Main/Makefile
CONFLICT (content): Merge conflict in Main/Makefile
Auto-merging Main/Main.c
CONFLICT (content): Merge conflict in Main/Main.c
Auto-merging Main/Init.c
CONFLICT (content): Merge conflict in Main/Init.c
Auto-merging Diags/Makefile
CONFLICT (content): Merge conflict in Diags/Makefile
Auto-merging Diags/Con_2.c
CONFLICT (content): Merge conflict in Diags/Con_2.c
Auto-merging Common/Con_1.c
CONFLICT (content): Merge conflict in Common/Con_1.c
CONFLICT (modify/delete): Application/App_3.c deleted in HEAD and modified in ANOTHER_COMMENT Version ANOTHER_COMMENT of Application/App_3.c left in tree.
Failed to merge in the changes.
Patch failed at 0003 ANOTHER_COMMENT
The copy of the patch that failed is found in:
   c:/local_repo/.git/rebase-apply/patch

When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".

更新 2: 在执行 --skip 之前,我复制了该目录,以便我可以从更新 1 之前的那个点进行试验。因此,更改为该副本,我尝试了到 commit --allow-empty 而不是 --skip。我一直发现自己陷入了死胡同:

> git commit --allow-empty -m "YET-MORE-COMMENT"
[detached HEAD 4dd9e38] YET-MORE-COMMENT

> git status
rebase in progress; onto fcd827a
You are currently rebasing branch 'br_ysap' on 'fcd827a'.
  (all conflicts fixed: run "git rebase --continue")

nothing to commit, working directory clean

看起来分支最终分离了,但没有附加到`

在第 1 季度,发生的事情是 Main/Init.c 您复制的内容:

cp ../dev-tree/Main/Init.c Main/Init.c

(然后 git added)与您要变基的树中的版本相匹配。

请记住,git rebase 通过进入从 --onto 提交生成的匿名 b运行ch 来工作——这默认为 b运行ch 提示你' rebase 到,在本例中是 master 的提示——然后在要复制的提交集合中重复每个提交的 git cherry-pick。 (在本例中,提交复制是 git log master..br_ysap 列出的那些。)

您当前的提交(rebase 的中间或真正开始)是对 git rebase 正在构建的匿名 b运行ch 的提交。我会给 b运行ch 起个名字,以便于查看。事情看起来像这样(我假设原始基础和变基之间的提交集非常短,所以 master 部分可能太短了,但这个想法应该足够清楚):

          A - B - C - ... - S  <-- br_ysap
        /
... - o - o - o - T   <-- master, rebase-temp

此处提交 T(b运行ch masterTip),这就是您要重新定位的内容。临时 b运行ch also 指向提交 T。提交 git 当前正在尝试复制(并且失败)是提交 A,当 rebase 告诉 git 挑选它时,它说要更改 Main/Init.c 中的某些内容, 但 git 无法进行更改。

(如果您使用发生冲突时应用的提交 ID——此处为 A 的 ID)——您可以 运行 git show <commit-id> 查看整个提交,或 git show <commit-id> -- Main/Init.c 查看一个文件发生了什么。 Git 无法将这些更改应用到匿名 b运行ch 的提示,所以它给了你一个冲突错误。)

然后您用 ../dev-tree 文件替换了工作树文件(其中包含冲突标记和所有内容)。在你 "git add" 编辑完所有内容后,你 运行 git status。这会将索引(您将要提交的内容)与最近提交的内容进行比较,即提交 T。如果文件与 T 中的文件匹配,git status 什么都不说。

此时你运行git rebase --continue。这产生了一个新的提交,git 自豪地声称它与提交 ​​A1 一样好所以我们称之为 A':

          A - B - C - ... - S  <-- br_ysap
        /
... - o - o - o - T   <-- master
                   \
                    A'   <-- rebase-temp

Git 现在继续 git cherry-picking commit B,工作正常,没有冲突——你可以明白为什么 git show 原来的 B 并查看此时 rebase-temp 中的内容。无论如何,现在我们有了这个:

          A - B - C - ... - S  <-- br_ysap
        /
... - o - o - o - T   <-- master
                   \
                    A' - B'   <-- rebase-temp

现在 git 尝试复制提交 C。如果你 git show 这个提交,你会看到 cherry-pick 应该对 Main/Init.c 做一些更多的新更改,但是同样,git 不能做这些更改:他们不适合。

因此,git 因冲突而停止。你现在应该编辑文件并修复它,但大概你可以再次复制并添加你的 ../dev-tree 版本(你这样做,所以这是第二季度和第三季度的处理)。现在您 运行 git rebase --continue 并收到来自 git 的最终投诉(与 Q4 相关):

Applying: SOME-COMMIT-COMMENT - review update
No changes - did you forget to use 'git add'?

再次仔细查看提交 C,如 git show 所示。我怀疑它有 onlyMain/Init.c 的变化。2 这些变化没有 do任何要提交 B' 的东西,因为那个已经有了它们:它们是使提交 BMain/Init.c 的版本与 Main/Init.c 中的 Main/Init.c 版本相匹配的最终更改提交 Tmaster 的提示)。

这意味着你想要的所有更改都已经存在。如果你想保留空提交,你可以使用 git commit --allow-empty 强制提交 "no changes",但是 git rebase不会为你做那件事。 Rebase 更喜欢你说 git rebase --skip-commit 来告诉它,天哪,毕竟不需要提交 C 的任何内容。然后它将继续进行剩余的提交——谁知道有多少(你可以找到!)——并且,如果在这些过程中一切顺利,完成它的收尾工作,包括移动 b运行ch br_ysap 以便它指向最顶端提交它 did make,我假设这里是 S':

          A - B - C - ... - S  [abandoned]
        /
... - o - o - o - T   <-- master
                   \
                    A' - B' - D' - ... - S'  <-- br_ysap

你没有做那个 "skip" 步骤,所以变基仍在进行中,你的 b运行ch 标签 br_ysap 仍然指向原始提交 C,不要复制提交 B'。因此 git push origin br_ysap 找不到要推送的内容。


1是否"just as good"取决于你在解决合并冲突时的表现如何。

2另一种可能性是它对一些其他文件进行了更改,这些更改与 git 能够检测到的更改已经存在,与 "merge base" 旧的 br_ysapmaster 加入。不过,我相信您会在这种情况下看到 "Falling back to ... 3-way merge" 消息。