【问题标题】:Git Squash by author - All author commits into a single commit作者的 Git Squash - 所有作者提交到单个提交中
【发布时间】:2015-06-20 00:26:07
【问题描述】:

我正在尝试将许多提交压缩为一个提交,问题是我需要由作者(姓名或电子邮件)执行此操作。

案例:

假设我有一个名为 feature-a 的分支,在这个分支中,我为许多作者提交了许多提交。如何将作者的所有提交(例如电子邮件)压缩为单个提交。我希望这样做能够将所有作者提交合并到 master 中。

这里有什么帮助吗?

提前致谢

【问题讨论】:

  • 这听起来好像会导致很多不必要的工作。也就是说,如果特定作者的提交不是连续的,那么压缩它们将需要大量的人工干预。你最好让你的许多作者都在他们自己的分支上工作。

标签: git git-rebase


【解决方案1】:

Be careful rewriting history

如果您为每个作者创建分支,cherry-pick 将每个作者的提交提交到正确的分支,然后压缩这些更改,则您想要的最终结果可能是可能的。但是,如果这些提交有意义地相互依赖,我认为这不会起作用。

如果你有一系列提交:

            Author1                Author2                Author1
version1 ---commit---> version2 ---commit---> version3 ---commit--->...

如果您要尝试从 Author2 中提取更改,并将它们应用到 version1,那么它很可能没有意义(例如,如果 Author2 修改了 Author1 创建的代码)。

【讨论】:

    【解决方案2】:

    考虑到Kenkroncaveats,您可以这样做:

    SORTED_GIT_LOGS=$(git log --pretty="format:%an %H" master..feature_a | sort -g | cut -d' ' -f2); \
    IFS=$(echo -en "\n\b"); for LOG in $SORTED_GIT_LOGS; do \
        git cherry-pick $LOG; \
    done | less
    

    git log --pretty="format:%an %H" master..feature_a | sort -g 将对feature_a 提交的日志进行排序(不是来自master 的日志,因为master..feature_a 语法)

    您仍然需要执行交互式 rebase 来压缩 master 上的(现在由作者订购)提交。

    【讨论】:

    【解决方案3】:

    当 repo 离线时,我需要对一个不必要的大存储库进行类似的重写。我采用的方法是使用 @james-foucar 和 @pfalcon 在 this answer 中介绍的 GIT_SEQUENCE_EDITOR 尝试自动“交互式”变基。

    为了使其正常工作,我发现最好先从正在重写的历史记录部分中删除合并。对于我自己的情况,这是使用大量 git rebase --onto 完成的,这在 StackOverflow 上的其他问题中得到了充分介绍。

    我创建了一个small script generate-similiar-commit-squashes.sh 来生成picksquash 命令,以便压缩连续的类似提交。我使用 author-date-and-shortlog 来匹配类似的提交,但你只需要 author (我的要点有一个关于如何使它只匹配作者的评论)。

    $ generate-similiar-commit-squashes.sh > /tmp/git-rebase-todo-list
    

    输出看起来像

    ...
    pick aaff1c556004539a54a7a33ce2fb859af0c4238c foo@example.com-2015-01-01-Update-head.html
    squash aa190ea2323ece42f1cd212041bf61b94d751d5c foo@example.com-2015-01-01-Update-head.html
    pick aab8c98981a8d824d2bc0d5278d59bc1a22cc7b0 foo2@example.com-2015-01-28-Update-_config.yml
    

    存储库也充满了具有相同样式的“更新 xyz”提交消息的自我恢复。当被压扁时,它们会导致空提交。

    我正在合并的提交具有相同的提交消息。 git rebase -i 提供了一个修改后的提交消息,其中附加了所有压缩的提交消息,这将是重复的。为了解决这个问题,我使用了来自this answer 的一个小型perl 脚本来删除git rebase 提供的提交消息中的重复行。最好放在文件中,因为它会在 shell 变量中使用。

    $ echo 'print if ! $x{$_}++' > /tmp/strip-seen-lines.pl
    

    现在进入最后一步:

    $ GIT_EDITOR='perl -i -n -f /tmp/strip-seen-lines.pl ' \
      GIT_SEQUENCE_EDITOR='cat /tmp/git-rebase-todo-list >' \
      git rebase --keep-empty -i $(git rev-list --max-parents=0 HEAD)
    

    尽管使用了--keep-emptygit 在此过程中多次抱怨空提交。它会以不完整的git rebase 将我转储到控制台。要跳过空提交和恢复处理,需要以下两个命令(在我的情况下相当频繁)。

    $ git reset HEAD^
    $ GIT_EDITOR='perl -i -n -f /tmp/strip-seen-lines.pl ' git rebase --continue
    

    尽管有--keep-empty,我还是在最终的 git 历史记录中发现了我的had no empty commits,所以上面的重置已将它们全部删除。我认为我的 git 版本 2.14.1 有问题。在一台蹩脚的笔记本电脑上处理大约 10000 个这样的提交只需要 10 多分钟。

    【讨论】:

    • 有趣的方法,比我的回答更完整。 +1。不过不确定您的--keep-empty 问题。
    • 另外值得注意的是任何时候重写历史,如果您不希望重写过程将自己(重写者)归因于每次提交的提交者,您可能需要通过重置来完成重写提交者。最简单的方法是setting committer=author,但如果原始提交者信息确实很重要并且需要保留,则需要更精细的方法。
    • 我已向gist.github.com/jayvdb/9b41677f00065dbd94cc02446fc5ba34 添加了一个脚本generate-multiple-new-file-squashes.sh 以合并仅包含连续添加的提交(即提交者使用了 GitHub/GitLab/BitBucket Web UI“上传文件”)
    • 如果您需要访问第一个提交,请使用 git rebase -i --root
    猜你喜欢
    • 2015-03-08
    • 2018-12-26
    • 2016-03-11
    • 2017-05-07
    • 2013-07-25
    • 2011-10-09
    • 2012-04-08
    • 2015-10-20
    • 1970-01-01
    相关资源
    最近更新 更多