We use git for version control. In this article we’ll go through our current workflow, present you with some tips on things you can do to keep your co-workers happy, and describe a couple of our favorite commands in order to encourage you to use the tool more.
Make sure that your
~/.gitconfig is properly configured. It should, at a minimum, contain the following:
[user] name = <your name> email = <email@example.com> [init] defaultBranch = main
Use feature branches
Note: We’re going to assume that you’re working against
main in the text below. Replace that with
development or whatever your team might be using as the primary branch for development.
We rely mostly on Feature branching during day-to-day operations. Encapsulating features in branches works well with our other practices and makes it easy to work on features in parallel without disturbing the main codebase.
Whenever a developer (or pair) starts working on a new feature they create branch off of the latest version of
main. The branch gets a descriptive name in the form of
Other prefixes can be used to add context about certain types of branches. Bugs should be fixed in branches following the pattern
fix/session-timeout-issue and experimental branches can be prefixed like
Make your changes, commit, test, and push as if you were working on
When you’re done, make sure your local
main is up-to-date with upstream
main and merge the updated version into your feature branch. Resolve any merge conflicts and run the tests again.
If you’re working with code reviews you can now create a merge request. Fix any problems with locally in the feature branch to ensure that they are visible in the MR.
If you’re not working with code reviews you’re free to merge the code into
main at this point.
Note: We generally prefer merging over rebasing during normal conditions. We like the traceability of merges and we’re not overly concerned with keeping the history “clean”. If we find a particular commit a bit shaky, and want the ability to undo it easily, we can squash it with
git merge --squash <branch> and create a new descriptive commit message for the feature.
Be sure to delete the feature branch when the dust has settled. Especially if you’re using squash merging as there’s no reference to the feature branch in the history!
General things to consider
- Make incremental, small changes to prevent unnecessary conflicts and to ensure that the code is shared within the team frequently.
- Keep commits reasonably atomic. Two bugs fixed? Two commits. A bunch of related changes? Might be nice to have in a single commit.
- Write descriptive commit messages. Start with a short summary in imperative mood and follow up with a more detailed description in the body of the message. The body is optional, but it is an oftentimes useful medium to convey implementation details or reasons for doing things a certain way.
Use the tool more
The versatility of git is impressive. The documentation is immense and – while really well-written – can be a bit overwhelming. This section contains a couple of useful features that you may want to add to your daily workflow.
Modify last commit
You can use
--amend to add staged changes to the previous commit (adding a file you forgot to stage in a commit for example) or to change the last commit message if there are no local changes:
git commit --amend
Quickly switch to the previous branch
You can switch to the previously checked out branch with:
git checkout -
Sometimes you’re uncertain when something problematic was introduced into the codebase. Normally you’d go back in time to find a commit that does not have the problem and start going forward until you find the commit that introduced it. This linear approach can be very time consuming in larger projects.
git bisect speeds this process up by performing an interactive binary search of the history.
Start the process:
git bisect start
You’re now in bisect mode! You need to find a good and a bad commit to get started. Poke around using
git log and
git checkout to find one of each and tell bisect about it to continue:
git bisect good <hash of good commit> git bisect bad <hash of bad commit>
The interactive mode will guide you through the rest of the process. You’ll be presented with different commits. Verify whether the problem exists in the commit or not and mark it as good or bad using the commands mentioned above. If the problem does exist in the commit bisect checked out you can run:
git bisect bad
If it wasn’t present, let bisect know with:
git bisect good
After a series of checkouts you’ll eventually end up with the commit that introduced the problem.
When you’re done, or if you at any time want to stop bisecting, simply run:
git bisect reset
Interactively select parts of tracked files
You can interactively select which parts of tracked files you want to add to a
commit with the following:
git add -p
That will start an interactive session in which you can choose to stage a “hunk” (diff terminology, essentially means a change), not to stage a hunk, split it etc. You can use
? during the interactive session to get a description of the different commands that are available.
It is often best to use
git revert when undoing commits. That way we’re not
touching the commit history more than necessary.
Locate the commit you want to revert using
git log. Then revert the
git revert <hash>
Add any relevant information to the commit message and you’re done.
An alternative, if you just want to undo local commits, is to use
git reset. To undo the last commit you can use:
git reset HEAD~1
When you want an overview of the history and its branches you can use:
git log --all --decorate --graph
Or for an even terser version:
git log --all --decorate --graph --oneline
See what changed since when
Another awesome command is
git whatchanged. You can use it to see what has changed since a specific moment in time:
git whatchanged --since="5 minutes"
Search the log
You can use the
-S flag when running
git log to search the log for code matching the query. Use the
-p flag to display the full diff for each commit.
git log -p -S <query>
Find the culprit :)
git blame is a very useful command when you need some context to understand why a section of a file was modified.
git blame -L 2,3 README.md
The above will show you who was the last to modify lines 2 - 3.