Windows Git Tutorial: Cygwin, SSH and Projectlocker

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.

Why Git?

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.

Why Cygwin?

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.

Why Projectlocker?

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.

I compared several private hosting alternatives including the ever-popular Github, Unfuddle and Projectlocker. Their free version for me had the best features:

  • 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 "youremail@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

Remote Deployment

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.

Conclusion

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.

15 comments:

Anonymous said...

Thanks for the article! Didn't really tried git yet, but indirectly learned about the public key in SSH, which will be a good timesaver in the future! :))

Anonymous said...

Excellent guide. I found this very helpful in getting set up on projectlocker today. It's certainly not the most intuitive site to use but it's good value for money :)

One little tidbit of info that you may want to know is this. I don't know if this is true or not but I read in a comment on another forum that projectlocker stores their passwords in plain text. I'm not sure it's a major concern but just thought I'd let you know.

Anonymous said...

ProjectLocker DOES NOT store passwords in plain text. I work at ProjectLocker, and wrote the relevant code. It stores passwords in a retrievable format (like Amazon or PayPal do with your credit card), but definitely NOT in plaintext. Please see the canonical response here:

http://superuser.com/questions/46810/should-i-be-concerned-if-my-git-hosting-provider-stores-passwords-in-plaintext/46951#46951

Thanks!

Anonymous said...

Excellent article !!!
ProjectLocker should DEFINITELY have it on there website.

Thanks VERY VERY much !

Raoul Duke said...

yeah, another sincere Thank You.

Raoul Duke said...

addendum: for getting set up with PL i had to push remote first, not pull the way it appeared to me your instructions were saying.

Vaibhaw Poddar said...

I am getting this error. Any suggestions

$git push origin master
fatal: The remote end hung up unexpectedly

Anonymous said...

The above instructions for creating your repository are not very good.
Here's a easier run-down:

= name you want to call the remote repository
= git-yourcompany@blah.projectlocker.com:project.git (copy/paste from the User Home page)

a) [go to your local source code directory]
a) git init
b) git remote add
c) git add *
d) git commit -am "initial commit"
d) git push master

Anonymous said...

The above instructions for creating your repository are not very good.
Here's a easier run-down:

{name} = name you want to call the remote repository
{url} = git-yourcompany@blah.projectlocker.com:project.git (copy/paste from the User Home page)

a) [go to your local source code directory]
a) git init
b) git remote add {name} {url}
c) git add *
d) git commit -am "initial commit"
d) git push {name} master

Ahmed Hamdy said...

That is Good, thank you very much
But I have a problem here in the test step. I don't know why your test contains hostname@hostname: ??? mine not.
anyway thanks.

William Shields said...

@Ahmed that's a typo on my part. It should be username@hostname. Thanks for pointing it out and glad you liked the post.

Ahmed Hamdy said...
This comment has been removed by the author.
Ahmed Hamdy said...

Thanks for your concerning and fast reply.and for deleted post.
But I still can't do any upload or any other test. In your post, your machine has username@hostname:~/project$, but mine only has username@hostname ~$, so when I use cat > test.txt, it didn't work
my code :
"ahmed@ahmed-PC ~
$ cat > test.txt
[1] 13156
bash: gt: command not found
bash: test.txt: command not found"

And test.txt is a file in /home/ahmed/Assembler.
Assembler is my project name. If you can tell me what I can do,I will very very glad.
Thank you very much for your effort.

Anonymous said...

re: "being able to distribute patches without creating history on your central repository."

this is brain-dead

this alone is reason to avoid git and it's ilk at all costs

this is NOT version control; it is fanboi chaos

Anonymous said...

Thanks for this post, although it didn't help to solve my specific problem, it helped me to understand Git a bit better and lead me in the right direction. Finally cloned a repository successfully today! Thanks very much.

Post a Comment