My Top Six Git Tricks

Annie Kiley, Former Application Development Director

Article Categories: #Code, #Front-end Engineering, #Back-end Engineering, #Tooling

Posted on

These are the commands I use every day in my usual workflow.

Git has a ton of powerful features, but the bulk of my usage is the same set of commands with the same set of flags, used countless times every day. Two things happened recently that made me want to write them down. The first is that I was working with an apprentice, and I realized that the details of my typical workflow were actually pretty different from what someone might learn from a tutorial or the docs. The second thing was that I only found out last week how to sort branches by recent activity. I couldn't believe how long it took me to do it that way, so here I am writing a blog post, which I guess is the developer equivalent of shouting it from the rooftops.

1. git branch --sort=-committerdate #

This lists branches in order of recent activity instead of alphabetically. If you, like me, pretty much always want to see things this way, you can make this setting your default by opening your git config file with $ git config --global --edit and adding this:

[branch]
  sort = -committerdate

After that, git branch will always show your most recently used branches at the top.

2. git add -p #

This is short for git add --patch. I use this almost exclusively when staging since I like to review my changes before I commit them. It helps me catch typos, errant debugging statements, or other mistakes. It won't automatically catch untracked files, so if I've added anything brand new, I'll run git add -N . first.

3. git rebase -i HEAD~3 #

I commit a lot while I'm working but like to leave a clean history before I open a pull request. My local commit messages are often notes to myself, like "tests passing but need to refactor database queries" or "created model and migration, do routes next." To get my work ready for a pull request, I do an interactive rebase to combine commits, reorder commits, and rewrite my commit messages so they are in line with project standards and useful for other developers. The "3" above can be replaced with any positive integer, depending on how many commits I want to work with.

4. git log --oneline #

I find that git log takes up too much space, so most of the time I use this when I want to see what's been going on recently. You can get some really lovely output with the --pretty option, but this is almost always good enough for me since it provides a quick list of recent commits without too much extra info.

5. git checkout - #

The - refers to the last branch I had checked out. So if I'm hopping between two branches, this saves a lot of typing. My most common use case for this is when I'm on a branch, let's call it "feature-branch," and want to rebase with main:

$ git checkout main
$ git pull
$ git checkout - # instead of git checkout feature-branch
$ git rebase - # instead of git rebase main

What's nice about this is that I don't have to type the name of my feature branch, so this is the same every time and has become muscle memory.

6. git rebase --onto #

This isn't something I use every day, but when I need to get a branch up to date after things have been moving around, it's perfect. I can't describe it any better than Chris Jones his classic post, How to Fix Your Git Branches After a Rebase.

Example Workflow

If you want to see these configurations and commands in action, here's what my typical workflow looks like in the in the terminal. There's nothing new down here, just examples, so if you aren't interested in seeing those, thanks for reading this far!

# Navigate to the project directory.
$~/P/blog_posts> cd my_app/
# Check out a new branch.
$~/P/b/s/my_app (abk/old-feature-branch)> git checkout -b abk/new-feature-branch
Switched to a new branch 'abk/new-feature-branch'
# Take a look at all my branches.
$~/P/b/s/my_app (abk/new-feature-branch)> git branch
* abk/new-feature-branch
  abk/old-feature-branch
  main
#
# ...
# Nothing to see here, but I opened my text editor
# and made some changes that include a new file.
# ...
#
# Tell git to track my new files.
$~/P/b/s/my_app (abk/new-feature-branch)> git add -N .
# Stage my changes in hunks.
$~/P/b/s/my_app (abk/new-feature-branch)> git add -p
diff --git a/README.md b/README.md
index 7db80e4..4c069bd 100644
--- a/README.md
+++ b/README.md
@@ -22,3 +22,5 @@ Things you may want to cover:
 * Deployment instructions

 * ...
+
+ This is a change to the readme.
# Use "y" to tell git that I want to stage this change.
(1/1) Stage this hunk [y,n,q,a,d,e,?]? y

diff --git a/new_file.md b/new_file.md
new file mode 100644
index 0000000..f317fcc
--- /dev/null
+++ b/new_file.md
@@ -0,0 +1 @@
+ This is a brand new file!
# Use "y" again to stage this change too.
(1/1) Stage this hunk [y,n,q,a,d,e,?]? y
# Commit my work with a note about what I need to do next.
$~/P/b/s/my_app (abk/new-feature-branch)> git commit -m "Added stuff, need to add more stuff"
[abk/new-feature-branch 8b20fd3] Added stuff, need to add more stuff
 2 files changed, 3 insertions(+)
 create mode 100644 new_file.md
#
# ...
# Nothing to see here, but I opened my text editor
# and made some more changes.
# ...
#
# Stage my new changes in hunks.
$~/P/b/s/my_app (abk/new-feature-branch)> git add -p
diff --git a/new_file.md b/new_file.md
index f317fcc..898d4e8 100644
--- a/new_file.md
+++ b/new_file.md
@@ -1 +1,3 @@
 This is a brand new file!
+
+And now this file is complete.
\ No newline at end of file
# Oh shoot, I don't have a newline at the end of the file and I should!
# Use "n" to not stage it
(1/1) Stage this hunk [y,n,q,a,d,e,?]? n
#
# ...
# Nothing to see here, but I went back and fixed that in my text editor.
# ...
#
# Okay, let's try staging these changes again now that I fixed my mistake.
$~/P/b/s/my_app (abk/new-feature-branch)> git add -p
diff --git a/new_file.md b/new_file.md
index f317fcc..e9a07c2 100644
--- a/new_file.md
+++ b/new_file.md
@@ -1 +1,3 @@
 This is a brand new file!
+
+And now this file is complete.
# Looks good now, so use "y" to tell git that I want to stage this change.
(1/1) Stage this hunk [y,n,q,a,d,e,?]? y
# Use git status to check that everything is staged.
$~/P/b/s/my_app (abk/new-feature-branch)> git status
On branch abk/new-feature-branch
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	new file:   new_file.md
# Looks good, so I commit everything.
$~/P/b/s/my_app (abk/new-feature-branch)> git commit -m "Okay feature is all done"
[abk/new-feature-branch e94ad5a] Okay feature is all done
 1 file changed, 2 insertions(+)
# Do an interactive rebase to squash these commits and clean up my message.
$~/P/b/s/my_app (abk/new-feature-branch)> git rebase -i HEAD~2
#
# ...
# Nothing to see here, but I squashed the two commits together and
# rewrote the commit message to be something more useful.
# ...
#
[detached HEAD 2f2a858] Add doc file and update readme
 Date: Tue Sep 20 11:08:53 2022 -0400
 2 files changed, 5 insertions(+)
 create mode 100644 new_file.md
Successfully rebased and updated refs/heads/abk/new-feature-branch.
# Check the commit history to make sure it looks right.
$~/P/b/s/my_app (abk/new-feature-branch)> git log --oneline
2f2a858 (HEAD -> abk/new-feature-branch) Add doc file and update readme
30c9572 (main, abk/old-feature-branch) Initial commit
# Check out main and pull any recent changes
# (in this case, there aren't any, but I always check).
$~/P/b/s/my_app (abk/new-feature-branch)> git checkout main
Switched to branch 'main'
$~/P/b/s/my_app (main)> git pull
Already up to date.
# Go back to my feature branch and rebase with main
# (not necessary here since main didn't have anything new).
$~/P/b/s/my_app (main) [1]> git checkout -
Switched to branch 'abk/new-feature-branch'
$~/P/b/s/my_app (abk/new-feature-branch)> git rebase -
Current branch abk/new-feature-branch is up to date.
# Push my work up the remote and open a pull request!
$~/P/b/s/my_app (abk/new-feature-branch)> git push origin abk/new-feature-branch

Related Articles