Git tips and tricks

A screenshot of a github repo
Photo by Markus Winkler on Unsplash

Git is an essential development tool, and an endless stream of things to learn. This post is some of the tips, tricks, and configurations I use to make life easier day-to-day. Here's what's below:

Disclaimer: I'm not a git expert. These are just things that have come in handy in my years as a heavy git user.

Git Aliases

Like regular aliases, git aliases can make common commands a lot easier. Here are some of the aliases from my personal .gitconfig:

[alias]
	co = checkout
    st = status
    br = branch
    ri = rebase -i --autostash

So instead of typing git checkout main I can use git co main, and instead of remembering the full interactive rebase command I like, I use git ri. This leads nicely into my next tip.

Git Config

Your local git installation reads from the file ~/.gitconfig for its default settings, and there's a lot you can do in there to make your life easier. Aliases are one example, but there are a TON of configuration options.

Here is my entire current .gitconfig, minus one or two lines:

[user]
    name = justin
[branch]
    autosetuprebase = always
[push]
    default = current
[fetch]
    prune = true
[alias]
    lg = log --graph --pretty=format:'%C(yellow)%h%Creset  %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit -10
	co = checkout
	st = status
	br = branch
    feap = fetch --all --prune
    rc = rebase --continue
    ri = rebase -i --autostash
    fwl = push --force-with-lease
	unstage = reset HEAD
[rerere]
    enabled = true
[core]
    editor = /usr/bin/vim
	ignorecase = false
[url "git@github.com:"]
	insteadOf = https://github.com/
I have a whole post devoted to my git lg alias

Use --stat

Git's --stat option gives you an overview of changes that have been made, on a per-file basis. Here's an example using the popular python package flask.

Using git lg, I see there was a merge 3 weeks ago:

screenshot of a merge

But what exactly was changed?

Git show --stat

Now I could go to github ui and find the above commit to investigate, but first let's get a quick overview with git show {commit_hash} --stat:

results of git diff --stat on a merge commit

Now I know exactly what files changed, and I can dig deeper if needed.

Git diff --stat

The --stat option is also useful when comparing branches locally. I've added a single commit to a test branch, let's see what I did:

results of git diff --stat
A quick visualization of changes via --stat

I have a separate post about git diff with a bit more detail.

Git Stash

I have a separate post devoted to git stash also, but here are the highlights:

  • git stash - stash your current changes without committing them
  • git stash save "message" - save a stash with a helpful message
  • git stash list - show a list of everything you have stashed
  • git stash pop - remove an entry from your stashes and apply it to your code
  • git stash apply - apply a stash entry without removing it from your stashes
  • git stash drop - remove a stash entry without applying its changes

For more detail, jump over to my git stash post.

Rebasing

Rebasing is a big topic, for which I plan to write an entire post. For now, here are some things I find helpful.

Always rebase -i

The -i stands for "interactive", which means the rebase begins in an editor with an overview of the commit history you're working with:

a screenshot of an interactive rebase
The result of git rebase -i origin/main

It's a quick way to make sure your rebase is doing exactly what you think it should, and it gives you a chance to modify your commit history via the rebase commands1 if desired.

Look into git rerere

If you have a rebase-heavy workflow, you might find yourself resolving the same conflicts each time you rebase your code. With git rerere, you only need to resolve them one time.

Git rerere remembers the resolutions that have been applied in past rebases, and if it sees the same conflict in a subsequent rebase it will resolve the conflict automatically.

[rerere]
	enabled = true
The line from my .gitconfig enabling rerere

Tag your first commit on a branch

This is another tip for rebase-heavy workflows. When rebasing a long-running branch, it can be hard to tell exactly where your personal changes started in the history, and a bad rebase can result in lost code. If there's an obvious tag in your first commit message, you can avoid this problem:

screenshot of an interactive rebase
Imagine this but with 20 commits instead of 3

Some codebases have a built in commit hook which automatically adds information to commit messages, which is great. If not, manually adding a tag to your history is a low-budget way to save yourself some headaches.

Git commit amend

Git commit --amend allows you amend, or modify, your most recent commit. You can update its message, its contents, or both. Here's a quick example:

a screenshot of a git commit with typos in it
oops, this message has typos in it

I'd like to fix the above message, because it looks bad:

fixing a git commit with --amend
git commit --amend -m fixed the message

If you look closely, you'll see that --amend created an entirely new commit hash. If this commit hasn't yet been pushed, you should be ok. But if you're amending a commit that has already been pushed up, you can run into issues. For more details, check out my post about amending commits.

Git cherry-pick

Git cherry-pick provides a way to pick commits off of one branch and apply them to another2. For example, maybe you forgot to checkout a new branch, and you accidentally committed something directly to main. If you still want those changes, you'll probably need to put them on a different branch, since committing directly to main is a no-no. That's where cherry-pick comes in.

a commit message on the main branch
oops, I committed directly to main

Cherry-pick allows you to easily apply this code to a different branch:

an example of git cherry-pick
The changes were cherry-picked using the commit hash

Now you can go back to main and undo that commit, and it'll be like nothing ever happened.

Git reset --hard head~1

This one is a bit of a mouthful. In plain English, this command erases the most recent commit from the branch history. A good time to use this would be immediately after you've cherry-picked!

The workflow would look like this:

  1. Commit to main by accident
  2. Checkout a development branch
  3. Cherry-pick your accidental commit onto your development branch
  4. Checkout main
  5. git reset --hard head~1 to erase the commit from main

Git reset --hard will erase your changes, and you won't be able to recover them; there is also a --soft flag.

Using git reset --soft will roll back the most recent commit, but it'll take its code and put it back into your staged changes, ready to be committed again or modified. For more details, I have yet another post about ways to undo a git commit3.

That's all the tips I have for now, if I think of more I'll come back and update this post. I hope this was helpful!


  1. It's also another good reason to learn Vim, git's default rebase editor.
  2. Cherry-pick is also my personal favorite git command name
  3. It doesn't feel like I've done a ton of writing, but I linked to myself a lot in this one. Good work, me from the past!

Helpful Links