DEV Community

Henrik Warne
Henrik Warne

Posted on • Originally published at henrikwarne.com on

6 Git Aha Moments

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.

Top comments (16)

Collapse
 
pratikaambani profile image
Pratik Ambani

Adding one from my side,

Ability to modify previous commits.

Yeah

Collapse
 
khmarbaise profile image
Karl Heinz Marbaise

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.

Collapse
 
henrikwarne profile image
Henrik Warne

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

Collapse
 
jessekphillips profile image
Jesse Phillips

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.

Collapse
 
cseeman profile image
christine • Edited

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

Collapse
 
rfbarraza profile image
René Barraza

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. :)

Collapse
 
sujithnath profile image
Sujith

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

Collapse
 
moopet profile image
Ben Sinclair

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

Collapse
 
henrikwarne profile image
Henrik Warne

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

Collapse
 
whitetire67 profile image
Paul Dailey

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

Collapse
 
henrikwarne profile image
Henrik Warne

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.

Collapse
 
kmonsoor_42 profile image
Khaled Monsoor

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

Collapse
 
sktguha profile image
Saikat Guha

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

Collapse
 
henrikwarne profile image
Henrik Warne

Agreed, good point!