Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Neat, clean compacted git PR and merge commit, into one commit

Most of the time in repos, we see a PR, then a merge commit of that PR, which just says "Merged pull request #XXX from ...".

But recently, I saw a compacted version of that, where the avatars of the pull requester and the committer overlap, and only one clean commit shows up in the history:

enter image description here

How can this be done?

What I've tried and doesn't work:

  • deleting the branch after the PR is accepted (PR #755)
  • deleting the repo after the PR is accepted (PR #78)

UPDATE

An example of what it looks like when one of my PRs was merged that way:

enter image description here

Results in:

enter image description here

like image 461
Dan Dascalescu Avatar asked Nov 29 '14 22:11

Dan Dascalescu


People also ask

How do I merge commits to a commit?

To "squash" in Git means to combine multiple commits into one. You can do this at any point in time (by using Git's "Interactive Rebase" feature), though it is most often done when merging branches. Please note that there is no such thing as a stand-alone git squash command.

Should merge commits be squashed?

As a general rule, when merging a pull request from a feature branch with a messy commit history, you should squash your commits. There are exceptions, but in most cases, squashing results in a cleaner Git history that's easier for the team to read.


2 Answers

2016 April update

GitHub has introduced an option to squash commits when merging, so you can do this straight from its web UI:

Squash and merge

Old solution

Just found this workflow from the Meteor team (coincidentally, thanks @Emily):

When you look at a pull request in the GitHub web interface, there's a very attractive "merge" button. NEVER USE THE MERGE BUTTON. It is an attractive nuisance. It leads to git history that's way more complicated than necessary: if the PR was filed a month ago, the commit's parent will be a very old revision that leads to way more lines than necessary in a graphical view of the git history. Plus, if you're using the merge button, that means that you didn't ever check out the code and try it yourself! The following is a better way to land pull requests.

First, in your repository, find the [remote "origin"] section of the .git/config file and add this line:

fetch = +refs/pull/*/head:refs/remotes/origin/pr/*

Make sure to add it BEFORE the existing fetch line. Now, every time you git fetch, you'll get all the Pull Requests in the repo updated! This is a one-time change that will give you direct access to PRs forever.

Then you can just git checkout pr/XXX and work with the changes directly. A git push origin after cherry-picking will create the compact PR:

git checkout pr/32
# ... test changes ...
git checkout master
git cherry-pick pr/32
git push 

enter image description here

The only downside is that GitHub won't automatically delete PR branches when they are closed, but that's just one click away and in exchange you get a much nicer history.

If the PR is multiple commits, the best thing to do is to check it out, rebase it onto your development branch, make whatever other changes you need, and merge it back to the development branch with an explicit merge commit. This is similar to what the GitHub merge button does, except that the merge button doesn't do the VERY IMPORTANT rebase step and so it leaves ugly spaghetti in the project's git commit history. To do this, run:

git checkout pr/32; git rebase devel; git checkout devel; git merge --ff-only pr/32

Then test and push.

If you'd like to combine some of the commits into a single commit, you can use interactive rebase by running git rebase -i devel instead. Some tutorials: http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html https://www.atlassian.com/git/tutorials/rewriting-history/git-reflog

Unfortunately GitHub is not smart enough to detect that you've merged a PR by hand, so you'll need to manually comment and close the issue with a link to the relevant commit. Alternatively, make sure that the merge commit's message contains Fixed #123.


UPDATE: A further update was made by Kahmali Rose that enables GitHub to detect that the PR was merged, pretty much as if the evil Merge button was clicked: make sure to rebase and merge instead of cherry-picking.

like image 135
Dan Dascalescu Avatar answered Sep 20 '22 21:09

Dan Dascalescu


If the PR is just a single commit, you can cherry-pick it on to the master branch (or whatever branch you merge PRs into). So, for example:

$ git checkout -b branch-for-pr master
$ git pull <fork url> <pr branch name>
$ git checkout master
$ git cherry-pick branch-for-pr

Alternatively, you can rebase the PR branch on top of master to allow a fast-forward merge (which will skip the merge commit):

$ git checkout -b branch-for-pr master
$ git pull <fork url> <pr branch name>
$ git rebase master
$ git checkout master
$ git merge --ff-only branch-for-pr
like image 21
Emily Avatar answered Sep 18 '22 21:09

Emily