Recently I’ve switched from using Subversion to using Git for version control on personal projects. Now as much as Windows annoys me—and believe it me when I say it does annoy me—I still prefer to use it as a development environment (for PHP or Java) over Ubuntu (which I used for that sort of thing for a year or two). There is a better selection of tools. The UI is better. And to top it off, Civilization 4 is easier to run on Windows.
There are quite a few comparisons between Subversion and Git out there. Ultimately they’re just different philosophies and approaches. For me it came down to:
- I like the Git philosophy of being able to distribute patches without creating history on your central repository. At work, doing a code review usually entails doing a checkin (and yes I know you can create svn diffs);
- Git allows you to push your changes to several repositories. This is great for redundancy. I’m paranoid about losing source code. Anyone who writes software should be paranoid about becoming the next Avsim;
- You can use Git for deployment to your hosting provider; and
- All the cool kids are doing it. :-)
That being said, Git does have some downsides:
- Subversion has better tooling and IDE integration;
- Getting Git to work right on Windows is a hair-pulling experience (which is the point of this post);
- With Subversion you are the user that’s set up for you in the repository. In Git, you are who you say you are, which takes a bit of getting used to;
- Obviously multiple repositories is by its nature more complicated than a single central repository; and
- Subversion deals with binary files better and easier than Git does.
One piece of advice I’ll give you is this: If your Windows username has a space in it, change it. I was bashing my head against a brick wall for awhile before I figured out that my Git commands were failing to remotely authenticate because the Python script didn’t handle the case where the username contained a space as best as I could tell.
The nicest environment to have is one where you don’t have to type in your password every time you want to do a pull or push to a remote repository. Good security suggests you should do such things over SSH.
I wasted a lot of time with firstly the bundled git-bash and then with PuTTY. I had problems with git-bash like when doing a git push over ssh it would inexplicably hang. It also seemed to be leaking file descriptors or something because it reached a point where it wouldn’t connect to anything, not even things I’d successfully connected to.
PuTTY I usually use under sufferance. It does the job but I find myself just wanting a good command line (rather than say plink.exe and a command prompt).
Do yourself a favour and use Cygwin from Day One.
I’m currently using Cygwin 1.7.0 even though it’s in beta. When you install it, you have to select the packages you want. SSH (openssh) is not installed by default so select that under Net or search for it and select it.
One of the (many) nice things about Cygwin is that it creates a virtual filesystem for you where you can mount different directories at different points using the mount command. For example:
mount c:/xampp/htdocs /www
creates a convenient spot for your deployment directory.
If you’re not familiar with a Unix/Linux shell like bash and the typical Unix/Linux commands, do yourself a favour and get comfortable with them.
One of the things I wanted was a remote backup for my source code that is separate to my hosting account. Some may consider this overly paranoid. I think it’s good practice to have a local repository, your production code deployed on your hosting provider and a remote backup of your development work since that won’t necessarily be pushed to the hosting provider.
- Both Subversion and Git;
- Multiple active projects;
- Unlimited repositories;
- RAID storage and nightly backups;
- 500MB storage; AND
- SSL encryption.
These services all differ in what products they integrate (eg Wikis, bug/issue tracking, project management and so on) so you really need to do your own research to find what’s right for you.
The one downside of Projectlocker is their website is rather primitive and at times slow to respond (with certain pages). But once you’re set up you should have almost no need to go to it again.
Setting up SSH
Using public key encryption is far more convenient than being asked for your password every time you want to access the remote repository.
First, create a public key if you don’t have one already:
username@hostname:~$ ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/home/username/.ssh/id_rsa): Created directory '/home/username/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/username/.ssh/id_rsa. Your public key has been saved in /home/username/.ssh/id_rsa.pub. The key fingerprint is: 63:17:a4:06:78:34:9d:4f:2d:4c:7f:8f:84:5a:4b:c4 username@hostname username@hostname:~$ cat ~/.ssh/id_rsa.pub ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEArGyNxx5nct8vic01GxKPybSxL6ZNBMcOrtwo0dMSU0qN9l4pxAuX0jjJe4Pl/I121NztTDdiIntOTaYiQQXTQ2NP8MD5X1oyr7svs8Rm50zpQwOQ3rt4MvwgotZZjMoETT39fA3soRoQLQS5LzD0W7cvVdSoTGYcL+lfv2f0xQdS+CgCrRTeiwn7KYgD6arZLo6B1wVPCAmaiyo1Hetu1q7UIzh4dCACUy4BymlLAxon0NRWAhEADKltZqMitnPgDqtRXyMLUzEn6AvIotRprK7LoPzvLqz2MgBfzTne13Dz8LFOPhbM2n7cSf/OEUt+TtKZqvIoUb79smKDsf2aXw== username@hostname
Next, go to the Projectlocker Portal, login and if you haven’t done so already, create a Git repository. Your Git URL will be under “User Home” on the left hand menu. Also on the left-hand menu is “Manage Public Keys”. Click “New Key” and enter:
Save that and assuming everything has been done correctly you should be able to go to your local machine and type:
username@host:~$ ssh git-CompanyName@freeN.projectlocker.com PTY allocation request failed on channel 0 ERROR:gitosis.serve.main:Need SSH_ORIGINAL_COMMAND in environment. Connection to freeN.projectlocker.com closed.
You don't have shell access but as long as you don't get prompted for your password, it should all be working correctly. You can get more detailed information with:
username@host:~$ ssh -v git-CompanyName@freeN.projectlocker.com
or even more verbose:
username@host:~$ ssh -vv git-CompanyName@freeN.projectlocker.com
Local Git Repository
There are multiple ways of doing this. You can create a local repository and push it to Projectlocker or you can simply clone it, which is what I’ll do:
username@hostname:~$ git config --global user.name "Your Name" username@hostname:~$ git config --global user.email "email@example.com" username@hostname:~$ git clone git-CompanyName@freeN.projectlocker.com:project.git Initialized empty Git repository in /home/username/project/.git/ remote: Counting objects: 118, done. remote: Compressing objects: 100% (96/96), done. remote: Total 118 (delta 15), reused 111 (delta 15) Receiving objects: 100% (118/118), 184.08 KiB | 69 KiB/s, done. Resolving deltas: 100% (15/15), done.
Your output may look different as I'm cloning a populated repository in this case. The first two statements are telling Git who you are. Any commits will be identified by that name and user and this includes pushes to remote repositories. This is what I mean by Subversoin users needing to get used to this. Rather than being who the remote server authorizes you as, you are who you say you are.
An alternative way to set this up is:
username@hostname:~/work$ git init Initialized empty Git repository in /home/username/work/.git/ username@hostname:~/work$ git remote add project git-CompanyName@freeN.projectlocker.com:project.git username@hostname:~/work$ git pull project master remote: Counting objects: 126, done. remote: Compressing objects: 100% (102/102), done. remote: Total 126 (delta 17), reused 111 (delta 15) Receiving objects: 100% (126/126), 184.87 KiB | 78 KiB/s, done. Resolving deltas: 100% (17/17), done. From git-CompanyName@freeN.projectlocker.com:project * branch master -> FETCH_HEAD
Now try the following test:
username@hostname:~/project$ cat > test.txt This is a test ^D username@hostname:~/project$ git add test.txt username@hostname:~/project$ git remote origin username@hostname:~/project$ git commit -m "adding test file" [master 4811b38] adding test file 1 files changed, 1 insertions(+), 0 deletions(-) create mode 100644 test.txt username@hostname:~/project$ git push origin master Counting objects: 4, done. Delta compression using up to 4 threads. Compressing objects: 100% (2/2), done. Writing objects: 100% (3/3), 282 bytes, done. Total 3 (delta 1), reused 0 (delta 0) To git-CompanyName@freeN.projectlocker.com:project.git a6a6bf9..4811b38 master -> master username@hostname:~/project$ git rm test.txt rm 'test.txt' username@hostname:~/project$ git commit -m "getting rid of test" [master 172d57d] getting rid of test 1 files changed, 0 insertions(+), 1 deletions(-) delete mode 100644 test.txt username@hostname:~/project$ git push origin master Counting objects: 3, done. Delta compression using up to 4 threads. Compressing objects: 100% (2/2), done. Writing objects: 100% (2/2), 243 bytes, done. Total 2 (delta 1), reused 0 (delta 0) To git-CompanyName@freeN.projectlocker.com:project.git 3edc309..bccaeeb master -> master
Here we’ve simply added a test file, committed it, pushed the whole master branch back to Projectlocker and then removed it. The "git remote" class lists our remote repositories
To do this cleanly, you require SSH shell access to your hosting provider or remote server. Rather than I write this out myself, I shall point you to excellent Using Git to manage a web site as to how to set this up.
I hope you’ve found this guide useful. It can be a daunting task to figure out exactly where to start and how to begin with a new tool like Git, particularly because there are so many ways you can use it. I truly hope this saves you some grief in getting it set up and working on Windows.