DEV Community

Andrew Steele
Andrew Steele

Posted on

My Favorite Git Helpers

You can find all of these aliases and functions (and then some!) on my Github here:Â https://github.com/Andrew565/dotfiles. Read on for detailed explanations of what they are and what they do, and be sure to also check out my preferred git workflow.

I use bash in my terminal. I know ZSH and fish and all the rest have their niceties, but I started with bash, and I like it fine enough, so that's what I use.

My favorite thing to do in bash? Create aliases and helper functions for everything, especially Git commands. So, here's a list of some of my favs.

Bash Aliases

# Git Aliases
alias g="git"
alias gs="git status"
alias gl="git log"
alias grh="git reset --hard"
alias gcmm="git checkout --"
alias gsm="git stash && git co master && git stash pop"
alias gsd="git stash && git co development"
alias gmd="git merge development"
alias gmm="git merge master"
alias gupdate="git co development && git pull"
alias glatest="git co development && git pull"
alias gmupdate="git co master && git pull"
alias gcm="gmupdate"
alias gphm="git push heroku master"
Enter fullscreen mode Exit fullscreen mode

Most of these are probably self-explanatory. Here are a couple commands that may not be immediately obvious:

alias gsm="git stash && git co master && git stash pop"

This is invaluable when I do work in a feature branch that I actually wanted in the master branch. This doesn't happen as much anymore since most of the time I never commit directly to master, but it happens.

alias gcmm="git checkout --"

This command is when you have a file staged for commit and you don't actually want it to be part of the current commit. It could also be aliased as 'unstage'.

Bash Functions

Aliases will only get you so far. Sometimes you want to be able to bundle function calls together, or use variables. That's where bash functions come in.

gnew - Create a new branch

# create new branch from a default named branch
# modify the first line to make it an argument if desired
gnew() {
 DEST_BRANCH=$2
 : ${DEST_BRANCH:='master'}
 git co $DEST_BRANCH
 git pull
 git co -b "$1"
 # bundle install # If using Bundler (ruby)
 # bundle exec rake db:migrate
 git push -u
}
Enter fullscreen mode Exit fullscreen mode

As it says, this creates a new branch based off of another branch. If you don't specify which branch to branch off of, it assumes/defaults to the 'master' branch. Use like this:

gnew new-branch-name old-branch-name

It then checks out the old branch/master, pulls to make sure you're branching off of the latest revision, then creates a new branch using the name you provided as the first argument. Commented out are commands to run bundler and rake db:migrate, only useful if you're working on a Ruby/Rails project. Finally, it does git push -u, which pushes up the new branch and sets up the local branch to track the remote version, which makes future push and pull commands more seamless.

grm - Git Rebase Master

# Get the latest changes on master pulled down locally
# and then rebase them into/onto the current branch
grm() {
  CURRENT=`git rev-parse --abbrev-ref HEAD` # figures out the current branch
  git checkout master
  git pull
  git checkout $CURRENT
  git rebase master
}
Enter fullscreen mode Exit fullscreen mode

In my preferred workflow I always rebase the latest commits from master into my feature branch before I commit it. This keeps merge conflicts to a minimum and helps to keep the commit history clean.

gsrm - Git Stash && Rebase Master

# Stash current, then update to latest, then pop the stash
gsrm() {
  git stash
  grm
  git stash pop
}
Enter fullscreen mode Exit fullscreen mode

Similar to grm (and it even makes use of grm), this stashes whatever you're currently working that hasn't been staged/committed yet, then does the rebase, and then pops it out again. SUPER USEFUL if you know of upstream changes that you want to bring into your feature branch but what you're working on isn't ready to be committed. Side Note: don't use this as an excuse NOT to commit often. You should definitely still do that.

gswitch - Quickly checkout branches

gswitch() {
  BRANCH=`git branch | grep "$1"`
  git checkout $BRANCH
}
Enter fullscreen mode Exit fullscreen mode

Switch branches by issue number or feature keyword. For example:

gswitch 1808 == git checkout features/1808-click-on-avatar

NOTE: only works well if you use a unique description, thus the recommendation to use issue numbers. Also works best if you delete your already-merged local branches regularly.

.gitconfig

If you're not taking advantage of a global .gitconfig file, you're doing Git wrong. Here too I have a bunch of aliases, and a couple functions.

aliases - Lookup what aliases you have

aliases = !git config --get-regexp 'alias.*' | colrm 1 6 | sed 's/[ ]/ = /'

I so need to recreate this in bash, I have a hard time remembering all of the aliases I've created (there are a lot of them). 😝

cam - Commit while Adding files and attach a Message

cam = commit -am

This is (essentially) the same as:

git add . && git commit -m "your message"

Be careful that you don't use this if you have any unstaged files you don't want to be committed, as it will add everything to the commit.

last - What is the last thing I committed?

last = cat-file commit HEAD

co - Checkout

co = checkout

delete-local - Clear out old branches quicker

delete-local = branch -d

Somehow it's easier for me to remember git delete-local than git branch -d.

delete-remote - Clear out remote branches quicker

delete-remote = "!sh -c 'git push origin :$1' -"

CAUTION: This doesn't ask if you know what you're doing before you do it, so be careful!

branches - Get a list of all of your local branches

branches = "!sh -c 'git branch -a | grep -v remotes'"

You can get rid of the grep -v remotes if you want a list of remote branches too. This is another alias for 'natural language' purposes, just feels better to type git branches.

edit-unmerged & add-unmerged - Fix merge conflicts like a boss

# use like `git edit-unmerged; ...edit..., ...test...
# git add-unmerged; get commit || rebase --continue
edit-unmerged = "!f() { git diff --name-status --diff-filter=U | cut -f2 ; }; code `f`"
add-unmerged = "!f() { git diff --name-status --diff-filter=U | cut -f2 ; }; git add `f`"
Enter fullscreen mode Exit fullscreen mode

This saves me so much time it's ridiculous. Basically, edit-unmerged looks at all of your files that are marked as "unmerged", meaning they have conflicts that need to be resolved. Then it opens them up in your code editor (replace code above with the cli alias for your preferred editor, vi, emacs, subl, etc.). When you're done, add-unmerged finds that list of unmerged files again and does git add on them (and only them, so you don't have to worry what else might get added). At this point, everything should be staged, so you can run git commit or git rebase --continue.

Final Notes

Remember that a good craftsman never blames his tools. These helpers are not intended to be substitutes for actually knowing what you're doing. 😉 Here again is a link to my Github repo with these files: https://github.com/Andrew565/dotfiles.

Top comments (7)

Collapse
 
samipietikainen profile image
Sami Pietikäinen

Great tips! I also like to use git-completion (shell auto-complete with git command line arguments, branches etc.) and git-prompt (show branch status in prompt when inside a git repository) when working with git.

Here's how to set them up: pagefault.blog/2017/02/16/improved...

Collapse
 
ben profile image
Ben Halpern

Great post Andrew!

Collapse
 
jandedobbeleer profile image
Jan De Dobbeleer

I'm stealing edit-unmerged. Nice 👍🏻

Collapse
 
der_gopher profile image
Alex Pliutau

What about this tool, which simplifies opening repo in browser from terminal.

github.com/plutov/o

Collapse
 
arandilopez profile image
Arandi López

grm seems so great! I will give a try

Collapse
 
gynidark profile image
Brandon S.

Thank you !

Collapse
 
maestromac profile image
Mac Siri

Time to rework my workflow. Thank you for this awesome post!