TL;DR: Use binary search to find the commit that introduced a bug.
For humans: Take 2 commits and start removing halves until you find the error.
The command git bisect has been my ally in those times that the bug is a mystery. It has allowed me to go back in history and see the commit that broke something. Usually it's me being a detective for my own murder.
As simple as it sounds, it takes a "correct" commit and a broken one and with binary search, it allows you to find the offending one fast.
This is probably as far as I can go on explaining so let's see it with an example, using my favorite song.
This code will go to your home directory and create a folder with a git history for us to experiment. Read it first, and go ahead and run it.
As you can see, after adding line 10, we change a word in line 4. This is where our code broke, but we continued working without noticing for a while, just like the real world.
And just like the real world, a user reported and now it's on us to fix it, let's do it:
This will bring up our git history, where we'll find the offending commit, but this will be way harder in a real timeline e.g. if you squash your commits, your commit names are not standardized, or your history is longer.
Now, you know that the latest commit ("Add line 13") is broken, this will be the bad commit. You need a commit that is considered good, so we'll take the original one where we added the line ("Add line 4"). This probably will take longer, skip back a lot and test.
Your commit IDs will be different, remember to use the output on your console.
We're in luck, git bisect is interactive, so let's let it guide us through this rabbit hole. Once you start you will be in bisect mode until you type git bisect reset.
This command has no output. Let's give it some input.
You can use short commit IDs but we already have the long ones.
And it will output a useful number of revisions and a calculated distance. With longer histories you'll see the power of binary search.
Now, the second part is the interesting one. Notice how a commit that we didn't input was printed? Well, now it is checked out and we can test it to know if it's a good or bad one.
We can see that this specific commit, even if incomplete, has the correct lyrics, so we'll tell git this one is good.
And now the output will be similar, also checking out another commit.
We check again.
Aha! We have found the error, or bug in a real development environment.
Output tells us that this is the last step.
We check for the last time.
No error so...
And now git tells us the offending commit has been found, the commit author, date, commit message and lists all changed files.
So we close the case, it was me (as it's common), we can fix it commit and close the Jira ticket.
Now we are in the commit we were in (usually HEAD) when we started, and know what broke our app.
Phew, that was a lot. Coding as a team is hard, but if you do it right it doesn't have to be crazy. The right tools help, and that's why we built Watermelon, a VSCode extension that gets the historical context of your code to make it easier. For now we have GitHub. Jira, Zoom and Slack integrations coming soon.