Getting started with GIT on Windows
A visual tutorial for the rest of us
Prerequisites
I assume that you know SVN well enough to have been using it (together with some other people) for some time now, on Windows. This should not come as a surprise, seeing that you read a document with the title "GIT for Subversion users on Windows".
Installation
Well, things have certainly improved since the early days. Now, there are only two products left to install, and it'll all work out like a charm:
- Install Git for Windows.
- Install TortoiseGIT
Installation instructions should be fairly simple to follow through; for now go with the default options and you should be fine.
Note: GIT is a moving target. I saw a lot of documentation that did not fit the behaviour of current releases; therefor note that I was using the following versions:
- Git for Windows - Version 1.9.4 (preview 15.8.2014)
- TortoiseGIT - Version 1.8.11.0 (64-bit)
Initial SVN Setup
I assume that in the past you have used Subversion mostly in a very straightforward way, something like this:
- There was a central repository on a shared server, say
\\SERVER\SVN\SUPERSOMETHING
. - Users
FOO
,BAR
andYUM
checked out that repository to a local folder (say,C:\Projects\SUPERSOMETHING
) and started working on their local copies. - When there was something to commit, the usual cycle involved
SVN UPDATE
(to get merge the latest changes someone else had done) followed bySVN COMMIT
.
Note: We're not working with a Subversion HTTP(S) setup here: we are in a corporate environment, and have to live with restrictions, so we'll use a SVN repository on a file server (Windows or Linux doesn't matter). Oh, and of course our interface was mostly Tortoisvn, not the command line: we are on Windows, right?
So our first task will be replicating that exact setup in GIT. This will not give us a lot benefits (it will give us some! I will list them at the end of the exercise), but it will give you a first feel of how working with GIT is like.
Setting up a central repository
The command git init
is used to create a repository. Most GIT tutorials start this way; however what they don't tell you is that this is not what you normally would want: instead, what you are looking for is to create a bare repository. The terminology "bare repository" was unfamiliar to me; in GIT parlance (and for our purposes) it means: a repository that
can act as a central repository. Non-bare repositorys cannot. So: let's create a bare repository then - but how ?
Well, convention says that you should create a directory with a name ending in .git
to create bare repositories in. I have no idea
whether this convention is enforced by anybody, but for now lets follow what the cool kids have been doing all along and create such a directory.
Step 1: create a directory named supersomething.git
somewhere.
Step 2: right click on that directory and choose Git Create repository here...
In the dialog make sure you tick the "Make it bare" box.
Finally, press OK to create it.
Note: The helpful comment that does not tell you what a bare repository the bloody hell actually is, but that instead gives the impression it is somewhat limited ("can only have changes pushed in"). I find many of the GIT comments frankly misleading. If you need the comment, you won't get any wiser by reading them: if you already know everything, you won't need the comments... Oh well...
Populating the initial repository
In Subversion, populating the initial repository works something like this:
- Create a local directory
- Checkout the (empty) project in this directory
- Add the files to the directory
- Add them to Subversion
- Commit them to Subversion
This basic sequence works for GIT as well - with some caveats. Let's start:
Step 1: create a directory named C1
somewhere.
Step 2: right click on the directory and choose Git clone
This will bring up a dialog
The URL
will be the existing bare repository. Note that I ticked the "recursive" box: it makes sense, even though at this point there is nothing much to see yet.
Note: GIT clone is something completely different from SVN checkout:
- A Subversion checkout gives you a revision, that is: a copy of all files in their latest version and only that. For example, it does not give you the complete history of each file. You must be connected to the subversion server to do that: you can see the file log only if you are "online".
- A Git clone gives you a local copy of the whole repository including all its history. This is very powerful: GIT clone a repository and you can edit it "offline" but retain access to the whole history while you do it!
You may remember one of my initial motivations was "working remotely": with GIT, there is little difference in an individual developers' workflow whether they are offline or online: they have access to all the information at any time.
Take a look at your directory now. It will have a structure somewhat like this:
Note that GIT automatically created a subdirectory for the supersomething project. Note also that there is a .git
folder which very much acts like the .svn
folder: the local database for GIT.
Step 3: Add your files to the directory
Actually, this is very much the same if you start from scratch, or if you start from an existing set of source files you want to add: copy them to the newly created supersomething GIT clone directory. Do not copy them to .git
- but then you wouldn't have done that with .svn
either, right?
Note: there is no general recommendation as to a GIT directory structure beyond this point. It is not like the trunc/tags/branches thing SVN has. Just copy the files as you see fit.
Step 4: Add the files to GIT
Now, right click on the new files and choose Git Add...
This should bring up a dialog with all files you selected, including those in subdirectories:
Click OK and you'll see the files being added:
Note how incredibly fast this feels. In many operations GIT is a lot faster than Subversion - something you'll soon accept as default, and then when you switch back to some project in Subversion it will be dearly missed :)
Note also that there is a button Commit right here at the end: click it to commit your changes...
Be sure to add a checkin comment; then press OK:
Again, note how fast this thing is... and then think about what you have just done.
- A subversion commit pushes the file to the central repository.
- A GIT commit pushes the file to the local repository. The central repository doesn't know anything about the changes yet!
Note that the dialog above has a Push button. The GIT push operation is the one that takes your repository and 'commits' it to the central repository. For now, because we're just starting, let's assume that nobody has changed something centrally, so we can proceed. You press the button and this dialog shows up:
Press OK and GIT rushes along
So now, the files are in the central repository!
Step 5: Confirm this by creating yet another clone
Just to verify that what we've done so far makes any sense, create another directory C2
, clone supersomething.git
in it, and then take a look. You will see that the new directory
now contains all the files from C1, just as you were expecting them to be.
Reverting local changes
At the beginning we said that when working offline, we want to use the SCM offline to track local changes. Well, it should be obvious by now how we can do this:
- If you made a change, use GIT commit to commit it to the local repository (You cannot GIT push it of course, because you are offline).
- If check a files history, use GIT show log, and then revert them
This process is not as intuitive as it seems to someone having used Subversion for many years, so I am going to spend a couple of minutes on it. When you bring up GIT show log, you will see an intimidating dialog like this:
This dialog has three areas:
- The top window is the commit list. In a single commit multiple files can be committed, so they do not reflect a single file, but rather a set of files committed at one point.
- In the middle window you see the comment associated with each commit.
- In the bottom window you see the files associated with each commit.
If, like me, you foolishly think that you revert a commit... you are most certainly wrong. These options are for GIT ninjas, not GIT noobies like us, stay away from them. To revert a file, go to the version (in the top window), then select the file in the bottom window, right click on the file, and there you can say "revert to this revision". Do not, I repeat DO NOT try "Reset master to this" or "Rebase master to this" unless you've been working with GIT for many weeks and know what you're doing.
Resolving a minor conflict
So far we've played by the rules. Now, let's raise a little conflict (just a little one to start, there is more to come!)
- Edit one file in C1, and commit it locally
- Push the changes from C1 to the central repository
- Edit one file in C2, and commit it locally
- Try to push the changes from C2 to the central repository, and voila:
Now, in a situation like that, what would have been the response of Subversion? It would have said our copy is out of date, and we need to do a SVN Update first. This is exactly the same situation we have here, only the names have been changed to protect the innocent: we need to do a GIT pull. Note the handy button at the bottom of the dialog! Click it...
Press OK and the files are pulled
Only now, you are in a situation like after an SVN Update: you have a local copy that matches what is on the server, and you can now probably push it. Note that there is a button "Pulled Diff" at the bottom: this shows you exactly the changes that were pulled:
So anyway, now you can do another GIT push, and this time it will work like a charm.
Where are we?
Let's do a short recap of our original motivation. We stated that in offline mode, these were our major issues with Subversion:
- M1: No going back: Your SCM was supposed to allow you to revert changes to a known state
- M2: No file history: Your SCM was supposed to show you the history of all changes to a file
- M3: Not committing often enough: Your SCM was supposed to help you in keeping changes minimal and being able to logically group them
Things have certainly changed with GIT already - we can do all of these now!
- M1: No going back: Now, you can locally GIT commit many times, and revert each and every single step.
- M2: No file history: Because a GIT clone includes the complete history, we have all the file histories we could ever want
- M3: Not committing often enough: And, because we're only hitting ourselves if things go wrong, we can commit to our hearts intent.
You can see at this point that M3 and M1 are really interconnected, and how GIT improves this workflow greatly for you. But now let's see something even better:
Working with Branches
Branches in Subversion are much more complicated than in GIT: actually, branches in GIT are really great. How does it work?
You are working in your repository, and you want to try out something. Say, you want to try a new feature TOAST() for SUPERSOMETHING. In Subverison, you would have probably labeled the last release before the change; then started working on the change (rather than really doing a branch). In GIT, if you want to start something but you're not sure yet if it works out, start a branch!
Step 1: Create the branch
This dialog will show up:
Give it a smart name, and be sure to tick "Switch to new branch"
Once GIT has completed its stuff, you are working in the new branch: work as you wish, and commit as often as you like. Any commits you'll do will be to that branch, not to the 'master' branch.
Step 2: Switching branches
Once the dialog is up
You'll be able to switch seamlessly between any of the different 'feature' branches you've done.
Step 3: Merging the branch back to 'master'
Once you are back in 'master', you can do this:
The dialog
allows you to basically set the feature you want to merge back into the main tree. And then you will follow that up with the usual GIT pull / GIT push thingy.
Next
Read Chapter 2 - Migrating a project from SVN to GIT
GK, Sept. 14, 2014