18
Elevate your Git-fu!
If I had a dollar for every time I looked up how to ... in Git, I would have enough to launch a new cryptocurrency of my own (dibs on the name Gitcoin™️ 😛). As developers, we use Git almost everyday, and most of us find ourselves experiencing déjà vu with some common scenarios when working with Git. This blog discusses how to easily navigate your way through such scenarios along with answers to some frequent Git how-to's.
Git commands like git diff
and git log
can print large amounts of text to standard output and are hence paginated by default (using less
command under the hood), requiring user input for navigation and termination. To disable pagination and have Git display the entire output, we can just pass the --no-pager
flag to Git.
git --no-pager log
If you want to disable it on all shells, you can add the following line to your .bashrc
(Linux) or .zshrc
(macOS), although I do not recommend doing this.
export GIT_PAGER=""
This technique works best for scripting and automation, where we want to avoid user interaction and maintain control flow without prompts.
Many times, we may inadvertently commit the wrong file(s), and checking the git status
doesn't help since there are no hint commands displayed as would be before committing. In this situation, we can use
git restore --source=HEAD~ --staged -- <file>
to bring a file back into the staging area.
If you are unsure of the filenames and would prefer to move all files back into the staging area, then
git reset --soft HEAD~
will be your best friend.
I personally require this all the time to navigate back and forth between commits. Every commit has a SHA-1 hash composed of few of the commit's properties such as the date, author/committer, commit message, etc. You can get the current commit SHA using
git rev-parse HEAD
The git shortlog
command can be used to aggregate commits by author and title. This is especially useful for release announcements. It even provides a summary of commits by count.
For example, commit count summaries in the aws/eks-distro-prow-jobs repository are as follows:
$ git shortlog -sn
62 EKS Distro Bot
31 Abhay Krishna
29 EKS Distro PR Bot
27 Abhay Krishna Arunachalam
23 [REDACTED]
15 [REDACTED]
.
.
.
Sometimes, we may need to make minor changes to files that have already been committed. Once the files have been updated and git add
ed, we need to amend the commit to include the new changes, but we probably want to retain the same commit message.
We can do that with the help of
git commit --amend --no-edit
or
git commit --amend -C HEAD
Note: I find myself using this a lot so I have configured the following Git alias, which is short for commit without amend.
git config alias.cwa 'commit --amend --no-edit'
In a software company, more often than not, you may be working on multiple features or modules at the same time. In some cases, you may want a more recent feature change to get reviewed first and merged before other changes, for several reasons like coherence, priority, etc. In such cases, we can re-order commits as follows.
- Get the list of all commits with their hashes
git log --oneline
- Identify the depth of the commit range you want to reorder with respect to the HEAD commit.
- Perform interactive rebase on the branch.
git rebase -i HEAD~n # n is the depth from the previous step
This will open an editor with the commits in the range specified, along with prompts on how to edit the history. Besides re-ordering, you can also edit, pick, drop, reword and squash commits as desired.
- Once you have saved and exited the editor, you can repeat step 1 to view the re-ordered commit history.
Note: After changing history and before pushing to a remote branch, it's important to rebase on top of the remote head to validate that the re-ordering does not cause conflicts.
git fetch upstream
git rebase upstream/main
If you are in a situation where you wrote hundreds of lines of code and then end up losing them due to some conspiracy of the universe, then this one command can save the day. That command is git reflog
(read ref-log and not re-flog, though I get why one might think they can expect Git to co-operate by repeatedly flogging it for all the torture 😤).
git reflog
gives you an entire history of all the changes and actions you made across all branches in the local repository. The entries in the log are called reference logs, and they record when the tips of branches and other references were updated in the local Git working tree. Each entry is marked with an index number which can be used to move forward and backward through history.
reflog
has several use-cases such as retrieving lost/deleted commits, reverting breaking changes, identifying divergent paths, etc.
The manual pages for Git command help open in the terminal by default. Perusing man-pages can be a cumbersome task and they are also not user-friendly when searching for information (unless your Vim-fu is on point). If you would prefer to look up a command's manual page on the browser, all you need to do is use the -w
or --web
flag.
For example, the man-page for git branch
can be opened on the default browser (configurable) using
git help branch -w
or
git branch --help -w
Commands like git diff
and git show
in their raw form are great for displaying all the changes that are yet to be and have been committed, respectively. But in some cases, we may only require the names of files affected by a Git operation (for example, for scripting or filtering). We can directly obtain just the names by passing the following flags to the command.
git diff --pretty="format:" --name-only
git show --pretty="format:" --name-only
To see all files added to the staging area, we can use
git diff --staged --pretty="format:" --name-only
Filtering based on file extensions is also supported. For example, to get the list of all Python files in the latest commit, we can use
git show --pretty="format:" --name-only -- "*.py"
That brings us to the end of this blog. Thank you all for giving it a read! As closing notes, I wish to point out that Git is flexible in that it gives you several different techniques to fix a single problem, and the above methods are just from my experience and not advocated as canon. Feel free to leave your comments and corrections, and do reach out to me on LinkedIn and Twitter.
18