The McGyver GIT Survival Guide
Working with version control system is one of the elementary skills for each and every software engineer. Over the years, I worked with CVS, Subversion, SourceSafe, Perforce as well as Mercurial. Within Microsoft, I worked a lot with Source Deport and Microsoft Team Foundation Server. At home I run my dedicated SVN repository. In fact, I don’t feel comfortable when not being able to check in source code at all.
For my personal projects, Git especially Github works quite well, however, since the openHAB project moved from Google Code (Mercurial) to GitHub, I deal with quite a lot of issues within Git over and over. Currently we have more than 50 60 forks and more than frequent pull requests. Therefore, keeping your local branch permanently in sync is quite inevitable.
Abstraction None
The worst thing about Git is the fact, the user interface and console commands seem to reflect the Git implementation bit by bit. Personally, I have the feeling there is zero abstraction for the user. Even worse, when used to non distributed systems like SVN or TFS doing simple syncs and commits, the concepts behind Git might drive one mad.
Small Steps
This seems obvious, however, try to make only small commits to the repository. The more collaborators you have, the more challenging it might become to merge. At the same time, the less experienced you are with Git, the smaller your checkins should be. Commit single files, minor changes as isolated as possible. This will make you life just so much easier.
Daily Routine Conflicts
As daily routine, fetching and merging the local branch should be done via
git fetch upstream git merge upstream/master
Usually, this should work quite well unless there are changes on local files that should not be merged at all or you have done changes not to be merged yet.
Updating e21a751..349468b error: Your local changes to the following files would be overwritten by merge: foo/bar/buzz.ext Please, commit your changes or stash them before you can merge. Aborting
To just avoid the merge stash the changes via
git stash
Do the merge, and than pull the stash.
git stash pop
Again, usually this should work fine unless the merge results in a conflict which cannot be resolved automatically.
Auto-merging foo/bar/buzz.ext CONFLICT (content): Merge conflict in foo/bar/buzz.ext
Simply run
git mergetool
to solve the issues and try to pull the stash again.
Delete from Repository only
To remove a file from the repository whilst keeping it locally just performa a
git rm --cached myfile.c
Bear in kind, this git will realise this file immediately as a new. rm works on folders as well, though. Anyway, this will become very handy once you accidentally check in files that are not intended to be checked in.
Backup early – Backup often
Just in case you don’t know what’s going to happen e.g. due to a larger refactoring – move the current state into a new brach as backup right after a commit
git branch my-backup-work
Reset to Remote
Ok, this one gave me quite a hard time, as I had changes checked in my forks but needed to reset particular files to the current revision of the original repository (not your local branch and neither your fork).
To do so, reset your working copy to the upstream master:
git remote update git reset --hard upstream/master
Afterwards push this new branch-head to your origin repository, ignoring the fact that it won’t be a fast-forward:
git push origin +master
you might have something like
Fetching origin Fetching upstream remote: Counting objects: 685, done. remote: Compressing objects: 100% (336/336), done. remote: Total 507 (delta 249), reused 321 (delta 87) Receiving objects: 100% (507/507), 6.57 MiB | 146.00 KiB/s, done. Resolving deltas: 100% (249/249), completed with 64 local objects. From https://github.com/aheil/example f55f8b0..e060456 master -> upstream/master macbook-pro:example andreas$
Reverting to a specific Revision
This one is easy, you simply need to tell git the hash of the revision you want to check out. This works quite well, however, you always need to consider the visibility of the branch you want to check out. To understand the reachability in git, you might want to read this article.
git checkout e095 -- somefolder/somefile
Conclusion
In my very personal opinion, Git is s**t if you are used to centralised repositories. If you worked a lot with Mercurial, Git is simply to complex. Git is not abstract enough. When working on code, I want spend 99% on the code and 1% on the revisioning system, not the other way around. When working on the open source projects, I currently waste a major part of my time on Git.
I probably will never setup and run a personal git server (I do run a SVN server and did run CVS before) and I probably will not maintain any Git servers (I did at work maintain Microsoft TFS, SVN and CVS servers, though).
Git is great when it comes to some kind of mass collaboration (but I haven’t found anything so far Mercurial won’t offer for the same purpose). While everybody plays nicely together, it works just great.
As there is much more to learn about Git, you eventually want to pick Pro Git to get some insights.