Git tutorial - part 3

    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 mi­croser­vices ar­chi­tec­ture, 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 de­vel­op­ment 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 oc­ca­sion­al­ly, 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 pro­gram­ming.

    > 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 au­to­mat­i­cal­ly 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 ap­prox­i­mate­ly 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, mirac­u­lous­ly, 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