Git 重置行为

Git reset behavior

我有以下情况:

master 分支有一个稳定的应用程序版本。

开发人员 A 最近创建了一个名为 branch-a 的功能分支,其中包含多个提交(假设它们是 a-1a-2, a-3)。此处实现的功能基于 master 的最新代码,目前已经过良好测试。

开发人员 B 有一个名为 branch-b 的功能分支,其中包含多个提交(例如,b-1b-2, b-3).由于某种原因,B 先生的功能分支中有一个过时的版本(基于一两周前的 master 状态)并且根本没有测试代码。

两位开发人员合并了他们的功能分支以掌握使用:

  1. git结帐大师
  2. git拉源主
  3. git 合并分支 X(其中 X = a,b)
  4. git push origin master

没有使用变基命令。这个序列首先由 B 完成,接下来由 A 完成。

当我(开发人员 C)从 master 拉取时,我在 git 日志 中看到类似这样的内容:

结果B先生不知何故在合并时强制旧版本的代码覆盖稳定版本(导致b-merge-conflicts commit)。

现在我想重写历史并保存 b-1 + b-3 + a-1 + a-2 + a-3 更改并撤销 b-2, b-merge-冲突a-merge.

我的想法是撤消几个最高提交直到 b-1 然后使用 cherry-pick 补丁来应用 b-3 , a-1, a-2, a-3 提交给新的 master.

但是当我尝试时:

git重置--硬头~7 我可以看到只包含旧提交(在 master-stable 之前)的历史,而没有 branch-a 和 branch-b 的历史。

当我尝试时:

git reset --hard HEAD~2

我可以在历史记录中看到顶部只有 master-stable 提交,但不是我想要的 a-2

看起来 git 重置不会在 HEAD 之后将 digit 转换为要重置的提交数(正如我从文档中理解的那样),但作为一些 HEAD-通过 git 拉动进行更改(在我的示例中有 2 个)。

如何正确撤消前 7 个提交 b-2 .. a-merge 并重写从 b-1 开始的历史记录?

更新在评论中询问

我使用了(没有 --all 来排除附加信息)

git log --oneline --decorate --graph

*   ef7d93f Merge with master by Developer A
|\
| * 2b9dd31 b-4
| * 924a452 b-3
| * 1f9489d b-2
| *   e3cd7a6 Merge by Developer B [2]: Merge branch 'master' from https://github.com ....
| |\
| * | aece506 Merge by Developer B [1]: merge branch
| * | 487e7ee b-1
* | | d9404f8 a-1
| |/
|/|
* | 9b202ce master-stable last commit

我不确定HEAD~,因为我通常使用HEAD^

虽然您不需要使用该表示法。您可以只提供提交的十六进制 SHA-1 哈希值,或者它的前 7 位左右的数字。

git reset --hard 72abfd4

git log 在骗你。它呈现 Git 历史,就好像它是线性的,它按日期顺序向您展示提交。那不是很有用。 git log --graph --decorate 将通过向您展示提交树(实际上是图表)来为您提供更清晰的故事。据我所知,您的存储库如下所示。

                                       a1 - a2 - a3
                                      /            \
origin c1 - c2 - c3 - c4 - b-merge - b3 -------- a-merge [master]
        \                  /
         b1 -------------b2

如您所见,"go back seven commits"可以有多种解释。这就是为什么您应该避免将多个提交移回的表示法,而是参考提交 ID。

你要的就是这个

                  a1 - a2 - a3 [branch-a]
                 /
c1 - c2 - c3 - c4 [master]
                 \
                  b1 - b3 [branch-b]

要到达那里,请在 c4 之外创建 A 和 B 分支,这样您就有了一个可以建造的地方。

git branch branch-a c4
git branch branch-b c4

             [branch-b]         a1 - a2 - a3
             [branch-a]        /            \
c1 - c2 - c3 - c4 - b-merge - b3 -------- a-merge [master]
  \                  /
   b1 -------------b2

现在检查那些分支,并挑选适当的更改到它们上,修复所有冲突。

                  b1b - b3b [branch B]
                 / 
                |   a1a - a2a - a3a [branch A]
                |  /  
                | /                a1 - a2 - a3
                |/               /            \
c1 - c2 - c3 - c4 - b-merge - b3 -------- a-merge [master]
  \                  /
   b1 -------------b2

这可能看起来一团糟,但现在结账大师和 git reset --hard c4 以及大师在 a-merge 保持活力的所有混乱都会消失(这是一个善意的谎言,origin/master 将在您推送之前保持它可见,而且 Git 实际上不会在数周内丢弃提交)。

                  b1b - b3b [branch B]
                / 
               |  a1a - a2a - a3a [branch A]
               |/
c1 - c2 - c3 - c4 [master]

现在可以正常合并A和B了。完成后,您必须 push --force 因为 master 不是 origin/master 的 child。

这只是完成您想要的事情的一种方法。重要的是能够可视化存储库图,你希望它在哪里,以及什么命令会转换它。