Git push to a new repository on remote, initializing on the fly

Basically I'd like to set up a repository on a remote server on the fly. Usually a repository has to be initialized on the remote with init --bare before one can push commits from another device. Is there any way to circumvent this?

Ideally I have two points I'd like to fulfill:

  1. Leave the client side unchanged, meaning no setup other than git remote add ....
  2. Use SSH as the transfer protocol.

What I've thought of so far:

  1. Ignoring the SSH demand. By pushing over HTTPS instead I could host a HTTPS server that initializes non-existing repositories before accepting the push.

  2. Changing git functionality on the server side, hijacking push commands (called in the git-shell?). I have found no documentation on what takes place on the server side when pushing over SSH so I've not been able to further investigate this possible solution.

  3. Related to #2, I could implement a SSH server running on the remote, initializing non-existing repositories before running further commands. But as with #2, I've found no documentation on the push pipeline.

Clarification:

Can I push to a remote that has not yet initialized the repository? Can I sufficiently detect incoming pushes, initializing the repository before continuing?

3

1 Answer

The solution ended up being based on #2:

Changing git functionality on the server side, hijacking push commands (called in the git-shell?). I have found no documentation on what takes place on the server side when pushing over SSH so I've not been able to further investigate this possible solution.

I found an article by "kamalmarhubi" that explained what git push was doing when set up to use SSH.

The solution

Set up - server side

Add a used called git:

sudo useradd -m git

Note that the user unfortunately cannot use the git-shell since the shell handles necessary commands internally.

Create the .ssh directory

mkdir .ssh

Create the authorized_keys file

touch .ssh/authorized_keys

Add any public keys you're going to use as a line to the authorized_keys file.

Add the following on top of the user's .bashrc file:

function git-receive-pack() { if [ ! -d $1 ]; then mkdir -p $1 && cd $1 && git init --quiet --bare && command git-receive-pack $@ fi
}

Setup - client side

Execute the following within any git repository:

git add remote origin git@server:directory

Where server is the ip or name of the server and directory the path to store the repository at (relative to the git user's home directory, usually /home/git/).

Usage

Pushing code from the client

Push as usually, the service has taken care of initializing the repository for you!

How it works

Whenever Git pushes over SSH, it calls ssh git@server git-receive-pack directory, i.e. runs git-receive-pack directory on the remote. When using the git-shell, the command is handled internally. When using a regular shell (bash) the command is handled as any other bash command. This means that we can override how the command works, which we do by defining our own git-receive-pack in .bashrc. The definition needs to be on the top of the file since .bashrc usually aborts execution if it is run in a non-interactive shell (like Git is). The command we define checks to see if the target repository already exists, if it doesn't, it initializes it as a bare repository (as per Git standard) before it runs the original git-receive-pack which takes care of the actual pushing.

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

You Might Also Like