Getting geeky with Git #8. Improving our debugging flow with Bisect and Worktree

Git

This entry is part 8 of 11 in the Getting geeky with Git

The debugging process is not always easy, and the bugs are sometimes difficult to track down. Fortunately, Git provides us with tools that might make this process easier. In this article, we learn both the worktree and bisect tools.

Git Worktree

Sometimes, when we focus on a new feature, a bug pops up in production. Unfortunately, this might require us to switch to a different branch. This might prove to be quite a hassle because we don’t want to lose our current work. The more we improve this process, the easier it will be for us to come back to our original focus.

When we initialize a new repository, Git creates a working tree for us. It is essentially one local copy of our repository. We refer to it as the main working tree.

The interesting thing is that we can have multiple working trees. By doing so, we can check out more than one branch simultaneously.

If we now want to switch to the master branch, we would either need to stash our current changes or create a commit. To avoid it, we can create a linked working tree instead.

We create a new directory on our drive and link it to the master branch with the above. Let’s list all of our working trees.

/home/marcin/Documents/Projects/bugs 786f0ea [feature-a]
/home/marcin/Documents/Projects/master-branch f256fa2 [master]

Please note that the directory created when creating a linked working tree does not include any files listed in our file. This means that we probably need to install dependencies and add environment variables to our project’s new copy.

Since the branch we currently work on has different dependencies than the master branch, we can run the inside the new directory.

If you feel like that might not be necessary and will take too much time, you can copy your existing directory.

Cleaning up after the linked worktree

An important thing to realize is that Git is aware of all of the linked working trees. In fact, it prevents you from checking out the same branch twice.

fatal: ‘master’ is already checked out at ‘/home/marcin/Documents/Projects/master-branch’

There are two ways to clean up if we don’t need our linked worktree anymore.  The most straightforward is to use the command.

At some point, we might have removed the directory that contains our linked worked tree. In this case, we can use the command to remove the information about the linked worktree.

Git Bisect

When looking into an issue, we are sometimes not sure what lines of code caused it. A viable strategy is to check out every commit one by one to see which change caused the bug. This is not the most elegant solution, though. Fortunately, Git has a bisect tool that can do just that. Its purpose is to help us find a commit that introduced a bug to our application.

Let’s say that our app’s current state contains the bug, and we know that it worked properly ten commits ago. If that’s the case, the regression probably was introduced somewhere along with those ten commits. The bisect tool starts checks out a commit right in the middle of a known good and bad state. Doing so repeatedly reducers the number of commits each time by half.

To start the bisect process, we need to run . Now, we need to point to a state that we know does not contain the bug. To do that, we need to provide the hash of a commit.

We also need to tell Git when the application contained the bug. If we don’t provide the hash, Git assumes that the application’s current state has the bug.

Doing the above starts the process of a binary search. Git checks out a commit right in the middle of a known good and bad state. Our job is to test the application to determine if the bug is still there.

After doing that, we either run , or . Every time we do it, Git checks out into a commit in the middle. After a few times, Git can pinpoint the specific commit that introduced the bug.

You can see a very good video representation of this process in this video

The smaller and more specific commits we have, the easier it is to find the issue using the bisect tool. Also, squashing many commits into one will decrease the effectiveness of bisect.

Instead of running or , we can also use if we can’t test the commit for some reason. Unfortunately, this might prevent Git from finding the exact commit that introduced the issue.

You can also use the Bisect run functionality to automate the whole process. This is possible only if you can write a script that can determine if the application’s given state is valid.

Summary

With linked worktrees, we can create additional local versions of our repository more easily than with . It might prove to be useful if we need to switch our focus for some period of time. Using linked worktrees also allows us to run a few instances of our application and compare them if we need to.

Once you have set up a working tree, you can use the bisect tool to determine the exact commit that introduced the issue. Even though the first thing might be to use it for looking for bugs, it doesn’t have to be the case. For example, we could use it to find the first time a feature was introduced.

Series Navigation<< Getting geeky with Git #7. Cherry Pick with ReflogGetting geeky with Git #9. Understanding the revert feature >>
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments