If you haven’t heard, Git is pretty much the new kid on the block in terms of version control systems. I’m still a bit new to Git myself, but I am already discovering its immense power. Now that I’m a little more familiar with branching and merging with Git, I’d like to share how these tools can improve software development.
My workflow before branching went something like:
- Do some work in my local repository
- Commit once when the work was done
- Push to origin
- As required by my editor… obligatory rinse and repeat
This workflow presents a problem because my team and I must carefully avoid change conflicts; usually in this fashion:
"Hey, don’t change that file, I’m working on it!"
We got by with this workflow because communication was quick and easy between two people and we didn’t have any review process for checking in (other than the fear that if you broke something and the other guy checked it out, you would probably get something heavy thrown at you).
Clearly we need a new way of working and to learn more about working effectively with Git. Enter git-branch and git-rebase, a set of tools I wrongly avoided when I was new to Git. To show how these tools are useful and powerful, I’ll discuss a scenario below.
I need to add a new feature. Going through my previous workflow, I would do some work, commit, and push to origin. It turns out I made some mistakes and my checkin was rejected so I could fix it. I went right back to my local master, made the changes, and checked in again. This is the point where a train crash sound effect should play – I had now committed changes that were dependent on broken code! This creates a problem because having a checkin that is broken, even for a short period of time, dirties the change history for the project and might lead to someone else wasting time looking for problems with broken code. Following a broken checkin immediately with a fix does not remove the broken checkin, and we want to avoid this scenario.
The first step toward a better workflow is learning how to branch. Making a branch before I start working allows me make changes without affecting master and merge my changes in at the end. This is much safer for many reasons. (Read more on branching). Now that I know how to branch from master, do my work, and merge back in, I am a step closer to understanding Git. A shortcoming still exists: even though I had worked in my branch and committed to it, all my incremental commits came along when I merged to master. (Bringing all the commits is good thing when all commits are solid pieces of work, not so much when one of them is broken). Since one of the commits was just a fix to a previous commit, I want to treat both as a single commit.
Now I feel like Marty, but I don’t have to hit 88 MPH to go back in time to fix my past mistakes! With git-rebase I can go back in time and change all kinds of details about my commits. The particularly important changes to make are removing commits and combining multiple commits into one. (Read more on rebasing) I now have the power to merge my branch, fix my commits with mistakes, and push a patch to origin without the patch being dependent on previous bad commits.
I’m More of a Visual Learner
The diagram below is is a simple walk through of the situation I just described.