【问题标题】:Git merge with --squash while keeping log of every commitGit 与 --squash 合并,同时保留每次提交的日志
【发布时间】:2015-10-17 20:30:25
【问题描述】:

初始场景:

A (master)
 \
 B - C  - D (development)

合并后我想要什么--squash:

A     -     E (master/development)
 \         /
 B - C - D 

在分支mastergit log 将是

commit E
    Squashed commit of the following:
    commit D
    commit C
    commit B
commit A

继续开发分支development:

A     -     E (master)
 \         / \         
 B - C - D    F - G - H (development)

再次与壁球合并:

A     -     E     -     I(master/development)
 \         / \         /
 B - C - D    F - G - H

在分支mastergit log 将是

commit I
    Squashed commit of the following:
    commit H
    commit G
    commit F
commit E
    Squashed commit of the following:
    commit D
    commit C
    commit B
commit A

在分支developmentgit log 将是

Commit I
Commit H
Commit G
Commit F
Commit E
Commit D
Commit C
Commit B
Commit A

我想与master 上压缩的提交合并,同时保留development 上的每个提交。

我不知道如何实现它。我的问题是我不知道如何在第一次合并中使D 指向E,而I 将包含B,C,D,E,F,G,H 而不是仅F,G,H

【问题讨论】:

  • 为什么要这样做?这似乎使历史变得更加复杂。此外,您的日志结果也不会像您想象的那样。 master 的日志将显示所有提交。

标签: git merge git-squash


【解决方案1】:

您无法使用您显示的结构获得所需的日志结果(git log --merges master 会这样做)。会给你你想要的日志的结构打破了这一点。最后,这是使用 Git 的一种弄巧成拙的方式。


希望能够运行 git log master 并且只看到压缩的提交。这行不通。 Git 不知道有些提交是针对master 的,而有些是针对development 的。让我们看看建议的结构。

A     -     E     -     I [master] [development]
 \         / \         /
 B - C - D    F - G - H

此时,masterdevelopment 指向同一个提交。就 Git 历史而言它们是相同的。分支只不过是指向提交的标签。 提交不记得他们提交到哪个分支git log mastergit log development 将生成相同的日志,显示从 A 到 I 的所有提交。E 和 I 压缩的提交日志将是多余的。

可以使用git log --merges master(或development)获得您想要的内容,以仅显示合并提交,但这将显示任何合并提交,即使是已完成的作为development 的一部分。所以它并没有真正起作用。

整个想法过于复杂,请继续阅读。


要得到你想要的日志结果,你必须像这样打破两个分支之间的关系。

A     -     E     -     I [master]
 \                   
 B - C - D - F - G - H [development]

你可以以某种方式完成工作,但没有意义。 git log master 包含所有相同的日志消息,因此它将与 git log development 一样长,但它们会被粉碎在一起。您不能使用git log master 来进行代码考古(即“为什么要这样写这一行”),因为所有更改都被拼凑成一个差异,这使得将一行更改与特定提交消息关联起来更加困难。由于 masterdevelopment 的历史是不相关的,因此无法确保开发中的所有内容都成为 master,反之亦然(例如,对 master 的热修复)。

git log master 提供的信息git log development,而且更难理解masterdevelopment 没有关联,并且失去了保留合并历史记录的所有好处。维护这种复杂的设置毫无意义。


改为使用git merge --no-ff 合并feature 分支(不是一个连续的“开发”分支)并保留分支历史以便于考古。

              G - J [feature/tacos]
             /
A     -     E     -     K [master]
 \         / \         /
 B - C - D    F - H - I

E 和 K 是git merge --no-ff 产生的正常合并提交。没有连续的development 分支,由功能分支处理。功能分支是一次性使用的,一旦合并就被删除。有关功能分支的信息保留在合并提交中,git merge --no-ff 保证保留分支结构。 feature/tacos 是一个功能分支,用于处理尚未合并的 tacos。

git log --graph --decorate master 将显示 master 的完整历史记录,合并提交显示功能何时结束,以及说明分支历史记录的行。 GUI Git 历史记录工具(例如 GitX)是另一种以图表形式读取历史记录的方式。

归根结底,Git 历史是一个图表。如果你学会了如何使用 Git 来处理这个图形,生活会容易得多。如果你试图让 Git 历史线性化,就像一大堆煎饼一样,那么你就违背了 Git 的意义,并为自己和其他人创造了额外的工作。

【讨论】:

    【解决方案2】:

    嗯,不可能准确地得到你想要的,就像你合并分支一样,无论如何你都会在提交日志中看到来自两个分支的提交。你可能想要的是这样的:

    A      -     E (master)
     \         
     B - C - D (development)
    

    您只需从 development 分支中挑选提交,压缩它们并应用到 master 之上。

    最简单的方法是这样的:

    git checkout development && git rebase -i master HEAD
    

    然后你用squash 替换除第一个之外的所有操作。结果,您将获得一个指向压缩提交的分离头,应用在master 之上。您只需将 master 重置为此提交即可。

    我想,提交消息不会完全符合您的要求,因为它会重新排序所有提交的提交消息,而不是它们的哈希值,但是您可以使用 --exec 挂钩到提交消息生成选项。

    一切都有点过于手动,但您可以编写所有内容并创建别名。我相信,这是使用git 本身可以获得的最接近的结果,而不是用某种高级编程语言重写所有内容。

    【讨论】:

      【解决方案3】:

      这只是一个常规的合并...

      #!/bin/sh
      git init
      touch a; git add a; git commit -m a
      git checkout -b patch
      touch b; git add b; git commit -m b
      touch c; git add c; git commit -m c
      git checkout master
      git merge --no-ff patch
      git log --graph --oneline
      

      结果

      *   a9fbaec Merge branch 'patch'
      |\
      | * fb7eac4 c
      | * 94f44c1 b
      |/
      * 4de57a5 a
      

      【讨论】:

      • 但是你的提交并没有在分支master git log 中被压缩
      • 感谢指出,我已经编辑了我的问题,希望它会更清楚
      猜你喜欢
      • 1970-01-01
      • 2018-04-03
      • 1970-01-01
      • 2015-04-20
      • 2015-08-22
      • 2013-05-25
      • 2016-12-30
      • 2016-06-27
      • 2015-04-17
      相关资源
      最近更新 更多