简体   繁体   English

作者Git Squash - 所有作者都提交到一个提交

[英]Git Squash by author - All author commits into a single commit

I am trying squash many commits into a single one, the problem is that I need do that by author (name or email). 我正在尝试将许多提交压缩成一个,问题是我需要通过作者(名称或电子邮件)来做。

The case: 案子:

Lets say I have a branch called feature-a, in this branch I have many commits for many authors. 可以说我有一个名为feature-a的分支,在这个分支中我有许多作者的许多提交。 How can I squash all commits by author (email for example) into a single commit. 如何将作者(例如电子邮件)的所有提交压缩到一个提交中。 I want do that to be able to merge all author commits into master. 我想这样做能够将所有作者提交合并到master中。

Any help here? 这里有什么帮助?

Thanks in advance 提前致谢

Be careful rewriting history 小心重写历史

The end result you want might be possible if you create branches for each author, cherry-pick the commits from each author into the right branch, then squash those changes. 如果您为每个作者创建分支,则可以获得您想要的最终结果,从每个作者中选择提交到正确的分支,然后压缩这些更改。 However, I don't think that will work if these commits meaningfully depend on each other. 但是,如果这些提交有意义地依赖于彼此,我认为这不会起作用。

If you have a series of commits: 如果您有一系列提交:

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

If you were to try to extract the changes from Author2, and apply them to version1, there's a good chance it won't make sense (For example, if Author2 modifies code that Author1 created). 如果您尝试从Author2中提取更改并将它们应用于版本1,则很有可能它没有意义(例如,如果Author2修改了Author1创建的代码)。

With Kenkron 's caveats in mind, you could do a: 考虑到Kenkron警告 ,你可以做一个:

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

The git log --pretty="format:%an %H" master..feature_a | sort -g git log --pretty="format:%an %H" master..feature_a | sort -g git log --pretty="format:%an %H" master..feature_a | sort -g would sort the logs of the feature_a commits (not the ones from master because of the master..feature_a syntax) git log --pretty="format:%an %H" master..feature_a | sort -g会对feature_a提交的日志进行排序(由于master..feature_a语法而不是master的日志)

You would still need to do an interactive rebase to squash the (now ordered by author) commits on master . 你仍然需要做一个交互式的rebase来压缩master上的(现在由作者命令)提交。

I needed to do a similar rewrite on an unnecessarily large repository while the repo was offline. 当repo离线时,我需要在不必要的大型存储库上进行类似的重写。 The approach I took was trying automated 'interactive' rebase using GIT_SEQUENCE_EDITOR which is covered in this answer by @james-foucar & @pfalcon. 我采用的方法是尝试使用GIT_SEQUENCE_EDITOR进行自动“交互式” GIT_SEQUENCE_EDITOR这个答案由@ james-foucar和@pfalcon讨论。

For this to work well, I found it better to first remove the merges from the section of the history being rewritten. 为了使其运行良好,我发现最好先从正在重写的历史记录部分中删除合并。 For my own case, this was done using lots of git rebase --onto which is covered amply in other questions on StackOverflow. 对于我自己的情况,这是使用大量的git rebase --onto在StackOverflow上的其他问题中完全涵盖的。

I created a small script generate-similiar-commit-squashes.sh to generate the pick & squash commands so that consecutive similar commits would be squashed. 我创建了一个小脚本generate-similiar-commit-squashes.sh来生成picksquash命令,以便连续的类似提交被压扁。 I used author-date-and-shortlog to match similar commits, but you only need author (my gist has a comment about how to make it match only on author). 我使用author-date-and-shortlog来匹配类似的提交,但你只需要作者(我的要点有关于如何使其仅与作者匹配的评论)。

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

The output looks like 输出看起来像

...
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

The repository was also full of self-reverts with the same style 'Update xyz' commit messages. 存储库也充满了自我还原,具有相同样式的“更新xyz”提交消息。 When squashed, they resulted in empty commits. 当被压扁时,它们导致空提交。

The commits I was merging had identical commit messages. 我合并的提交有相同的提交消息。 git rebase -i offers a revised commit message with all squashed commit messages appended, which would have been repetitive. git rebase -i提供了修改后的提交消息,其中附加了所有压缩的提交消息,这些消息本来就是重复的。 To address that, I used a small perl script from this answer to remove duplicate lines from the commit message offered by git rebase . 为了解决这个问题,我在这个答案中使用了一个小的perl脚本来删除git rebase提供的提交消息中的重复行。 It is better in a file, as it will be used in a shell variable. 它在文件中更好,因为它将在shell变量中使用。

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

Now for the final step: 现在进行最后一步:

$ 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)

Despite using --keep-empty , git complained a few times through this process about empty commits. 尽管使用了--keep-emptygit在这个过程中抱怨了几次空提交。 It would dump me out to the console with an incomplete git rebase . 它会使用不完整的git rebase将我转移到控制台。 To skip the empty commit and resume processing, the following two commands were needed (rather frequently in my case). 要跳过空提交和恢复处理,需要以下两个命令(在我的情况下经常这样)。

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

Again despite --keep-empty , I found I had no empty commits in the final git history, so the resets above had removed them all. 尽管--keep-empty ,我发现在最终的git历史中我没有空提交 ,所以上面的重置已经将它们全部删除了。 I assume something is wrong with my git, version 2.14.1 . 我认为我的git版本2.14.1有问题。 Processing ~10000 commits like this took just over 10 minutes on a crappy laptop. 处理~10000这样的提交在一台糟糕的笔记本电脑上花了10多分钟。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM