Git 合并简单与壁球。目的是什么?如何跟踪每个功能的一次提交?
Git Merge simple vs Squash. What is the purpose? How to track one commit per feature?
我不喜欢 Git 的一件事是提交的数量。不要误会我的意思,这是一种非常方便的(安全地)存储您的工作的方法,但是在很长的 运行 中,搜索的粒度太大了。
让我在使用从 develop.
分支的功能分支进行开发时描述以下场景
- Feature1 是从 develop 分支出来的,有 5 次提交
- Feature2 是从 develop 分支出来的,有 3 个提交
- Feature3 是从 Feature1 分支出来的,有 5+2 次提交。
之所以有三个分支是因为有一个团队在处理存储库。 Feature3 假定 Feature1 已完成,等待合并到开发中。还有其他用例,但这是最简单的示例。
我的目标是在完成所有功能后在 develop 上提交三个。
使用gitmerge/pull
以上场景效果很好。因为本质上这两个命令都将提交移动到开发分支中。合并 Feature1 时,develop 引用它的五个提交。当 Feature3 将被合并时,只有最后两个提交会被合并到 develop.
唯一的负面影响是 develop 提交太多。这意味着当合并到 master 时,所有 "noise" 都会移动。所以我的目的没有达到。
使用 git 与 squash 合并
当合并 Feature1 时,develop 得到一个新的提交,它是所有 Feature1[=79 的聚合=].这非常好,因为现在只需一次提交即可跟踪该功能。当删除 Feature1 时,所有中间提交都不再可见,从而使跟踪更容易。这也与诸如一个拉取请求和一个 github 问题等概念相匹配。
当 Feature3 将要合并时,出现冲突并出现问题。要解决这个问题,您需要将 develop 合并回 feature3。与冲突。这会导致一个新的提交,其中有零个文件被更改。现在我们将 squash Feature3 合并到 develop.
我的目标实现了,但在微观管理上做出了很多牺牲。
Questions/Remarks
据我了解,这就是 git 现实。我读过的一个建议是创建一个兄弟功能分支来保存压缩的合并提交。将兄弟分支用于拉取请求,因此强制每个功能使用一个提交。这并不能解决在尝试合并其他分支时产生的冲突,尤其是从其他功能分支继承的冲突。
- 能否在同一分支内进行内部压缩?我不这么认为,但问问也无妨。
- 我是不是漏了什么?
- 这是挤压合并的权衡吗?解决可能具有零代码更改的冲突?
- 追求"one commit per feature"概念是否值得?
- 如果不是,那么 squash 的目的是什么?谁在使用这个?
我已经阅读了使用 rebase 的替代方案并在合并后使用 reset 模拟壁球,但据我了解 none 解决了提到的合并 feature3 的开销。
我真的认为变基是你的解决方案。
如果我理解,下面是你的git结构:
develop
\
A - B - C [feature1]
\
D - E [feature3]
你的问题是,一旦你将 feature1 压缩并合并到 develop,最初的三个提交 feature3 引用不再存在。你本质上就像下面这样,除了 feature1 并不真正存在。
develop — feature1Merge
\
A - B - C [feature1]
\
D - E [feature3]
因此 feature1Merge 在 develop 中的提交与 feature3 的历史记录不同.
在这种情况下,如果您尝试 rebase
feature3 回到 develop,提交 A
B
和 C
会随之而来,理论上这不会导致任何问题,因为更改已经在 develop 上,所以 git 应该只是 fast-forward 那些提交。显然,这似乎并没有发生。
在这种情况下我建议做的是rebase onto
。
变基到
--onto
选项允许您变基特定的提交,而不是整个分支。
因此,为了停止 git 尝试在变基时使用提交 A
B
和 C
,我们使用 --onto
,它有 3 个参数:
分公司新基地
分支当前基地
要变基的分支名称
在你的情况下,这将是:
git rebase --onto develop C feature3
这将检查 develop,然后应用 feature3 自 C
:
以来的所有提交
develop — feature1Merge
\
D - E [feature3]
希望这一切都有意义,并尽可能少地实现您想要的!
是的,git 有这么多提交的目的是让每个更改都可跟踪。如果某些提交并不重要,或者可以将所有更改记录在一个提交中供您查看历史记录,那么您当然可以压缩这些提交。
针对您的问题:
1.Yes,你可以做一个内部壁球。假设您的 git 提交历史如下图所示:
K---L---M Feature2
/
A---B---…---C---… develop
\
D---E---F---G---H Feature1
\
I---J Feature3
您可以使用这些步骤来压缩每个分支:
git checkout Feature1
git rebase -i HEAD~5
输入i
pick D
squash E
squash F
squash G
squash H
press Esc button and then input :wq
git checkout Feature3
git rebase -i HEAD~7
pick D
squash E
squash F
squash G
squash H
squash I
squash J
git rebase Feature1
git checkout Feature2
git rebase -i HEAD~3
pick K
squash L
squash M
- 你的流程没问题。
- 要压缩提交,第一个(最旧的)应该使用 pick,其他人可以使用压缩,这样它会显示只有一个提交的分支。如果有冲突,可以修改并保存冲突文件,然后使用
git add .
和git rebase --continue
.
- 不一定,看你喜欢。 squash 的主要目的是让历史看起来更整洁和清晰。
我不喜欢 Git 的一件事是提交的数量。不要误会我的意思,这是一种非常方便的(安全地)存储您的工作的方法,但是在很长的 运行 中,搜索的粒度太大了。
让我在使用从 develop.
分支的功能分支进行开发时描述以下场景- Feature1 是从 develop 分支出来的,有 5 次提交
- Feature2 是从 develop 分支出来的,有 3 个提交
- Feature3 是从 Feature1 分支出来的,有 5+2 次提交。
之所以有三个分支是因为有一个团队在处理存储库。 Feature3 假定 Feature1 已完成,等待合并到开发中。还有其他用例,但这是最简单的示例。
我的目标是在完成所有功能后在 develop 上提交三个。
使用gitmerge/pull
以上场景效果很好。因为本质上这两个命令都将提交移动到开发分支中。合并 Feature1 时,develop 引用它的五个提交。当 Feature3 将被合并时,只有最后两个提交会被合并到 develop.
唯一的负面影响是 develop 提交太多。这意味着当合并到 master 时,所有 "noise" 都会移动。所以我的目的没有达到。
使用 git 与 squash 合并
当合并 Feature1 时,develop 得到一个新的提交,它是所有 Feature1[=79 的聚合=].这非常好,因为现在只需一次提交即可跟踪该功能。当删除 Feature1 时,所有中间提交都不再可见,从而使跟踪更容易。这也与诸如一个拉取请求和一个 github 问题等概念相匹配。
当 Feature3 将要合并时,出现冲突并出现问题。要解决这个问题,您需要将 develop 合并回 feature3。与冲突。这会导致一个新的提交,其中有零个文件被更改。现在我们将 squash Feature3 合并到 develop.
我的目标实现了,但在微观管理上做出了很多牺牲。
Questions/Remarks
据我了解,这就是 git 现实。我读过的一个建议是创建一个兄弟功能分支来保存压缩的合并提交。将兄弟分支用于拉取请求,因此强制每个功能使用一个提交。这并不能解决在尝试合并其他分支时产生的冲突,尤其是从其他功能分支继承的冲突。
- 能否在同一分支内进行内部压缩?我不这么认为,但问问也无妨。
- 我是不是漏了什么?
- 这是挤压合并的权衡吗?解决可能具有零代码更改的冲突?
- 追求"one commit per feature"概念是否值得?
- 如果不是,那么 squash 的目的是什么?谁在使用这个?
我已经阅读了使用 rebase 的替代方案并在合并后使用 reset 模拟壁球,但据我了解 none 解决了提到的合并 feature3 的开销。
我真的认为变基是你的解决方案。
如果我理解,下面是你的git结构:
develop
\
A - B - C [feature1]
\
D - E [feature3]
你的问题是,一旦你将 feature1 压缩并合并到 develop,最初的三个提交 feature3 引用不再存在。你本质上就像下面这样,除了 feature1 并不真正存在。
develop — feature1Merge
\
A - B - C [feature1]
\
D - E [feature3]
因此 feature1Merge 在 develop 中的提交与 feature3 的历史记录不同.
在这种情况下,如果您尝试 rebase
feature3 回到 develop,提交 A
B
和 C
会随之而来,理论上这不会导致任何问题,因为更改已经在 develop 上,所以 git 应该只是 fast-forward 那些提交。显然,这似乎并没有发生。
在这种情况下我建议做的是rebase onto
。
变基到
--onto
选项允许您变基特定的提交,而不是整个分支。
因此,为了停止 git 尝试在变基时使用提交 A
B
和 C
,我们使用 --onto
,它有 3 个参数:
分公司新基地
分支当前基地
要变基的分支名称
在你的情况下,这将是:
git rebase --onto develop C feature3
这将检查 develop,然后应用 feature3 自 C
:
develop — feature1Merge
\
D - E [feature3]
希望这一切都有意义,并尽可能少地实现您想要的!
是的,git 有这么多提交的目的是让每个更改都可跟踪。如果某些提交并不重要,或者可以将所有更改记录在一个提交中供您查看历史记录,那么您当然可以压缩这些提交。
针对您的问题:
1.Yes,你可以做一个内部壁球。假设您的 git 提交历史如下图所示:
K---L---M Feature2
/
A---B---…---C---… develop
\
D---E---F---G---H Feature1
\
I---J Feature3
您可以使用这些步骤来压缩每个分支:
git checkout Feature1
git rebase -i HEAD~5
输入i
pick D squash E squash F squash G squash H
press Esc button and then input
:wq
git checkout Feature3
git rebase -i HEAD~7
pick D squash E squash F squash G squash H squash I squash J
git rebase Feature1
git checkout Feature2
git rebase -i HEAD~3
pick K squash L squash M
- 你的流程没问题。
- 要压缩提交,第一个(最旧的)应该使用 pick,其他人可以使用压缩,这样它会显示只有一个提交的分支。如果有冲突,可以修改并保存冲突文件,然后使用
git add .
和git rebase --continue
. - 不一定,看你喜欢。 squash 的主要目的是让历史看起来更整洁和清晰。