loading...

6 Git Aha Moments

henrikwarne profile image Henrik Warne Originally published at henrikwarne.com on ・4 min read

When I switched jobs four years ago, I went from using subversion (svn) to using git as the version control system. Even though I am a pretty quick learner, it took me a quite a while to really understand git. I read a lot on how git works, but even so, I didn’t always realize what the implications were for how to use git. Here are six big “aha moments” I had on how to use git.

Aha Moments

Looking at these aha moments now, they all feel really obvious. But I remember literally thinking “aha” when I understood a concept and realized the ways in which I could then use git.

1. Local and remote changes are independent. I often used “svn status -u” to see what changes I would get if I ran svn update. In the beginning I was confused about the equivalent operation in git. You can run git status, and that will show the local changes compared to what was last pulled. But to see the changes on the server, I first need to do a git fetch. This concept of there being two independent sets of changes – local changes, and changes on the server (pushed there by other people) – took me a while to really grok.

2. Merge makes older commits accessible. It took me a long time to realize that merging simply makes already existing commits accessible. Initially my mental model of a merge was that all changes from the merged branch became commits at the time of the merge. Realizing that commits from a branch remain, and that merging simply allows them to “be seen” in the other branch helped explain some odd things. For example, showing git log of a file (for example in PyCharm) can show commits from two different branches interleaved. Showing a diff between two commits (adjacent in time, but on two different branches) can give a really big diff.

3. The meaning of merge commits. Since my understanding of merging was incomplete, merge commits used to be a bit of a mystery to me. I viewed commits only as “what is the diff of the code for this commit”, and from that perspective, merge commits didn’t make any sense. Often they are empty, with no code diff at all. Now of course I understand that it is important to see at what point commits from another branch were made reachable by a merge.

4. You can merge in both directions. If you have a long-running branch b _that you eventually want to merge back into master, you can resolve the merge conflicts a bit at a time by periodically merging master into _b (and fix any merge conflicts that arise). Eventually I want to merge all the changes from b into master, but that can only be done when b works as intended. It was a big conceptual aha moment for me when I realized that I don’t have to wait till b is done before I resolve some merge conflicts. Merging master into b at regular intervals means that when I finally merge b into master, most of the merge conflicts will already have been dealt with.

5. You can start over if a merge fails. When I used svn, I often used –dry-run to see what would happen if I did a certain operation (but without actually doing it). In git, I took me a while to realize that the same functionality exists, but it is not defined explicitly. For example, if I merge some changes, and I mess up resolving the merge conflicts, I can simply go back one step and do it again. As long as I did not push to the server, it is no problem to go back by doing a “git reset –hard HEAD~”. Now I can simply do the merge again, and hopefully resolve the conflicts correctly this time. It is very liberating to know that almost anything I do with git can be easily reverted, undone or redone.

6. Committed changes can be reset to local changes again. Sometimes I work on a branch b with local changes, and I need to check out another branch and do some work there. In the past, I would often stash the local changes. But these days I often commit the local changes, with a commit message that it is work in progress (WIP). I don’t push these changes to the server. When I come back to branch b, I do a “git reset HEAD~” to get the committed changes back as local changes again. Making WIP commits on a branch means I don’t have to keep track of which branch the stashed changes are meant for. It was a real aha moment for me to realize that I can “undo” the commit into local changes again.

Conclusion

I remember reading a lot of tutorials on how to use git, and how git is organized. But even knowing how git works didn’t immediately translate into understanding how I could use git. The above aha moments only depend on understanding a few things – that there are local changes, and how branches and merging works. Knowing what I know now, all these insights seem trivial. However, I remember quite clearly that these were not obvious to me when I started learning git. Hopefully these aha moments can be useful to somebody else new to git.

Posted on by:

henrikwarne profile

Henrik Warne

@henrikwarne

Senior software developer in Stockholm, Sweden. Loves coding, learning, reading.

Discussion

pic
Editor guide
 

Adding one from my side,

Ability to modify previous commits.

Yeah

 

It is interesting that you use the phrase, "makes the Commits available." In svn the merge has you apply all the branch changes in one commit then it Commits meta data so tools can show history. Git has the meta data native to its structure.

I keep finding out how important it is to emphasize that git Commits are safe. Merge and rebase have --abort. If you don't use hard or force git won't touch your files, but then they use gui that warns in a dialog everyone ignores.

 

Hi Henrik,

a hint to your point #5 ... In svn you can do a merge in your working copy without committing back to the server.

If you think you done something wrong you can simply do a

svn revert -R .  

and start from beginning. Afterwards you can do the final commit

svn commit -m"Done merge."

But I would always recommend to run your build including tests before I finally commit.

 

Thanks for the tip! I'm only using git these days, but you never know...

 

4 was a huge one for me too, I also came from a SVN to GIT background. Rebase still is like magic somedays :)

 

These were the exact same aha moments I had when learning git (in a heavily cherry-pick biased team). Nice post for folks learning the ropes. :)

 

Now, try tj's git extra. You'll be blown away ... 💯

 

I never merge ... you squash all the commits into one. I only ever rebase. Only. Ever. Rebase. Good luck! Paul

 

For small changes and short-lived branches (which are most common), I prefer rebasing. For long-running branches with really big changes (changing how a major feature works, changing a framework), I prefer merging.
Regardless, understanding that you can merge in both directions, and why that works, improves your knowledge of git.

 

also git merge --abort is a good command to do , if you find that you are messing up the merge

 

Agreed, good point!

 

Any particular GUI front-end you use for Git, or do you prefer using Git from the command line?

(I include Xcode or Visual Studio or Eclipse or other Git-savvy IDEs as a front-end.)

 

I mostly use git from the command line, but I also look at diffs and file histories from within PyCharm.

 

“git reset –hard HEAD~” always saviour for me!!! Also instead of you could have mentioned about git rebase.

 

Your talk of periodically merging master into b makes be think you should just rebase b onto master instead.

 

For small changes, rebase is fine, but for bigger changes I prefer merging.