Git重置行为

And*_*hin 6 git merge rebase

我有以下情况:

分支有应用的稳定版本.

开发人员A最近创建了一个名为branch-a的功能分支,其中有几个提交(让它们为a-1,a-2,a-3).这里实现的功能基于master的最新代码,目前已经过充分测试.

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

两个开发人员使用以下方法将其功能分支合并为master:

  1. git checkout master
  2. git pull origin master
  3. git merge branch-X(其中X = a,b)
  4. git push origin master

没有使用rebase命令.首先,这个序列是由B完成的,接着是由A.

当我(开发人员C)从master中撤出时,我在git log中看到过类似的东西:

  • a-merge:由开发人员A与master合并
  • A-3
  • a2
  • A-1
  • b-3(是的,这个提交恰好在合并之后)
  • b-merge-conflicts:由开发人员B与master合并(数千个文件冲突)
  • B-2
  • B-1
  • master-stable:以前的稳定提交

因此,B先生以某种方式迫使旧版本的代码在合并时覆盖稳定版本(导致b-merge-conflicts commit).

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

我的想法是撤消几个顶级提交,直到b-1,然后使用cherry-pick修补程序将b-3, a-1,a-2,a-3提交应用于新主人.

但是当我尝试:

git reset --hard HEAD~7 我可以看到一个只包含旧提交的历史记录(在master-stable之前),而不包含branch-a和branch-b的历史记录.

当我尝试:

git reset --hard HEAD~2

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

看起来git reset不会将HEAD之后的数字转换为一些要重置的提交(因为我从文档中得到了不应该),但是通过git pull进行了一些HEAD更改(在我的示例中有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
Run Code Online (Sandbox Code Playgroud)

Sch*_*ern 2

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

                                       a1 - a2 - a3
                                      /            \
origin c1 - c2 - c3 - c4 - b-merge - b3 -------- a-merge [master]
        \                  /
         b1 -------------b2
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,“返回七个提交”可以有多种解释。这就是为什么您应该避免使用向后移动多个提交的符号,而应引用提交 ID。

你想要的就是这个。

                  a1 - a2 - a3 [branch-a]
                 /
c1 - c2 - c3 - c4 [master]
                 \
                  b1 - b3 [branch-b]
Run Code Online (Sandbox Code Playgroud)

为此,请从 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
Run Code Online (Sandbox Code Playgroud)

现在检查这些分支并挑选适当的更改对其进行修复,解决任何冲突。

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

这可能看起来像一团糟,但现在签出 master 并且git reset --hard c4master 处于合并状态时保持的所有混乱都会消失(这是一个善意的谎言,origin/master 会保持它可见,直到你推送,Git 也不会实际上将提交扔掉了几周)。

                  b1b - b3b [branch B]
                / 
               |  a1a - a2a - a3a [branch A]
               |/
c1 - c2 - c3 - c4 [master]
Run Code Online (Sandbox Code Playgroud)

现在可以正常合并A和B了。当你完成后,你必须这样做push --force,因为 master 不是 origin/master 的孩子。

这只是实现您想要的目标的一种方法。重要的是能够可视化存储库图、您想要的位置以及将转换它的命令。