如何压缩分支中的提交
How to squash commits in branches
我正在将旧的 svn 存储库导入 git。有一次,一个文件夹在所有分支中都被重命名了。这是在 svn 中通过创建具有历史记录的副本来完成的,然后在第二次提交时删除原始文件。所以我有一个看起来像这样的回购协议:
A -> B -> C -> D* -> E* -> F -> G -> H
\-> 1 -> 2* -> 3* - > 4 -/
其中 D/E 和 2/3 是我要压缩的提交。
压缩的原因是虽然 svn 知道 "duplicate with history",但 git 不认为这是重命名,因为原始文件直到下一次提交才被删除,我因此失去了历史记录点.
我已经尝试了一些可行的 rebase 脚本,但它们也压平了我的所有分支。以上是我必须做的事情的一个非常简化的版本,这就是为什么我真的需要脚本,因为我不能手动完成。在 SVN 存储库的整个历史中有超过 1,000 个分支,并且可能有十几个并行分支完成了此更改(全部同时进行)。
git 存储库尚未发布,因此维护哈希无关紧要。我假设我需要使用一些过滤器分支脚本,但我仍在尝试弄清楚如何管理我希望能在这里得到帮助的东西。我 可以 提供每个需要压缩的提交及其父项的 sha1。
您想使用 git filter-branch
使用 --parent-filter
将 D
的 SHA 的任何外观替换为 C
的 SHA。您还可以查看 .git/info/grafts
或 git replace
,这可能比编写 --parent-filter
更简单,并且可以使用 filter-branch
.
使其永久化
更新: 正如@torek 所说,你绝对应该使用git replace
。举一个真实的例子,这里是从 readme.md
到 README.md
的重命名,中间重命名为 README1.md
:https://github .com/dahlbyk/posh-git/compare/dahlbyk:2b9342c...dahlbyk:57394c5。让我们将 2b9342c
称为 C
,将 57394c5
称为 E
:
$ git tag E 57394c5
$ git tag C 2b9342c
$ git tag G 450d8f1
$ git log --oneline --graph --decorate C~..G
* 450d8f1 (tag: G) Merge pull request #320 ...
|\
| * 941935c Fix a few kbd / missing markdown issues/
| * f13dcf9 Upcase readme and have more prompt examples.
| * 57394c5 (tag: E) Now rename to README.md.
| * eb79ef2 Prepare to upcase README.md filename.
* | 536c57f Merge pull request #319 ...
|\ \
| |/
|/|
| * 7fafb7b Speed up Get-GitStatus
|/
* 2b9342c (tag: C) Merge pull request #313 ...
为了假装中间移动从未发生过,我可以 replace
E
的父级 (E~
) 与其祖父级 (E~2
= C
):
$ git log --stat --oneline C..E
57394c5 Now rename to README.md.
README1.md => README.md | 0
1 file changed, 0 insertions(+), 0 deletions(-)
eb79ef2 Prepare to upcase README.md filename.
readme.md => README1.md | 0
1 file changed, 0 insertions(+), 0 deletions(-)
$ git replace E~ C
$ git log --stat --oneline C..E
57394c5 Now rename to README.md.
readme.md => README.md | 0
1 file changed, 0 insertions(+), 0 deletions(-)
eb79ef2 Merge pull request ...
最后,filter-branch
将使更改永久生效:
$ git filter-branch -- ^C G E # For demo, only rewrite G & E afer C
$ git log --graph --oneline --decorate C~..G
* fcfd345 (tag: G) Merge pull request #320 ...
|\
| * fa76267 Fix a few kbd / missing markdown issues/
| * 4900687 Upcase readme and have more prompt examples.
| * b25aa5a (tag: E) Now rename to README.md.
* | 536c57f Merge pull request #319 ...
|\ \
| |/
|/|
| * 7fafb7b Speed up Get-GitStatus
|/
* 2b9342c (tag: C) Merge pull request #313 ...
为了您的目的,您将执行如下操作:
$ git replace E~ E~2
$ git replace 3~ 3~2
$ git filter-branch -- ^A --all
更新 2:
The commit message I get is off of E, which I don't care about. I'd rather have D's commit message (or a script provided message).
为了保留 D
的提交元数据,我建议重新开始并使用 --commit-filter
来指定 E
的 tree
(git cat-file -p E
) 对于 D
(并且应该跳过 E
),例如
git filter-branch --commit-filter '
if [ "$GIT_COMMIT" = "SHA of D" ];
then
git commit-tree "TREE of E" -p "SHA of C";
elif [ "$GIT_COMMIT" = "SHA of E" ];
then
skip_commit "$@";
else
git commit-tree "$@";
fi;
' -- ^A E G
我正在将旧的 svn 存储库导入 git。有一次,一个文件夹在所有分支中都被重命名了。这是在 svn 中通过创建具有历史记录的副本来完成的,然后在第二次提交时删除原始文件。所以我有一个看起来像这样的回购协议:
A -> B -> C -> D* -> E* -> F -> G -> H
\-> 1 -> 2* -> 3* - > 4 -/
其中 D/E 和 2/3 是我要压缩的提交。 压缩的原因是虽然 svn 知道 "duplicate with history",但 git 不认为这是重命名,因为原始文件直到下一次提交才被删除,我因此失去了历史记录点.
我已经尝试了一些可行的 rebase 脚本,但它们也压平了我的所有分支。以上是我必须做的事情的一个非常简化的版本,这就是为什么我真的需要脚本,因为我不能手动完成。在 SVN 存储库的整个历史中有超过 1,000 个分支,并且可能有十几个并行分支完成了此更改(全部同时进行)。
git 存储库尚未发布,因此维护哈希无关紧要。我假设我需要使用一些过滤器分支脚本,但我仍在尝试弄清楚如何管理我希望能在这里得到帮助的东西。我 可以 提供每个需要压缩的提交及其父项的 sha1。
您想使用 git filter-branch
使用 --parent-filter
将 D
的 SHA 的任何外观替换为 C
的 SHA。您还可以查看 .git/info/grafts
或 git replace
,这可能比编写 --parent-filter
更简单,并且可以使用 filter-branch
.
更新: 正如@torek 所说,你绝对应该使用git replace
。举一个真实的例子,这里是从 readme.md
到 README.md
的重命名,中间重命名为 README1.md
:https://github .com/dahlbyk/posh-git/compare/dahlbyk:2b9342c...dahlbyk:57394c5。让我们将 2b9342c
称为 C
,将 57394c5
称为 E
:
$ git tag E 57394c5
$ git tag C 2b9342c
$ git tag G 450d8f1
$ git log --oneline --graph --decorate C~..G
* 450d8f1 (tag: G) Merge pull request #320 ...
|\
| * 941935c Fix a few kbd / missing markdown issues/
| * f13dcf9 Upcase readme and have more prompt examples.
| * 57394c5 (tag: E) Now rename to README.md.
| * eb79ef2 Prepare to upcase README.md filename.
* | 536c57f Merge pull request #319 ...
|\ \
| |/
|/|
| * 7fafb7b Speed up Get-GitStatus
|/
* 2b9342c (tag: C) Merge pull request #313 ...
为了假装中间移动从未发生过,我可以 replace
E
的父级 (E~
) 与其祖父级 (E~2
= C
):
$ git log --stat --oneline C..E
57394c5 Now rename to README.md.
README1.md => README.md | 0
1 file changed, 0 insertions(+), 0 deletions(-)
eb79ef2 Prepare to upcase README.md filename.
readme.md => README1.md | 0
1 file changed, 0 insertions(+), 0 deletions(-)
$ git replace E~ C
$ git log --stat --oneline C..E
57394c5 Now rename to README.md.
readme.md => README.md | 0
1 file changed, 0 insertions(+), 0 deletions(-)
eb79ef2 Merge pull request ...
最后,filter-branch
将使更改永久生效:
$ git filter-branch -- ^C G E # For demo, only rewrite G & E afer C
$ git log --graph --oneline --decorate C~..G
* fcfd345 (tag: G) Merge pull request #320 ...
|\
| * fa76267 Fix a few kbd / missing markdown issues/
| * 4900687 Upcase readme and have more prompt examples.
| * b25aa5a (tag: E) Now rename to README.md.
* | 536c57f Merge pull request #319 ...
|\ \
| |/
|/|
| * 7fafb7b Speed up Get-GitStatus
|/
* 2b9342c (tag: C) Merge pull request #313 ...
为了您的目的,您将执行如下操作:
$ git replace E~ E~2
$ git replace 3~ 3~2
$ git filter-branch -- ^A --all
更新 2:
The commit message I get is off of E, which I don't care about. I'd rather have D's commit message (or a script provided message).
为了保留 D
的提交元数据,我建议重新开始并使用 --commit-filter
来指定 E
的 tree
(git cat-file -p E
) 对于 D
(并且应该跳过 E
),例如
git filter-branch --commit-filter '
if [ "$GIT_COMMIT" = "SHA of D" ];
then
git commit-tree "TREE of E" -p "SHA of C";
elif [ "$GIT_COMMIT" = "SHA of E" ];
then
skip_commit "$@";
else
git commit-tree "$@";
fi;
' -- ^A E G