365Git

  1. Search
  2. About
  3. Subscribe
  4. Archive
  5. Random

365Git

Regular small snippets and workflows for Git

My original plan of a post everyday turned out to be unrealistic, but I'll carry on posting as regularly as I can.

Find me @abizern on twitter if you have anything you'd like me to cover.

Newer
Older
  • Git merge –squash

    There is a flag to the git merge command: --squash which at first looks as if it does the same thing as a rebase, but this isn’t exactly so. This post attempts to explain the difference.

    Consider the following repository structure:

    merge_squash1

    There is a master branch and two feature branches feat1 and feat2. The feat2 branch will introduce a merge conflict, which is why it is highlighted in red.

    Say you want to bring the two features into the master branch as a single change. There are, as you would expect with Git, multiple ways of doing this.

    Merging

    One way to do that is by merging the two branches into the master. From the master branch you can just git merge feat1 feat2 (yes, you can merge multiple branches in one step) You will get an error because of the merge conflict, which you should know how to fix by now, and this will give you this structure:

    merge_squash2

    Rebasing

    That’s fine if you want to be able to show that the merges have happened, but sometimes, that isn’t the case and you want to be able to show a clean history and a single change. To do that, you can use the rebase command. First by rebasing feat1 onto feat2 git checkout feat1; git rebase feat2

    merge_squash3

    And then you can rebase this branch onto the master with git rebase --interactive, where you can squash the three individual commits to a single commit, and resolve the merge conflict introduced by feat2:

    merge_squash4

    And now, switch to the master branch and rebase it onto the feat1 branch (or merge it, the result will be the same as it will resolve as a fast-forward merge). This will give you a single commit with a clean history and all the merged changes from feat1 and feat2:

    merge_squash5

    git merge –squash

    Now to the topic of this post; using the --squash flag with git merge. What this does is similar to an interactive rebase where you squash all of the commits, except it doesn’t check in the change, it just updates the index (and by extension, the working directory). So, starting from the original repository structure we can get the same result by first git merge --squash feat1 feat2 and fixing the merge conflict. This won’t affect the the checked in state of the master branch, but your index will have all the changes:

    merge_squash6

    What’s the advantage of this? Well, you can get a clean history by just commiting the changes:

    merge_squash7

    But, even more interestingly, you can now back out the changes from the index (which leaves them in the working directory) and add back selective changes using git add --patch and create an entirely different set of commits.

    Which should you use?

    For most cases, merging would be the choice of most people. It’s simple enough, and if there aren’t many micro commits the history will be coherent. In this example it only takes three steps (1. merge 2. fix conflicts 3. commit).

    If you are the sort that makes many micro commits (like me) and you then rebase them into larger chunks before merging the changes to another branch, then the rebasing method is the one you are already using, even if you squash all the changes into a single commit. I prefer this method, because you have greater flexibility with what changes you make. I also find it easier to handle merge conflicts this way. But it does take longer (1. rebase feat1 onto feat2 2. Interactive rebase 3. Amend the commit messages 4. fix conflicts 5. commit 6. rebase master onto feat1).

    But, if you’re aware of what conflicts might occur and how to resolve them, or if you want to use interactive patching, then using git merge --squash is a good choice; and it might be faster (1. merge 2. fix conflicts 3a. commit or 3b/3c … patch add the changes)

    Tagged: git merge rebase squash conflict clean history

    Posted on April 5, 2011 with 23 notes ()

    1. tomekq75 liked this
    2. hikergeek liked this
    3. memeetstheworld liked this
    4. bonham690-blog liked this
    5. 365git posted this

Field Notes Theme. Designed by Manasto Jones. Powered by Tumblr.