When I career switched into tech, the two big management shocks were daily standup and
git. And I mean that in a good way, a very good way. I love
git very much, and am starting to get opinionated about it. It's not just version control! It's history, and narrative, and structure. It's collaboration! It's TEAM. It's a beautiful tree spawning many branches. Or a lot of hair with a lot of braids that need to get re-braided. I like to keep my repos like little bonsais or Princess Leia buns of good practice.
git is not to be neglected! And often is!
This tutorial assumes that you have used
git, at least a little bit. That is, you know that it's a version control system, you've made some commits, pushed and pulled, and have an account on GitHub. If you're very new to
git, then I highly recommend Udacity's How to Use Git and GitHub.
Some philosophy: Git as history (AKA the power of
I think the main power of
git is that it tells a story of your project. Sometimes I get lazy and just rely on
git to, well, not lose all my stuff. And this is, yeah, its big sell. But, if you write good (long!) commit messages and commit at the Right Time, and if you wield the majestic power of
git squash and
git rebase with aplomb, I think you can create quite a beautiful, readable little story, something to be passed down from collaborator to collaborator. This is useful for welcoming new team members, or for dealing with the passage of time (why did you write it that way, all those months ago?).
Here are some stuff I find helpful in
1. Visualize your history
There are several ways to visualize git histories:
- Tower ($80/license) - A very pretty GUI, integrates nicely with GitHub.
gitk- A built-in command-line "graphical repository browser" that ships with git. Uglier GUI than Tower.
- A bash alias:
alias glg='git log --graph --full-history --all --color --pretty=format:"%x1b[31m%h%x09%x1b[32m%d%x1b[0m%x20%s"'
I don't know who wrote the above. Someone at my old gig? It was passed down to me from the ancients. If this was you, please let me know. I feel super guilty sharing some mystery code like this. Please let me assuage my guilt and just say you wrote this.
Anyway, the point is: find some way to visually navigate through the commit history and the various branches. Git is surprisingly/eerily smart about tracking when things are happening in relation to each other. Seeing all that is powerful and informative. I
glg repeatedly throughout the day. I just checked now --
history | grep glg | wc -l >> 34
-- 34 times! That's 13 times an hour, or once every 4.6 minutes.
Okay, maybe I check it too much.
2. Pick a comfy editor
Git uses your global default
$EDITOR as its own. I think that's Vim on OSX? Or is it
nano? Anyway, I like Sublime as my lightweight "small jobs" editor. If you want to change your default text editor for
git to Sublime (but keep whatever
$EDITOR for other stuff), then:
git config --global core.editor "subl -n -w"
You can also do Atom or TextMate, or anything that launches from the command line.
Having a comfy/friendly text editor is important so I can write long, involved commit messages (further reading: How to Write a Git Commit Message).
3. Rewrite history (responsibly):
When we're working on our local machines, we can create as many branches as we like, however we like. We can commit whenever and whatever. But this can get messy when we start sharing that history around.
One way to keep things clean is to combine many commits into one big commit (
git squash) and to rewrite our git history such that our suggested changes are always on top of the newest version of code (
Git squashing and rebasing is useful but potentially destructive. It rewrites git history. I think a good general rule of thumb is: rewrite your own history, not other people's. In other words, right before submitting a pull request, you can combine all your branch commits into one - "This is my final version!" - and you rebase that one commit on top of the latest
develop branch such that it looks like you used the freshest codebase to start your branch from.
But you never want to squash or rebase
git rebase is distinct from
git merge since it doesn't merge in other people's commits (thus sullying your story), but rather just pretends you started work on whatever the latest code is.
The end goal is this:
Let's assume you've been working on a branch for a few days. You have some code you want to PR into
- Update your local copy of the master branch with any remote commits.
git fetch git pull
- If there are any updates, rebase your work on top of those changes in master.
git checkout [my branch] git rebase master
This might be a pain point: merge conflicts. Untangle each of them in turn (I like grepping for
<<< in the conflict files),
git add . them and then
git rebase --continue.
Now it should look like this:
- Squash your commits (which you can count down from
HEADto where your work begins, or use a specific commit's SHA) into one final commit. For example, say you wanted to squash the last five commits:
# Rebase by counting down from the HEAD... git rebase -i HEAD~5 # ...or by selecting a specific, older commit's SHA git rebase -i 9b20280
-i flag will launch
git's default editor. There, you select which commits to keep as separate commits (
p) and which to combine (
Pro tip: If you forget the
gitwill not squash anything, and will just exit out back to your shell.
pick your branch's first commit, and
s (squash) all the others.
Next, git will prompt you to adjust the squashed commit message.
Check your git history, and voila! You should see that all those commits collapsed into one!
4. Keep polishing your git skills
In my day to day
git, I've always tried to note down the random stuff I've learned about how to use it. Can I search for a specific piece of code? Even if it's been deleted? Can I search for a deleted file? Stuff like that. The mystical
.git file keeps track of so much, and it's great to be able to essentially trawl back through all these different versions of the past.
Here are some useful recent TILs:
- To search all commit history for when a
git log -Sstring
- To compare the differences between specific commits:
git diff COMMIT_SHA^ COMMIT_SHA
- To remove stuff from the staging area:
(I know, I know. That one should be basic, but I almost never used it, yolooooo.)