Just recently I gave a presentation on Git (the version control system, not the British pejorative). I introduced newbies to the Git world and the concepts behind it and demonstrated advanced users some lesser known Git features.
Additionally, I introduced my personal workflow when working on small scale features, let’s say the size of one commit to the main line. Some of my colleagues found this workflow to be particularly interesting, so I’d like to share it here and discuss its benefits and drawbacks.
Since I trust the reader’s competent knowledge of Git basics, I will not explain any git commands in this blog post.
The workflow I’ll describe should only be applied to features that fulfill the following conditions:
Before we proceed, please remember this important advice from the Pro Git book:
Do not rebase commits that exist outside your repository.
If you follow that guideline, you’ll be fine. If you don’t, people will hate you, and you’ll be scorned by friends and family.
This simple rule also applies to any operation which changes commit hashes, e.g.
So now that we know what to do in order to keep our friends and family at peace, let’s get started with my personal workflow for working locally.
The basic (and simple) idea is to use a local, dedicated, temporary feature branch where you commit as often as you like until the feature is done. Then the result is merged into the main line as one commit without rebasing or any other major Git magic.
The important steps are printed in bold.
I’ll assume two things:
The workflow itself is fairly easy once you have used it yourself:
my_featurein this example)
git merge --squash my_feature
master'sstaging area (
merge --squashdoesn’t auto-commit)
I use this workflow because of the following reasons:
git stashcould be used but the stash can be deleted accidentally, e.g.
git stash drop).
my_featurehas been integrated into
master. At this point you know that everything has been merged.
I am writing this blog as a single file which is version controlled in a local branch of a Git repository which also holds my presentation files. I have created a new branch for the work in progress and commit the text from time to time. However, in the end I want to have one commit for the blog entry, since I do not care how I got to the end result, I just want to save in between.
So here are my commits in my local branch
$ git log --oneline --decorate 53a53dd (HEAD, blog) Some last modifications 3c494d9 Add conclusion, remove more TODOs f20e47b Remove TODOs bebcc78 Benefits and Drawbacks 843b6e9 Finished workflow section e3aa37c Some minor corrections b47eec4 Add example 92009c7 Until benefits 7ee81bc First draft of blog
git merge --squash blog on branch
master, as you can see, there is only one new file in the staging area:
$ git status On branch master Your branch is up-to-date with 'origin/master'. Changes to be committed: (use "git reset HEAD <file>..." to unstage) new file: blog/blog.mdown
After committing the finished blog my history looks this way:
$ git log --oneline --decorate --graph --all * 2281abe (HEAD, master) Git blog entry about 'merge --squash' | * 2cca283 (blog) Updated example | * 53a53dd Some last modifications | * 3c494d9 Add conclusion, remove more TODOs | * f20e47b Remove TODOs | * bebcc78 Benefits and Drawbacks | * 843b6e9 Finished workflow section | * e3aa37c Some minor corrections | * b47eec4 Add example | * 92009c7 Until benefits | * 7ee81bc First draft of blog |/ * 25690aa (origin/master) Add PDF for latest version
blog commits (
7ee81bc through to
2cca283) have been squashed into commit
If used responsibly, Git’s capabilities in rewriting history can be very helpful. The local
merge --squash workflow can safely store work-in-progress and hence protect your work from accidental modification or loss (this does not apply to
git stash for example, since you can always
As always, you don’t have to use this feature, Git just makes it possible for those who want to. So go ahead and try! It certainly changed the way I work locally.