【问题标题】:What is wrong with this Git rebasing attempt?这个 Git 变基尝试有什么问题?
【发布时间】:2016-01-22 10:23:18
【问题描述】:

我正在努力学习如何“按部就班”地使用 Git。与多个开发人员一起处理一个项目,我们共享相同的“原点”遥控器。我正在与本地 git 存储库不同的工作区域中开发我的代码。

让我们打电话给我的分支br_ysap。我对我的代码进行了更改,并试图将它们引入我的分支,并最终引入master 分支。远程 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 上收到“冲突”消息。接下来,我正在解决冲突。检查当前状态:

> 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

所以,我现在将这 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

问题 1: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:这个变基过程有什么问题?


更新 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

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

【问题讨论】:

    标签: git rebase git-rebase


    【解决方案1】:

    在第一季度,发生的事情是您复制的Main/Init.c

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

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

    请记住,git rebase 的工作原理是进入一个从 --onto 提交增长的匿名分支——这默认为你要变基到的分支提示,在本例中为 master 的提示——然后重复git cherry-pick set-of-commits-to-copy 中的每个提交。 (在这种情况下,提交复制是git log master..br_ysap 列出的那些。)

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

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

    这里提交T(分支Tip 的master),就是你要重新定位的内容。临时分支指向提交T。 git 当前尝试复制(但失败)的是 commit A,当 rebase 告诉 git 挑选它时,它说要更改 Main/Init.c 中的某些内容,但 git 无法进行该更改。

    (如果您使用发生冲突时应用的提交 ID(此处为 A 的 ID)),您可以运行 git show &lt;commit-id&gt; 来查看整个提交,或者运行 git show &lt;commit-id&gt; -- Main/Init.c 来查看发生了什么一个文件。 Git 无法将这些更改应用到匿名分支的尖端,因此它给了您一个冲突错误。)

    然后,您将工作树文件(其中包含冲突标记和所有内容)替换为您的 ../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 提交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 版本(您这样做,所以这是 Q2 和 Q3 的照顾)。现在你运行git rebase --continue 并且你从 git 得到你的最终投诉(这与 Q4 相关):

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

    再次仔细查看提交C,如git show所示。我怀疑它更改为Main/Init.c2这些更改不会任何事情来提交B',因为那个已经有它们在其中:它们是使提交BMain/Init.c 的版本与提交TMain/Init.c 的版本相匹配的最终更改(master 的提示)。

    这意味着您想要的所有更改都已经存在。如果您想保留空提交,您可以使用git commit --allow-empty 强制“无更改”提交,但git rebase 不会为您执行此操作. Rebase 更喜欢你说 git rebase --skip-commit 来告诉它,天哪,毕竟提交 C 中的任何内容都不需要。然后它将继续进行剩余的提交——谁知道有多少提交(你可以找出来!)——并且,如果所有这些都顺利,完成它的收尾工作,其中包括移动分支 br_ysap 所以它指向了它做过的最重要的提交,我假设这里是S':

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

    您没有执行“跳过”步骤,因此变基仍在进行中,并且您的分支标签 br_ysap 仍然指向原始提交 C,而不是复制提交 B'。因此,git push origin br_ysap 找不到可推送的内容。


    1它是否“一样好”取决于你在解决合并冲突时所做的工作有多好。

    2另一种可能性是它对某些其他文件的更改与 git 能够检测到的更改相匹配已经存在,而不是旧 @987654383 的“合并基础” @ 和 master 加入。不过,我相信您会在这种情况下看到“回退到... 3 路合并”消息。

    【讨论】:

    • 感谢您的详尽回答。在我看来,与我必须真正理解答案相比,需要更深入地了解 git 及其术语。第一次阅读的大部分内容都在我脑海中飘过……
    • 所以,我给了它第二次和第三次阅读,加上一些“git帮助”。让我们看看我是否理解。变基的过程涉及重新应用从masterbr_ysap 的过去提交的更改。这是通过离散的步骤完成的,处理途中的每一次提交。这就是为什么一个文件在这个过程中可能不止一次发生冲突。它可能会在路线中的任何站点发生冲突。
    • 当做一个变基时,git 会在冲突的提交处停止。然后,在解决冲突时,执行--continue 从它停止的点移动到更改中的下一个过去提交。在第一个 rebase 命令和手动复制Main/Main.c 之后,暂存的副本实际上与master's 提交中的副本相同,这就是它从modified 列表中消失的原因。这是有道理的。
    • 正如我上面提到的,文件Main/Init.c 在此过程中发生了两次冲突。我相信这是这个文件,而不是您在回答中涉及的Main.c。根据您的建议,我继续使用git rebase --skip。与我的预期相反,我得到了一个压倒性的更改文件和冲突列表。请参阅问题正文中的更新 1
    • 在本地 repo 的副本上,我尝试使用 git commit --allow-empty 完成而不是跳过。我收到一条消息,据说要分离分支,但检查状态然后尝试rebase --continue 让我回到我们原来的位置。有关详细信息,请参阅更新 2
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多