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.
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
- Git Tag - How to create version tags
- Git Web - How to use builtin GUI
- Git Reflog - How to know actions taken
- Git Log - How to view commit logs
- Git Cherry Pick - How to pick a commit
- Git Notes - How to attach info to commits
- Git Diff - Compare changes between two files
- Git Hooks - How to execute scripts on git command
- Git Blame - How to blame code or developer ;)
- Git Bisect - How to debug git commits
- Git Grep - How to search git repo
- Git Archive - How to share git project
- Git Submodules - How to have repo within a repo
- Git Bugreport - How to build a bug report using git
- Git Fsck - How to verify and recover
- Git Stripspace - How to autoremove whitespaces
- Git LFS - How to store big files in git
- Git Garbage Collection - How to GC git repo
- Git Show - How to inspect git objects
- Git Describe - How to get readable names for tags
- Git Switch - How to jump among branches
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
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 specifiedgit 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 expressiongit log <since>..<until>
- Show all commits between two references as mentionedgit log -- <file>
- Show all commits made only to a specific filegit 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