Git 与 --squash 合并,同时保留每次提交的日志
Git merge with --squash while keeping log of every commit
初始场景:
A (master)
\
B - C - D (development)
合并后我想要什么 --squash:
A - E (master/development)
\ /
B - C - D
在分支 master
上,git 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
在分支 master
上,git 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
在分支 development
上,git 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
.
这只是一个常规合并...
#!/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
您无法使用您显示的结构获得您想要的日志结果(git log --merges master
可以做到)。将为您提供所需日志的结构打败了重点。而且,最后,这是使用 Git.
的一种弄巧成拙的方式
希望能够 运行 git log master
并且只看到压缩的提交。这行不通。 Git 不知道有些提交是针对 master
而有些是针对 development
。让我们看看建议的结构。
A - E - I [master] [development]
\ / \ /
B - C - D F - G - H
此时,master
和 development
指向同一个提交。就 Git 历史而言 它们是相同的 。分支只不过是指向提交的标签。 提交不记得他们提交到哪个分支。 git log master
和 git 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
进行代码考古学(即 "why was this line written this way"),因为所有更改都被粉碎到一个差异中,这使得将一行更改与特定提交消息相关联变得更加困难。由于 master
和 development
的历史是分离的,因此无法确保开发中的所有内容都进入 master,反之亦然(例如,对 master 的热修复)。
git log master
比 git log development
提供的信息少,而且更难理解。 master
与 development
没有关联,并且失去了保留合并历史记录的所有好处。维护这个复杂的设置没有意义。
而是使用git merge --no-ff
合并feature分支(不是一个连续的"development"分支)并保留分支历史,便于考古。
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
是一个功能分支,用于处理尚未合并的炸玉米饼。
git log --graph --decorate master
将显示 master 的完整历史,合并提交显示功能何时结束,以及说明分支历史的行。 GUI Git 历史工具,例如 GitX 是另一种以图表形式阅读历史的方法。
说到底,Git历史是一个图表。如果您学会了如何使用该图表,使用 Git 的生活将会容易得多。如果你试图让 Git 历史变成线性的,就像一大堆薄煎饼,你就违背了 Git 的要点,并为自己和其他人创造额外的工作。
好吧,不可能 完全 您所要求的,就像您合并分支一样,无论如何您都会在提交日志中看到来自两个分支的提交。你可能想要的是这样的东西:
A - E (master)
\
B - C - D (development)
您只需从 development
分支中挑选提交,压缩它们并在 master
.
之上应用
最简单的方法是这样的:
git checkout development && git rebase -i master HEAD
然后用 squash
替换除第一个操作之外的所有操作。结果,您将获得一个分离的头,指向压缩的提交,应用在 master
之上。您只需将 master
重置为该提交即可。
我想,提交消息将不是您想要的,因为它将重新排序所有提交的提交消息,而不是它们的哈希值,但是您将能够使用 --exec
选项。
一切都有点过于手动,但您可以编写所有内容并创建别名。我相信,这是使用 git
本身最接近的结果,而不是用某种高级编程语言重写所有内容。
初始场景:
A (master)
\
B - C - D (development)
合并后我想要什么 --squash:
A - E (master/development)
\ /
B - C - D
在分支 master
上,git 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
在分支 master
上,git 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
在分支 development
上,git 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
.
这只是一个常规合并...
#!/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
您无法使用您显示的结构获得您想要的日志结果(git log --merges master
可以做到)。将为您提供所需日志的结构打败了重点。而且,最后,这是使用 Git.
希望能够 运行 git log master
并且只看到压缩的提交。这行不通。 Git 不知道有些提交是针对 master
而有些是针对 development
。让我们看看建议的结构。
A - E - I [master] [development]
\ / \ /
B - C - D F - G - H
此时,master
和 development
指向同一个提交。就 Git 历史而言 它们是相同的 。分支只不过是指向提交的标签。 提交不记得他们提交到哪个分支。 git log master
和 git 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
进行代码考古学(即 "why was this line written this way"),因为所有更改都被粉碎到一个差异中,这使得将一行更改与特定提交消息相关联变得更加困难。由于 master
和 development
的历史是分离的,因此无法确保开发中的所有内容都进入 master,反之亦然(例如,对 master 的热修复)。
git log master
比 git log development
提供的信息少,而且更难理解。 master
与 development
没有关联,并且失去了保留合并历史记录的所有好处。维护这个复杂的设置没有意义。
而是使用git merge --no-ff
合并feature分支(不是一个连续的"development"分支)并保留分支历史,便于考古。
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
是一个功能分支,用于处理尚未合并的炸玉米饼。
git log --graph --decorate master
将显示 master 的完整历史,合并提交显示功能何时结束,以及说明分支历史的行。 GUI Git 历史工具,例如 GitX 是另一种以图表形式阅读历史的方法。
说到底,Git历史是一个图表。如果您学会了如何使用该图表,使用 Git 的生活将会容易得多。如果你试图让 Git 历史变成线性的,就像一大堆薄煎饼,你就违背了 Git 的要点,并为自己和其他人创造额外的工作。
好吧,不可能 完全 您所要求的,就像您合并分支一样,无论如何您都会在提交日志中看到来自两个分支的提交。你可能想要的是这样的东西:
A - E (master)
\
B - C - D (development)
您只需从 development
分支中挑选提交,压缩它们并在 master
.
最简单的方法是这样的:
git checkout development && git rebase -i master HEAD
然后用 squash
替换除第一个操作之外的所有操作。结果,您将获得一个分离的头,指向压缩的提交,应用在 master
之上。您只需将 master
重置为该提交即可。
我想,提交消息将不是您想要的,因为它将重新排序所有提交的提交消息,而不是它们的哈希值,但是您将能够使用 --exec
选项。
一切都有点过于手动,但您可以编写所有内容并创建别名。我相信,这是使用 git
本身最接近的结果,而不是用某种高级编程语言重写所有内容。