Setting up a Git Server on Windows Server 2008 R2 (using msysgit and WinSSHD)

My first attempt to use a remote Git repository on my Windows Server was to set up a WebDAV site and connect it as network drive on my PC. In principle this works well and the setup is quite fast and easy. The only problem was that it was really slow on my Win 7 machine. Unworkable slow. Even with this magic Auto-detect proxy settings turned off it didn’t improve very much. On Win XP it worked quite well though.
So that was the one of the main reasons why I decided to set up a Git remote repo over SSH. Unfortunately there were some hurdles to take to get this to work.

Basic Setup:

1. Go download and install WinSSHD on your Server. There’s a free version for personal use.

2. Configure WinSSHD. Set up the account(s) you want to use etc. This should be pretty straightforward, as it’s all self-explaining.

3. Now you should be able to connect from a remote client using simple password authentication. For example in Git Bash you can try to connect by typing

ssh username@server

If the connection works. Type ‘exit’ to disconnect and return to the bash

4. Since we don’t want to use password auth the next step is to generate a ssh key pair.
(You can configure the allowed auth types for users/groups in the advanced settings of WinSSHD)

$ ssh-keygen -t rsa -C "Comment" Generating public/private rsa key pair. Enter file in which to save the key (/c/Users/shoehle/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /c/Users/shoehle/.ssh/id_rsa. Your public key has been saved in /c/Users/shoehle/.ssh/id_rsa.pub. The key fingerprint is:c5:ed:1b:d1:40:94:5b:a1:6b:d1:76:a1:46:8b:7b:fc Comment

The -t specifies the type. In this case RSA with a default length of 2048 bit.
And with the -C parameter you can add a comment.
The default file path should be fine so just press enter at the first prompt.
Then choose a good passphrase for your key.

5. Import the public key (id_rsa.pub) in WinSSHD to the user account you want to connect with

6. At this point you should be able to connect to your SSH server with the key. If you type ‘ssh username@server’ again you should be able to connect with the key + passphrase.

Ok so these are the basic steps to connect with git to your sever through SSH.
Also if you don’t want to re-enter the passphrase everytime you connect, have a look at this help article from Github

If you now try to clone/push/pull/etc. from the server you will very likely get some errors.
Something like “git-upload-pack: command not found” or “myrepo.git does not appear to be a git repository” or similar.
To fix the first error you can specify the path to the upload/receive pack on the server with some additional parameters. But more on this later.
The second error is due to the command that msysgit tries to execute on the shell. It has single quotes instead of double(or no) quotes that enclose the path to the repository and therefore Windows can’t execute it properly and throws an error. To fix this we use sh.exe from msys.

[Update 05.08.2011]: Here’s a follow-up post that shows an easier way to set up the server. So you can skip the below sections.

Making Git work on the server:

1. If not already done, install msysgit on your server (I would recommend to install it directly to C:\Git or at least a path that has no spaces because I had some weird issues with “spaced” paths)

2. Add C:\Git\bin to the PATH variable. This is very important!! sh.exe and other dependencies are in this folder

3. Now go to C:\Git\bin and add the following two files

gup.sh grp.sh

4. Open gup.sh in your favorite editor and insert

C:/Git/libexec/git-core/git-upload-pack.exe $*

5. Open grp.sh and insert

C:/Git/libexec/git-core/git-receive-pack.exe $*

The $* essentially rips off the single quotes from the repository path argument, so a path that has spaces in it won’t work here either I guess

Basically we’re done now and all git operations from the client should work.
For a clone you have to type

git clone -u 'sh gup.sh' ssh://username@server/path/to/myrepo.git

or a push would be

git push --exec 'sh grp.sh' ssh://username@server/path/to/myrepo.git

but that is not very elegant.

Cleaning things up:

1. At first we want to get rid of the whole repo path by specifying a remote alias

git remote add origin ssh://username@server/path/to/myrepo.git

Where “origin” would be the alias name

2. Next we set the config for the git-upload-pack and git-receive-pack so we don’t have to reference the shell script all the time.

git config remote.origin.uploadpack 'sh gup.sh'

and

git config remote.origin.receivepack 'sh grp.sh'

That’s it. Now we can use the normal git commands without any additional parameters:

git clone origin git push origin master git pull origin ...

Hurray!

Alternatively I could have gone with Cygwin + OpenSSH of course and there are some tutorials out there on how to set this up, but I don’t want to have the unnecessary Cygwin bloat on the server unless I really need to. Also these Cygwin tutorials seemed to be much longer than the approach I took.

14 Responses to “Setting up a Git Server on Windows Server 2008 R2 (using msysgit and WinSSHD)”

  1. Vince Says:

    Hi,

    Should the title of this article be “Setting up git on Windows Server” rather than, “Setting up a Git Server on Windows Server”.

    I’ve followed all these steps and it doesn’t say how to setup a git server at all, only simple client commands.

    How can I set up a repo?

  2. Steffen Höhle Says:

    Hi Vince,
    to set up a git repo that will just serve as a remote repo and not as a working repo you just have to create a new folder on the server, open up a command prompt/git bash at the folders location and type "git init --bare".
    From the client you first have to open a ssh connection as described in the blog post and then create the folder on the server and execute the git command.

    As far as I know git doesn’t have a built-in server functionality as you might expect. But its remote functionality does just the same.

    So the title may be a little misleading, thats right. Perhaps should be something like “Setting up a git remote repo on Windows Server” or so.

  3. Denis Says:

    Nice… but in gup.sh, the line:

    C:\Git\libexec\git-core\git-upload-pack.exe $*

    should be:

    C:/Git/libexec/git-core/git-upload-pack.exe $*

    Same goes for grp.sh file!

  4. Dan Kendall Says:

    Hi, really useful – thanks.

    Getting an issue, I wonder if you have any insight. I’ve got SSH working to my 2008 server but am getting fatal errors with git-upload-pack command. Have you seen this before? Rather than create the gup.sh and grp.sh commands I just added the git libexec folder to the server’s PATH environment which gets over the “not found” error but now I get these fatal errors.

    Thanks for any help!

    • Steffen Höhle Says:

      Hi Dan,
      what error do you get? Have you tried if it works when you use the gup.sh and grp.sh files? The $* command in these files is very important. It rips off the quotes from the repo path. Otherwise you’ll get an error.
      You should see the command string that is posted to the server in the WinSSHD log files. So if you have single quotes around the repo path and you dont remove them this may very likely be the cause for your error.

      • Dan Kendall Says:

        Hi Steffan,

        Thanks for the reply. That got the grey cells working and I think I have a solution that avoids the use of gup and grp! As I mentioned earlier I added libexec to the path which mean the git-upload-pack command gets found but I was getting an error. I managed to reproduce this error in powershell and realised that it was caused by the dlls that git-upload-pack depends on not being found. When I ran my test case in my msysgit bin folder (where the dlls live), it worked. Armed with this knowledge I set the WinSSHD working directory to be my msysgit bin folder.

        This got the command working but I was now faced with another error, which was essentially the problem you mention with the quoted parameter. I created a simple DOS bat script that just calls msysgit’s sh command with all the arguments from the command line.

        I now have a generic ssh-based git solution on windows without having to do anything special on the client side. This is working nicely with GitExtensions, for example.

        Thanks again for your post – would not have got anywhere near this far without it!

        Dan

      • Steffen Höhle Says:

        Hi Dan,

        glad you’ve found a solution.
        Now that you’ve mentioned it I remember this issue.
        The fact that you don’t need to configure the client with your approach sounds indeed very charming. Thanks for your remarks. I will definately have a closer look at this and will possibly also update my blog post on this.

      • Steffen Höhle Says:

        It seems that in more recent versions of msysgit the git-upload-pack.exe and the git-receive-pack.exe are also located in the Git/bin/ folder. That makes things easier to setup and you don’t have to put the libexec folder on your PATH or change the WinSSHD working dir. I wrote a follow-up post about on this here.

        *edit* Ok thats not 100% true. The two files are only located in the bin folder in the portable version of msysgit. But that shouldn’t be a big problem I guess.

  5. Setting up a Git Server on Windows Server 2008 R2 (using msysgit and WinSSHD) [Update] « Holyhoehle's Blog Says:

    […] Setting up a Git Server on Windows Server 2008 R2 (using msysgit and WinSSHD) […]

  6. scypior Says:

    Now this is something that finally helped me to get it up and running. And who needs cygwin!

    Many thanks!

  7. Ron Hilmes Says:

    This is a GREAT post! WinSSHD is MUCH better than openSSH – the logging actually works. However, I took this one step further so the git-gui and other UIs would work also, I modified git-upload-pack and receive-pack to strip the offending quotes:
    /* remove surrounding single quotes */
    if (dir[0] == 39) {
    /* printf (“found single quote \n”); */
    dir[strlen(dir)-1] = ”; /* trim end */
    dir = dir+1; /* trim start */
    }


Leave a comment