I love bzr, it is elegant, simple and does not get in my way. And it has never let me down, everything I wanted to do with it worked in the way I expected it to work. But sometimes I have to use git and usually I’m confused by it. I would like to share some of my finding about the sources of this confusion in the hope that you have a easier time with it then 🙂
Please note that this list is by far not complete and its just what I found from a user perspective. Please also note that I’m far from a git expert.
git has some important conceptional differences from bzr. Those can be confusing for people like me used to bzr.
The big differences on a glance:
- git uses a intermediate layer between the working tree and the commited items called “the index”
- git uses repositories (container of branches) that contains multiple branches and uses the working tree to switch between branches
- some commands do different things (bzr revert, git revert)
The index is a stagging area for changes. It sits between the working tree and the current HEAD of the branch. If you want to commit to HEAD, you first need to run “git add file” before a “git commit” will consider it to be part of the commit. Because this is a pretty uncommon model a option “git commit -a” was added that basicly tells git to ignore the index and implicitly add all changed files (but not new files) to the commit. So the “git add” command is really more about “add this content” (that maybe a new file too) than the bzr “add this file”.
The index has some side-effects that can be suprising. A “git add file” means that from that point on, “git diff” does not show the changes to “file” anymore. If you then change file again “diff” will show the changes relative to the last “add”. Why? I don’t really know, but it seems to be a huge part of the git philospohy ,.
A lot of commands in git work against the index, not the HEAD of the current branch. For example a “git diff” will diff against the index not against HEAD. The commands “git diff –cached” will tell you the diff between working tree and index and “git diff HEAD” the difference between the working tree and the current branch HEAD.
A git revert reverts a *commit* not the changes in the working tree (like bzr does). Instead, you use “git checkout .” to revert everything back to the index. Stuff that is already added to the index is left untouched (“git diff –cached” will show it) or “git checkout -f” to throw away changes in the index too. Suprised? Me too 🙂 There is also “git revert –hard” that may or may not behave different from “git checkout -f”.
git uses a repository to have collections of branches that can then be checkout out into the working tree (in contrast to the simple model of bzr where each dir is a branch). “git branch” tells you about the available (local) branches and “git checkout branchname” switches the working copy over to the “branchname” branch. With “git branch newname” you can start a new branch but *not* switch the working tree to it. There “git checkout -b newname” to create the branch and switch the working tree to it in one go.
To work with remote repositories you first have to clone them with “git clone sftp://remote-repo”. If the remote repository has branches they will not show up with “git branch”. You have to use “git branch -r” for this (-r apparently means “remote”). Why? I have no idea.
So to work with a specifc remote branch (instead of master) you run:
$ git checkout origin/remote-branch $ git checkout --track -b my-branch-based-on-the-remote-branch-name [hack away] $ git pull
So git pull gets all of the new changes from the “origin” repository and then merge the tracked branch into your branch. You can say “git pull origin branch-name” to merge other branches.
I hope the above helps you if you use git and come from a bzr backend to have a easier start. There is probably tons more that I haven’t mentioned or discovered or just got wrong 🙂 I used this post as a start to create a wiki page so that others can add their findings to it too.