Skip to content

Instantly share code, notes, and snippets.

@delineas
Forked from wilmoore/branch-organization.md
Created October 23, 2018 22:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save delineas/45f274f8fce7a09cb409cbf1b08cc182 to your computer and use it in GitHub Desktop.
Save delineas/45f274f8fce7a09cb409cbf1b08cc182 to your computer and use it in GitHub Desktop.
Branch Organization

Scenario

Work is done within a feature branch created from master. You've incrementally gotten the feature branch working as expected; however, you'd prefer to re-organize your commits so that you can better reason about the changes.

Setup

Let's create a new repository in order to set the stage:

 % mkdir repo
 % cd repo
 % git init
 % touch {a,b,c}.txt
 % git add --all
 % git commit -m 'added a, b, and c'

Screenshot

As a git user, I want to create feature "d, e, and f"

Let's make a mess (err...feature)

 % git checkout -b feature/a-b-c
 #=> Switched to a new branch 'feature/a-b-c'

 # apathetic, yet deceptively entertaining commit message for e.txt.
 % touch e.txt
 % git add e.txt
 % git commit -m 'added some file -- I guess it was e.txt; whatever!'

 % touch d.txt
 % git add d.txt
 % git commit -m 'added d.txt'
 # oh nooooh; we've done this out of order...oh well, let's continue but fix it later.

 % touch f.txt
 % git add f.txt
 % git commit -m 'added f.txt'

 % touch n.txt
 % git add n.txt
 % git commit -m 'added n.txt -- looks like we have gotten ahead of ourselves'

Let's review the state of things

Current list of files

What have we done in only this branch (excludes stuff from master)

I don't get it...what's the problem again?

  1. The commits are out of order (though, this normally doesn't matter as long as the code works as expected)
  2. n.txt shouldn't be here; however, we should preserve it as it can be used with another feature branch.
  3. Also, we've incorrectly named our branch feature/a-b-c; it should be feature/d-e-f

Preserving n

 % git show --format=oneline --abbrev-commit

 % git checkout -b temp-stash master
 % git cherry-pick --no-commit 6773a35
 % git status

 % git stash save 'added n.txt'
 % git stash list
 #=> stash@{0}: On temp-stash: added n.txt

 % git checkout feature/a-b-c
 #=> Switched to branch 'feature/a-b-c'

 % git branch -D temp-stash

Let's review

At this point, we need to:

  1. undo commit 6773a35 (we won't lose anything since the content is stashed).
  2. rename feature/a-b-c to feature/d-e-f.
  3. squash all of the commits into a single commit allowing a neat merge.

We have a few options:

  1. git revert: while this would work, on it's own, it further extends the many commit problem by adding yet another commit.

  2. git rebase --interactive: this would work just fine in most cases; however, the syntax is a bit daunting if you haven't spent a lot of time using it. Also, for some use-cases, there are other valid methods. That being said, for completness, the correct git rebase --interactive command sequence would be:

     % git rebase --interactive HEAD~5
     #=> since there are 5 commits that we want to squash together:
     #=> the initial commits of {d,e,f,n}.txt (4) and the revert of n.txt (1)
     #=> 4 + 1 = 5 (that was hard)
    

NOTE: if you were following along with the git rebase --interactive, do not go forward with it, abort!

Revert, Checkout, Merge, Squash, profit

 % git revert 6773a35
 % ls -lah
 #=> look mah, no n.txt

 % git checkout -b feature/d-e-f master
 #=> correcting our branch name

 % git branch

 % git merge --squash feature/a-b-c

 % git status

 % git commit -m 'added d, e, and f'
 % git log

 % git branch -D feature/a-b-c
 % git branch

Epilogue (github pull requests)

If you have an existing pull request out on the original topic branch, after squashing, you might think you need to open a new pull request. That is not the case. You can simply force push (use --force or +HEAD) over the old un-squashed branch and your pull request comparison view will reflect a single commit while the files updated count will be as it was pre-squash.

In other words, you should not have to open a new pull request losing valuable code review comments.

Epilogue (on "shared" branches)

If you are concerned about "shared" branches (as you should be):

  1. Try not to do that if you can :)- it is an open invitation for pain and makes git rebase --interactive even less attractive. That's a shame because sometimes, it's the right tool.

  2. If you must do the "shared" branch dance, make sure to use git merge --squash or git rebase --interactive ONLY once the feature is complete, just before issuing a pull request. Those sharing the branch should be well-informed that they MUST stop integrating into the branch immediately. Renaming the branch can certainly help in this regard.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment