General

Debugging with Git

Powerful techniques to identify bugs and issues on a codebase with Git

  • #git
  • #debugging
  • #grep

There are much more Git commands that can be quite handy apart from the usual fetch, commit, or push commands. This short article will introduce 3 useful Git commands namely bisect, grep and blame.

Bisect

A technique to pinpoint a bug-inducing commit through the commit history. It uses binary search under the hood to detect the bad commit. Interestingly, the process can be automated with custom scripts.

Step 1: Find good and bad commits

The first step is to identify the good (old) commit and the bad (newer) commit. The bad commit will most probably be the current HEAD in which some issue arises unexpectedly, such as missing a file.

Identify those commits and note down the hash of those commits.

good commit hash: <hash>
bad commit hash: <hash>

Step 2: Initiate Bisect

Start the interactive debugging session by using the bisect start command.

git bisect start

Step 3: Specify good and bad commits

With the commit hash gathered on step 1, populate them into the debugging session.

git bisect good <good-hash>
git bisect bad <bad-hash>

Step 4: Inspect codebase for issues

This is an iterative step. Bisect will now traverse through the history with binary search for code inspection.

Investigate the codebase. If the bug or issue persists in the current commit, we can reflect by using bisect bad command.

git bisect bad

Bisect will acknowledge the feedback and jump to another commit in history. Investigate the codebase and provide feedback again.

If it is a good commit, we can tell bisect using bisect good command.

git bisect good

Repeat this until there is no more commits to be inspected. Once that happens, the problematic commit should be found.

Automating the process

The bisect process can be automated by writing custom scripts that can be executed on the respective command line. The script needs to return -1 or non-zero numbers in case of failure the meet the criteria, and 0 to indicate the criteria has been matched in order for bisect to work correctly.

Specify both the bad and good commit hash to the bisect start command to initiate the automated bisect session.

git bisect start <bad-hash> <good-hash>

After that, specify the script or command to run against.

git bisect run <custom script or command>

At the end of the execution, it will show the problem-inducing commit just like the manual bisect session.

Reset

After identified the regression cause, we need to end the bisect session with reset.

git bisect reset

Blame

Blame is used to outline the authorship of each line of code within a document. It will display three useful info for the respective line.

  • commit hash
  • author
  • commit timestamp

For VSCode, the GitLens extension comes in handy as it shows the abovementioned info directly within the editor for the line the cursor is currently hovering on.

git blame <document name>

Blame a Segment

To inspect only part of a file, use the -L flag to provide a range of line numbers to be inspected for the file.

git blame -L <line-start>,<line-end> <document name>

# example
git blame -L 23,54 azure-pipeline.yml

Show

Use the show command to further inspect a commit. We can utilize the hash gathered from the blame command to learn more about the changes.

git show <commit-hash>
@@ -23,4 +23,4 @@
        using System.Collections.Specialized;
        using System.IO;

-       public sealed class Calculator
+       public class Calculator
        {
            private const string Name = "Calculator";
            private readonly IMapper mapper;
            private readonly IRepository repository;

Grep

git grep is just Grep, but for Git. It is used to search text with string or regular expressions for committed files within a Git repository.

git grep <regex/text>

# example
git grep "plain text"
git grep "^regex[a-zA-Z0-9]+$"

To limit file type for searching, provide the glob pattern as follows.

git grep <regex/text> -- <glob-pattern>

# example
git grep "hello" -- "*.tsx"

To search for a specific branch, provide the branch name as the second parameter.

git grep <regex/text> <branch>

This is an example of chaining everything together.

git grep -n "section" origin/master -- index.html

References

Stewart, A. Git Debugging Techniques.ย Pluralsight. https://app.pluralsight.com/library/courses/git-debugging-techniques/table-of-contents
IAdapter, Ulhaq, M. How do I use git bisect?https://stackoverflow.com/questions/4713088/how-do-i-use-git-bisect
git bisect. Retrieved 2024, March 24 from https://git-scm.com/docs/git-bisect
git grep. Retrieved 2024, March 24 from https://git-scm.com/docs/git-grep
git blame. Retrieved 2024, March 24 from https://git-scm.com/docs/git-blame