将github拉取请求压缩为一个“合适”的提交

46

我在Github上有一个仓库,其中有人(为了方便,我们称他为Bob)发起了拉取请求。他的代码并不完美,所以我们经过几轮修改和标记。据我所知,他每次完成一组标记后就会提交并推送到他的拉取请求中。

因此,我的仓库现在看起来像这样:

master: ---o A (Chowlett
           |
           |
pull-req:  o---o---o---o
               B   C   D (all Bob)

提交的SHAs和消息如下:

A:

123456 Good commit <chowlett>

B:

777ccc Fix the widget bug <bob>

C:

888ddd Review markups <bob>

D:

999eee Further markups <bob>

我现在很高兴接受这个拉取请求,但我不想在我的仓库中保留预标记版本。 我能否实现以下所有内容?如何操作?

  • 将B、C和D合并为一个提交到我的仓库中
  • 生成“合并拉取请求#99到...”的提交
  • 让Github自动关闭拉取请求

4
请请求贡献者将更改合并到一个提交中,再进行合并。 - Stefan
6
@Stefan - 那不违反“不要对已经推送到远程的提交进行变基”的原则吗? - Chowlett
7
@Chowlett 这是一个不错的经验法则,但当远程分支尚未合并且没有其他人在使用它时,这并不会造成任何损害。 - Jeremiah Orr
5
是的,这正是会发生的事情。有时在拉取请求中的评论可能会出现混乱,特别是如果您对提交中的特定行进行了评论,但除此之外,一切都没问题。 - Jeremiah Orr
8
@Chowlett或Bob可以将压缩过的提交推送到另一个分支,打开一个新的拉取请求,并关闭第一个请求。 - Stefan
显示剩余6条评论
5个回答

17
请注意,当Bob在创建GitHub PR时,他不必压缩他的提交。
从2016年3月开始,您可以将此操作留给接受您的PR的维护者(即您)。

请参见“压缩您的提交”及其新文档

  

这是一个新选项,它允许您在通过合并按钮合并的所有拉取请求上强制使用提交压缩。

https://help.github.com/assets/images/help/pull_requests/squash-and-merge.png


文档上写着4月1日。我不确定他们是不是在开玩笑,但看起来这似乎是贴纸 :) - Rob W
1
@RobW 我确认,这不是一个愚人节的玩笑。(https://twitter.com/synhershko/status/716465979828604928) - VonC
我不明白为什么要把所有工作压缩成一个无法审查、重用和撤销的大提交。 - Gayan Weerakutti
@reversiblean 这取决于要压缩的提交的性质:有时,您会有一个由许多较小的提交组成的小补丁,所有这些提交都是试错的结果:如果该历史记录不重要,则您可能希望将您的 PR 呈现为最终结果(压缩提交),而不是代表达到该结果所做的所有提交的噪音。 - VonC

10

git中有两个内置的“压缩”功能。一个是git merge --squash,另一个是 git rebase --interactive 中的 squash 操作。前者不保留作者或日期信息,仅将一系列提交的所有更改收集到本地工作副本中。后者很烦人,因为它需要交互。

git squash扩展可以满足您的需求。它会将当前HEAD重新基于指定的基础,同时自动压缩之间的提交。在重新基础没有创建冲突的情况下,它还提供了一个命令行选项来设置最终压缩提交的消息。

将此与hubghi结合起来,您可能能够构建以下脚本:

git pull upstream master
hub checkout https://github.com/$user/$repo/pull/$issue
git squash master
rev=$(git rev-parse --short HEAD)
git checkout master
git merge $rev
git commit --amend "Merged pull request #$issue"
git push upstream master
ghi close $issue $user/$repo
ghi comment $issue "Merged as $rev" $user/$repo 

9
您可以使用--squash选项进行合并。
git merge <remote url> <remote branch> --squash

然而,这样做不会产生合并提交。相反,它将产生一组普通的工作树更改,就像您手动应用了他所有的更改到您的副本一样。然后您可以像平常一样提交。

缺点是您在主分支上的历史记录将不会显示此提交作为从他的分支合并而来。它看起来就像您自己完成了这项工作,没有给Bob功劳。


3

使用 Git rebase

一种想法是检出分支并使用交互式 rebase 将所有提交压缩为一个,然后强制推送以更新 pull 请求并合并(尽管这项工作的一部分可以委托给 Bob)。

要自动将分支中的所有提交压缩为第一个提交,并将其应用于 pull 请求,您可以使用以下命令:

$ git checkout pull-req
$ GIT_SEQUENCE_EDITOR='sed -i "2,\$s/^pick/s/g" $1' git rebase -i origin/master
$ git push --force

GIT_SEQUENCE_EDITOR 是一个Git环境变量,用于设置重定位提交列表的临时编辑器。我们将其设置为一行脚本,该脚本将除第一行以外的所有行的单词 pick 替换为 s(表示压缩),这是在 sed 模式中的 2,\$。传递到脚本的提交列表是一个简单的文本文件。然后,Git会继续进行重定位并让您编辑最终的提交消息。

此外,通过 git 钩子,您可以更轻松地编辑此最终消息以适应您的需求(例如,在压缩提交的消息之间添加可视分隔符)。

使用 git merge --squash

也可以通过 git merge --squash 进行压缩。请参见此处了解两种方法之间的区别。下面的脚本将使用合并命令将一个分支的提交压缩为单个提交。它还创建了分支的备份(以防万一)。

MAINBRANCH="master"    
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)

# update current feature branch with master
git pull origin $MAINBRANCH

# delete existing backup
git branch -D "$CURRENT_BRANCH-backup"

# backup current feature branch and go back
git checkout -b "$CURRENT_BRANCH-backup" && git checkout -

# checkout and update master branch
git checkout $MAINBRANCH && git pull

# create new branch from master
git checkout -b "$CURRENT_BRANCH-squashed"

# set it to track the corresponding feature branch
git branch "$CURRENT_BRANCH-squashed" --set-upstream-to "$CURRENT_BRANCH"

# merge and squash the feature branch into the one created
git merge --squash $CURRENT_BRANCH

# commit the squashed changes
git commit

# force push to the corresponding feature branch
git push -f . HEAD:$CURRENT_BRANCH

# checkout the feature branch
git checkout $CURRENT_BRANCH

# delete the squashed copy
git branch -D "$CURRENT_BRANCH-squashed"

1
这对我很有帮助。
  • devtools_import_export 上的工作仍然完整。
  • 我的 issue35squashed 的拉取请求到上游 / 主分支只有一个提交。
  • 遗憾的是,合并没有记录,但提交消息包含所有详细信息。

以下是我实际执行的操作(请参见 https://github.com/anaran/devtools-snippets/network

git checkout master
git status # all clean
git checkout -B issue35squashed master
git merge --squash devtools_import_export
git status # looks good
git commit # review and commit via emacs
git log --graph --abbrev-commit --stat --pretty --decorate=full --branches
git push --all -v

我之前尝试使用 git merge --no-ff ...,但在 issue35take2 中,它没有成功。提交拉取请求时包含了来自 devtools_import_export 的所有单独提交。不好。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接