If anyone have ever browsed the git manual (man git), then one may have noticed there are a whole lot more to git than what most of us use on a daily basis.

Most of these commands are incredibly powerful and can make developers life a lot easier. Some of them are superficial and helps in chores.

21 Git Commands you probably didn't know

Here we are going to cover 21 such under-utilised git commands; which, when used can level up developers productivity and make life easier

Contents

  1. Git Tag - How to create version tags
  2. Git Web - How to use builtin GUI
  3. Git Reflog - How to know actions taken
  4. Git Log - How to view commit logs
  5. Git Cherry Pick - How to pick a commit
  6. Git Notes - How to attach info to commits
  7. Git Diff - Compare changes between two files
  8. Git Hooks - How to execute scripts on git command
  9. Git Blame - How to blame code or developer ;)
  10. Git Bisect - How to debug git commits
  11. Git Grep - How to search git repo
  12. Git Archive - How to share git project
  13. Git Submodules - How to have repo within a repo
  14. Git Bugreport - How to build a bug report using git
  15. Git Fsck - How to verify and recover
  16. Git Stripspace - How to autoremove whitespaces
  17. Git LFS - How to store big files in git
  18. Git Garbage Collection - How to GC git repo
  19. Git Show - How to inspect git objects
  20. Git Describe - How to get readable names for tags
  21. Git Switch - How to jump among branches

21 Git Commands you probably didn't know

Git Tag

This is one such command from git’s kitty, which one may have seen; being used. This is a nicer and more human readable way to tag a commit SHA with anything more easy to read and remember then SHA. It is most commonly used to denote versions of releases. To tag a commit, one shall use

git tag <TAGNAME>

Where TAGNAME is human readable tag name. This will tag HEAD of current git repository branch. To tag any commit in git log history, one shall use

git tag -a v1.1.2 <COMMIT_SHA_ID>

Where COMMIT_SHA_ID is SHA of commit we are willing to tag. Like with commits, one can also include a message alongside a tag, using -m flag.

Remember; tags are not automatically pushed to remote. These tags needs to pushed manually to remote repositories. To push these tags to remote; one shall use

git push origin <TAGNAME>

Where TAGNAME is name of the tag, to be pushed to remote origin. To see list of all tags, just run git tag. One can optionally use -l for a wildcard tag search. You’ll then be able to checkout a specific tag, with git checkout <tagname>. Here is the official documentation.

Git Web

Git has a built-in web-based visualiser for browsing local repositories, which lets you view and manage repositories via a nice GUI in the browser. To use this feature one need to have Lighttpd installed or provide httpd servers via --httpd= or -d option. To use this one shall run

git instaweb
//OR
git instaweb --httpd=nginx

This should now be accessible a http://127.0.0.1:1234/

Git web provides following useful features

  • Browsing and stepping through revisions and inspecting diffs, file contents and metadata
  • Viewing commit logs, branches, directories, file history, and attached data visually
  • Generating RSS or Atom feeds of commits and repository activity logs
  • Searching commits, files, changes and diffs

If you don’t have Lighttpd installed, you can specify an alternative web server with the -d flag. Git instaweb also provides other options to override defaults. For example to change port one can use -p flag, -b for browser to open. Moreover; one can configure these options in .gitconfig under [instaweb] block

There’s also the git gui command, which can open up a GUI-based git app. To use git gui, it needs to be configured via .gitconfig. Official documentation can be found here

Git Reflog

Ever wondered, how git keep tracks of updates to the file(s)? Git also keeps tracks of updates to the tip of branches using a mechanism called reference logs or reflog. Using this, various events are tracked, including, clone, pull, push, commit, checkout and merge. It’s often useful to be able to find an events reference, as many commands accept a ref as a parameter. To see recent events on HEAD one shall run

git reflog

So what’s the use of reflog? One use is that reflog is recovering lost commits. Git never really loses anything, even when rewriting history (like rebasing or commit amending). Reflog allows developer to go back to commits even though they are not referenced by any branch or tag.

By default reflog uses HEAD (one current branch), but you can run reflog on any reference. To run reflog on branch other than current, one shall use

git reflog show <BRANCH_NAME>

To run reflog on stash, one shall use

git reflog stash

To run reflog against all references use

git reflog show --all

Git Log

This one is already popular git command. So one may already be familiar with running git log to see commits history of current branch. But there are many thing you may do using git log. For example, to see a neat commit graph with ref pointers, one may use

git log --graph --decorate --oneline

21 Git Commands - Git Log

One may also often need to be able to filter logs based on various parameters, the most useful are

  • git log --search="<search-keyword>" - Search logs for specific keyword as specified

  • git log --author="<name_or_email_of_author>" - Show log only for specific author(s)

  • git log --grep="<pattern>" - Filter log using search keyword or regular expression

  • git log <since>..<until> - Show all commits between two references as mentioned

  • git log -- <file> - Show all commits made only to a specific file

  • git shortlog for a summerized list of commits.

We can refer official documentation here

Git Cherry Pick

Sometimes we do not wish to merge entire feature branch into active development branch. We only wish to pick few commits that are important or needed. This is very useful for applying hot-fixes, restoring lost commits and in certain other specific situations. To pick and merge only specific commit, git provides us cherry-pick command. To cherry-pick a commit one shall use

git cherry-pick <COMMIT_SHA_ID>

Note: That often traditional merges are better practice, since cherry picking commits can cause duplicate commits in the log. Cherry pick also changes SHA id and hence comparing commits may lead to duplicate commits

Git Notes

Git commit messages are great. But we may sometime need additional messages/notes to be attached to a commit. Git provides git notes for the rescue

These notes are stored within .git/refs/notes. This is separate from from commit object, this can be modified without SHA hash getting changed. Isn’t it Brilliant?

To add a note to HEAD, one shall use

git notes add -m "<GIT_NOTES_HERE>"

To add notes to specific commit use SHA commit id, like following

git notes add -m "<GIT_NOTES_HERE>" <COMMIT_SHA_ID>

You can view notes with git log, using most git GUI apps, or with the git notes show command. Some git hosts also show notes in the commit view (although Github no longer displays notes).

We can refer official documentation here

Git Diff

With git diff you can compare the difference between 2 sets of code

You’re probably aware that you you can run git diff to show all changes since the last commit, or use git diff <COMMIT_SHA_ID> to compare either 2 commits, or 1 commit to the HEAD. But there’s much more you can do with the diff command.

You can also use it to compare any two arbitrary files, with git diff <FILE1> <FILE2>. Even when these are not part of any active git repository. It can also be used to compare two branches, or refs with each other. To use this one shall run git diff <BRANCH1>..<BRANCH2>. Note that a double dot (..) is the same as a space and indicates the diff input should be the tip of the branches, but you can also use a triple dot (…) to convert the first parameter into a ref of the shared common ancestor commit between the two diff inputs.

If you want to only compare a single file across branches, just pass the files name in as the third argument. Like following

git diff <BRANCH1>..<BRANCH2> <FILENAME>

One may want to see all changes made within a given date range, for this use

git diff HEAD@{6.day.ago} HEAD@{0}

Where HEAD@{0} is denoting current HEAD of current branch, while HEAD@{6.day.ago} is denoting HEAD 6 days ago. NOTE This can be paired with git ref, filename or branch

There’s also the git range-diff command, which provides a simple interface for comparing commit ranges. There’s more to the git diff tool, so I recommend checking out the docs here.

Git Hooks

Git Hooks let us automate pretty much anything and everything with Git repository. For example, checking commit messages against a regex for meeting standards, code quality checks, branch names or calling any external hooks, process or kicking a pipeline.

There’s pre and post hooks available for most git events, like commit, rebase, merge, push, update, applypatch, etc.

Hooks are stored in .git/hooks file unless we configure them elsewhere using .gitconfig via core.hooksPath), and can be tested with the git hook command. Since they’re just shell files, they can be used to run any command.

Hooks aren’t pushed to the remote repository, so to share and manage them across the team, we’ll need to use a hook manager, like lefthook or husky.

Remember, hooks can always be skipped (with the --no-verify flag), so never rely purely on hooks, especially for anything related to security.

We can refer official documentation here

Git Blame

A literal translation of this command is to blame who changed/wrote a line using git. But this is for useful to determine with which commit something was changed and then inspect that entire commit and its metadata. For illustration, to view author and commit info for line 220 to 300 of app.js, one shall run

git blame -L 220,300 app.js

We can refer official documentation here

Git Bisect

This is one of the most powerful, yet easy to use git command. bisect is an absolute life saver when it comes to debugging git. Once we start a git bisect, git marks out commit for us, and we tell it weather that commit is good or bad. Which lets us narrow down the the earliest commit where the bug is present.

To start this, we shall use git bisect start. Once it’s started we can then mark a known good commit in history where we know that nothing was broken

git bisect good <COMMIT_SHA_ID>

and to mark a bad commit (mostly latest commit, where bug is known); we can run

git bisect bad <COMMIT_SHA_ID>

If we do not pass commit SHA, it would mark current HEAD as bad one. Now we know that bug was introduced between good and bad commit. After that we can start checking commits from good marker, until we reacha commit that actually introduced that bug for first time.

After this we can inspect that bad commit and take correctional measures. Once we found and fixed that bad commit we can cancel anytime with git bisect reset.

Git bisect also allows replays, viewing those commits, skipping and so fourth. For more details we can check or refer git docs

Git Grep

Ever used Linux’s grep, did you find it powerful and brilliant? Git has same powerful search tool grep. We can search a string, regular expression across commits and branches.

git grep <regexp> <ref>

It includes plenty of options to narrow down our search, or specify results format. For example, use -l flag to only return file names, -n flag to search with line number, -c flag to specify number of matches per file to return, --and flag to specify multiple conditions, -e flag to exclude results matching a condition.

Since git grep is regular expression compatible, we can get much more advanced with the string we are searching for. We can also use it to specify a file extension to limit what to search into. For example to look for console.error in all JavaScript files, we can use

git grep 'console.error' *.js

which will list all JavaScript files containing console.error. The second parameter is a ref, and it can be a branch name, commit, range of commits, or anything else that qualifies as git ref.

git grep "somestring" HEAD~1

The command above will only search for string “somestring” in previous commit referred as HEAD~1

We can refer official documentation here

Git Archive

We already know what Archive means. Git also provide facility to archive a repository. This command archives entire repository as a single file. Git will include all repository history and it can be extracted back to its original form.

The command also includes a lot of other options, so we can customise exactly what files are and aren’t included in the archive. To archive repository one shall use

git archive --format=tar --output=./project_archive HEAD

Command above will archive current project HEAD reference as tarball and save it in project_archive. We can refer official documentation here

Git Submodules

In git, submodules allows to let us mount one repo into another, and is commonly used as core dependencies or splitting components into separate sub/children repositories.

Adding a submodule, will create a .gitmodules file to keep reference of submodules added to current repository. This helps git in downloading submodules when current repository is cloned. But to do this while cloning, we need to use --recursive flag to clone submodules as well. For example

git clone <URL_TO_GIT_REPO> --recursive

To add a submodule to git repository, we can run following command

git submodule add <URL_TO_GIT_SUBMODULE_REPO> <path/to/save/at/in/current/repo>

There’s also git subtree, which does a similar thing, but without the need for metadata files. We can refer official documentation here

Git Bug Report

git bugreport command captures system info and then opens up a bug template to fill in. Once all information is put in, it should be a complete bug report, with all required information captured.

This bugreport comes very handy when we need to report a bug to an open source project using git. This captures all necessary information to be submitted to project to easily reproduce or inspect bug. We can refer official documentation here

Git Fsck

Use git fsck to check all objects, or recover unreachable ones

This command is not one needed frequently, but a good one to have knowledge about. Like in Unix; fsck performs a file system check. When we run it, it will test object databases. Then it will verify SHA IDs of all objects and their references stored. This will report any anomalies if found.

It can also be used alongside the --unreachable flag to find objects that are no longer reachable from any named reference. Unlike other commands, it includes everything in .git/objects). We can refer official documentation here

Git Stripspace

We often see unnecessary blank lines and trailing whitespaces in our code files. Removing then manually becomes tedious. Though there are many external tools that can be used to automate fix for this, but git provides it. And if we do not have eternal tools we can simply use git stripspace to format whitespaces and blank lines in specified file.

It is originally intended for commit messages, tags etc., but we can use it for files as well. To use this we shall

cat <./path-to-file> | git stripspace
//or
git stripspace < ./path-to-file.md > fixed-file.md

In second command, the output will be saved in fixed-file.md. We can also use it to remove comments using --strip-commit flag or to comment out lines with --comment-lines flag. We can refer official documentation here

Git LFS

Have you ever tried to store large files in git and it refused? (i.e video files or blobs). Often our project contains large files which slows down the git workflow. Git provide large files store feature or git lfs. It can enable to stored these large datasets/assets elsewhere; while keeping them trackable within git repository. git lfs works by replacing these larger files with text pointers (pointing to storage) that are tracked within git. To use we shall use

git lfs track <LARGE_FILE>

This will make an entry for same in .gitattributes file. To get list of all files tracked by lfs, we shall use

git lfs ls-files

Git GC

Use git gc to optimize your repository

Like other things, git repository does accumulate various types of garbage (i.e unreferenced pointers, untracked references). That’s when we need git’s own Garbage Collector. To run Git’s GC, we shall run

git gc

This will remove orphaned and unaccessible, untracked commits. Combining this with git prune will further optimize repository by compressing file revisions, git objects, packing references, pruning reflog and updating indexes

With --aggressive flag, this will aggressively optimize the repository, throwing away any existing deltas and re-computing them, this takes much longer to run but may be needed if we’ve got a large repository. We can refer official documentation here

Git Show

This command we may already have used on daily basis like git logs, however they have more capability then we are leveraging. To use, just run git show <SHA_ID>.

This command can be used to preview a file in different branch than we are working on without switching branch. To preview file in branch, we can run

git show <BRANCH>:<FILE>

However can append the --pretty flag, for a clearer output, but there’s many other options available to customize the output (with --format), so this command can be extremely powerful for displaying exactly what we need. We can refer official documentation here

Git Describe

Use git describe to find the latest tag reachable from a commit, and give it a human-readable name

At times, we may need to refer latest git tag reachable from a commit in a human-readable form. To generate this string one can running

git describe

We can also pass a specific tag to it. Note that we must have at least one tag for this to work, unless we append the --all flag. Git describe will also only use annotated tags by default, so you must specify the --tags flag to make it use lightweight tags as well. We can refer official documentation here

Git Switch

Moving between branches is something that we do often, the switch command is like a simplified version of git checkout, it can be used to create and navigate between branches, but unlike checkout does not copy modified files when you move between branches.

Similar to checkout -b flag, with the switch command you can append the -c flag to create a new branch, and jump strait into it, e.g. git switch -c <new branch>. We can refer official documentation here

CAUTION Running git switch will discard any unstaged changes.


About The Author

I am Pankaj Baagwan, a System Design Architect. A Computer Scientist by heart, process enthusiast, and open source author/contributor/writer. Advocates Karma. Love working with cutting edge, fascinating, open source technologies.

  • To consult Pankaj Bagwan on System Design, Cyber Security and Application Development, SEO and SMO, please reach out at me[at]bagwanpankaj[dot]com

  • For promotion/advertisement of your services and products on this blog, please reach out at me[at]bagwanpankaj[dot]com

Stay tuned <3. Signing off for RAAM