[Git] The lesser known features and commands of git
by Riley MacDonald, November 5, 2017

After reviewing the pro git book I found the following git features and commands I didn’t realize existed. Here’s the topics covered in this post:

Interactive Staging
Git includes an “interactive” mode to ease command line use. Interactive mode is especially helpful when you have several files changed but only want to commit certain files or even certain parts of the changed files. Enter interactive mode using -i or interactive:

rmacdonald-XPS-15-9560 ~/Documents/Android/my_project (my_git_branch) $ git add -i
           staged     unstaged path
  1:    unchanged        +2/-1 Project/app/src/main/java/com/my/project/Class1.java
  2:    unchanged        +4/-3 Project/app/src/main/java/com/my/project/Class2.java
  3:    unchanged        +5/-1 Project/app/src/main/java/com/my/project/Class3.java
*** Commands ***
  1: status	  2: update	  3: revert	  4: add untracked
  5: patch	  6: diff	  7: quit	  8: help
What now>

You’ll be given a what now prompt with options listed under *** Commands ***. These options are:

1: status / 6: diff / 7: quit / 8: help

These are self explanatory commands (equivalent to git status, git diff, exit/ctl+c and a help menu.

2: update

Changed files are listed by number (see above). Using these numbers you can quickly add (stage) whole files by their listed number. To add Class1.java and Class2.java to staged enter 1,2:

$ what now> 2
$ update>> 1,2

3: revert

You can unstage using revert by choosing option 3. For example you can unstaged Class1.java by:

$ what now> 3
$ Revert>> 1

4: add untracked

Add all untracked files just by choosing option 4.

$ What now> 4
  1: new_file
  2: another_new_file

5: patch

It’s possible to commit only partial changes of a single file while omitting other changes and leaving them unstaged by using the patch option:

rmacdonald-XPS-15-9560 ~/Documents/Android/my_project (local_test) $ git add -i
           staged     unstaged path
  1:    unchanged        +3/-0 Project/app/src/main/java/com/Class1.java
*** Commands ***
  1: status	  2: update	  3: revert	  4: add untracked
  5: patch	  6: diff	  7: quit	  8: help
What now> 5
           staged     unstaged path
  1:    unchanged        +3/-0 Project/app/src/main/java/com/Class1.java
Patch update>> 
diff --git a/Project/app/src/main/java/com/Class1.java b/Project/app/src/main/java/com/Class1.java
index e53448071a..73763261c2 100644
--- a/Project/app/src/main/java/com/Class1.java
+++ b/Project/app/src/main/java/com/Class1.java
@@ -119,6 +119,8 @@ public class Class1 {
+    // Add this change
Stage this hunk [y,n,q,a,d,/,j,J,g,e,?]? y
@@ -347,6 +349,7 @@ public class Class1 {
+        // Dont add this change
Stage this hunk [y,n,q,a,d,/,K,g,e,?]? n
rmacdonald-XPS-15-9560 ~/Documents/Android/my_project (local_test) $ git status
On branch local_test
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
	modified:   Project/app/src/main/java/com/Class1.java
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)
	modified:   Project/app/src/main/java/com/Class1.java

Voila, you have staged a partial change from Class1 while keeping the other changes unstaged. The same file is both staged and unstaged.

Git Rerere
Git rerere stands for “reuse recorded resolution”. The idea is that git remembers how you chose to resolve hunk conflicts and applies them again in the future instead of having you resolve them again manually. This is particularly handy for long lived “feature” branches away from the “master” branch. With rerere enabled you can periodically perform a merge, resolve the conflicts then back out of the merge. Git will remember how you resolved the conflicts along the way. When it’s time to merge (where you would normally have to go through many conflicts) git will apply all the fixes you applied in the past manually greatly simplifying the merge process. To enable rerere globally enter:

$ git config --global rerere.enabled true

To work with rerere use the following workflow:

# show pre-merge recorded state
$ git rerere status
# will show the current state of the resolution
$ git rerere diff
# Fix the conflicts and add and commit the conflicted file
$ git add conflicted_file
$ git commit
# Reset the changes as rerere has saved them
$ git reset --hard HEAD^

When it comes time to merge/rebase the feature branch for a pull request all the conflicts resolved using the above workflow will be automatically applied.

Git Log / Shortlog
Git can format logs and changelogs by author, email, format, etc. Documentation for git log / shortlog

Git Patches
If you want to send someone changes you have on your local machine without committing them use the ">" unix operator. For example:

# generate a git patch file named patch_name containing the current changes
git diff > patch_name

Anyone who has the file patch_name can apply it to their local by running:

# apply the patch
git apply patch_name

Also see Git format-patch – Prepare patches for e-mail submission.

Show Conflicted Files
When dealing with conflicted files (during a merge for example) you can list the affected files by running:

$ git ls-files -u

Managing Git Stash
git stash is a handy tool for saving changes to your local without committing them. Here’s a few git stash features I wasn’t aware of:

# remove a stash from stack
git stash drop
# apply and remove a stash from the top of the stack
git stash pop

Git Clean
git clean is used to remove untracked files from the local working tree. Clean also has an interactive mode (-i) that can be used to accelerate the process. See Git Clean Documentation for more information including all of the available arguments.

Git Grep, Log and Line Log
Git Grep:
Works like unix grep except it searches through the entire git tree and history. Has many configurable options for filtering, display and more. For example if you’re looking for the name of something (such as a function, var, etc.) that was potentially renamed you can:

$ git grep method_name
Project/path/app/File.java:    void method_name(String arg);

Git Grep Documentation for more information including all of the available arguments.

Git Log Search:
Useful if you’re searching for where something was introduced. It’s basically git blame but performs a search instead. For example if you’re looking for when a constant variable was introduced you could:

$ git log -S SAVED_SESSIONS_KEY --oneline
c53a688044 Refactored class honeybee with fabulous new methods
a35525861c Added support for new fantastic feature

Commit Template
Good commit messages make reviewing pull requests and commits more descriptive and efficient. You can automate this process by editing your commit.template. Edit the ~/.gitconfig file with the following.

  template = ~/.gitmessage

Add the new ~/.gitmessage file containing a template such as the following:

Purpose of change:
Required By:

Anywhere your commit message appears (for example during pull requests) will automatically be populated with the template keeping communication consistent.

Git Pretty Log
I prefer to use the command line while working with git. I’ve relied on an alias named lol to display a “tree” style graph to analyze branch status, tags, etc. Add the following entry to your ~/.gitconfig file to utilize lol:

        lol = log --graph --decorate --pretty=oneline --abbrev-commit --all

Then run the command:

$ git lol
* 83bc947 (HEAD, origin/develop, develop) Added device frames to playstore screenshots.
| * 26df0c3 (origin/issue-131, issue-131) issue-131: bump slide day time picker build tooling versions.
*   3cc3a8c (tag: 1.0.2) Merged in issue-130 (pull request #87) Issue-130: 1.0.3 release
| * 77d9a27 (origin/issue-130, issue-130) issue-130: 1.0.3 release
*   2b22c85 Merged in issue-129 (pull request #86) Issue-129: fix comma issue with fr locale.

You’ll get colored output indicating the state of each commit / branch. Navigate up and down with j and k. Perform searches with /.

Git Autocomplete
You can enable linux style autocompletion to your commands (press tab to autocomplete) by adding the autocomplete.bash script to your local machine. Git Autocomplete GitHub. Add it by running:

# Save the script to your local machine
curl https://raw.githubusercontent.com/git/git/master/contrib/completion/git-completion.bash -o ~/.git-completion.bash

Then adding the following snippet to your ~/.bash_profile or ~/.bashrc (depending on your local configuration:

if [ -f ~/.git-completion.bash ]; then
  . ~/.git-completion.bash

You should now be able to autocomplete git commands and even branches found on your local machine.

Quickly Switching Between Branches
Similar to cd - you can quickly switch to the last checked out branch using git checkout -

# on develop, checking out branch issue-143
(develop) $ git checkout issue-143
# on branch issue-143, checking out develop
(issue-143) $ git checkout -
# back on develop
(develop) $

I prefer to use the command line interface of git over GUI applications such as sourcetree. The above commands have accelerated my efficiency with git allowing me to focus more on development and less on VCS.

Open the comment form

Leave a comment:

Comments will be reviewed before they are posted.

User Comments:

Be the first to leave a comment on this post!