Git tutorial - part 3
I wrote my last Git tutorial 6 years ago, but I guess it took me quite some time to learn some new Git tricks.
At work we have a microservices architecture, with each service in a different repo. I work with around 6 of them on a regular basis and sometimes I have to make changes that touch more than one repo, such as changing the interface of one service and then changing all the other services that make calls to it.
We use the Azure Release flow for developing code, which means feature development happens on branches and we send pull requests (PR) to merge our code. Because sometimes I start another task before I get the necessary approvals for a PR, I sometimes have to juggle many branches in the same repo.
Inevitably, I make commits to the wrong branches. Because I’ve searched for this too many times, I’ve decided to blog about how to fix this.
If you commit to the wrong branch and you already have an existing branch that you should have commited to:
git checkout wrong_branch
git log
git checkout correct_branch
git cherry-pick commit_hash
If you commited to master and you should have created a new branch:
git branch new_branch
git reset --keep HEAD~1 # Move master back by 1 commit
git checkout new_branch
So the first problem is solved. But then I am left with another one: the Azure Devops repository offers the option to delete branches when merging pull requests, but obviously it deletes them only remotely, and, sometimes, I uncheck that option because I know I still have work to do on that feature. But eventually I do want to clean up stuff and occasionally, I want to do that from the command line, because the Git UI from the IntelliJ line of products is not always very clear and helpful.
git push -d origin old_branch # Deletes remote branch
git branch -d old_branch # Deletes local branch only if it has been fully merged
git branch -D old_branch # Nuke the local branch, regardless of merged status
And now for the fun part. A weird bug emerged at work, related to Flask logs, and I didn’t see any commits that looked like they touched the logging system. Checking out an old commit showed that back then the logs were still working fine, so it was not an issue with a dependency or something else, but it was something from our code.
Time to whip out git bisect. I’ve known for a long time that it existed, but I never used it in my almost 10 years of programming.
> git bisect start # Start bisecting
> git bisect bad # Current head on master is bad
> git bisect checkout old_hash
> git bisect good # The version at old_hash is good
Then you should get something as follows:
Bisecting: 378 revisions left to test after this (roughly 9 steps)
Git automatically checked out the commit in the middle of the range history, so you can run your tests and see if the bug is still present. If yes git bisect bad
, otherwise git bisect good
. Do this approximately 9 times and you will get to the commit that introduced the bug. The last step is to clean up the bisection state and return to HEAD:
> git bisect reset
In my case, the commit bisect found didn’t touch logging at all. Yet, miraculously, in the previous commit, logs showed up fine, but with this commit, they didn’t. Sometimes I seriously question my career choices… but then I realize I enjoy messing with this stuff :D