开发者

Git create remote repository on push

开发者 https://www.devze.com 2023-01-23 21:56 出处:网络
I have been trying to figure this one out but I am having a hard time doing so. I am currently working on an open source project that requires me to allow a user to push to remote repository without i

I have been trying to figure this one out but I am having a hard time doing so. I am currently working on an open source project that requires me to allow a user to push to remote repository without it already existing there. I want to avoid manually logging in to a server and running git init or git init --bare.

For obvious reasons, I get the following error when trying to push my local repository to a path tha开发者_运维问答t doesn't point to an existing repository on the remote server:

fatal: '/var/repositories/myrepo' does not appear to be a git repository
fatal: The remote end hung up unexpectedly

But I would like to be able to run for example the following command:

git push origin master

And have that create /myrepo in /var/repositories if it does not yet exist. How would I be able to accomplish this? I would assume it is some kind of (global) git config setting you would probably set on the remote server, or otherwise a (repository specific) git config locally, but I couldn't figure it out.

Any help would be much appreciated!

Thanks!


There is currently no way to use git push to create a repository on the remote. The best you can do is write a one-liner script something like this:

#!/bin/bash
ssh $1 "git init --bare $2" &&
git push ssh://$1/$2

Hopefully you can ssh in; if you can't, you could use some kind of filesystem access to just manually create the repo by dumping in the appropriate file/directory structure (maybe create it locally and copy). You might also create a named remote along the way.

This was actually one of the most requested features on the 2010 Git Survey - so maybe you'll get your wish sometime in the next year!


You can write a wrapper script on the remote, and prepend command="/path/to/wrapper" to the authorized_keys' lines.

command="/usr/local/bin/gitaccess" ssh-rsa ...

In this wrapper you would check SSH_ORIGINAL_COMMAND. Git issues these commands:

git receive-pack '/path/provided' # when pushing
git upload-pack '/path/provided' # when pulling

If SSH_ORIGINAL_COMMAND is not empty and starts with one of these, you check the path, create the repository if necessary, install any configuration you need in it, and execute the command.

If SSH_ORIGINAL_COMMAND is empty and you want to provide users with shell access, you invoke a shell.

If SSH_ORIGINAL_COMMAND is not empty but doesn't start with a git command, if you want to allow users to have shell access, you just execute the command provided.

Here's a bit of Ruby code to demonstrate. Note that I didn't test it and there's room for improvement (for example we should not hardcode /bin/bash).

#!/usr/bin/env ruby
orig_command = ENV['SSH_ORIGINAL_COMMAND']
if orig_command.nil?
    # If you want to preserve shell access
    exec '/bin/bash' # not tested, I hope it's interactive if executed this way
end

cmd_parts = orig_command.match /([a-z-]+) '([a-z0-9.\/]+)'/
if cmd_parts.nil?
    # If you want to preserve shell access
    exec '/bin/bash', '-c', orig_command
end

command = cmd_parts[1]
path = '/var/repositories/'+cmd_parts[2] # not secured (could contain '..')

if command == 'git-receive-pack' || command == 'git-upload-pack'
    if not File.directory?(path)
        `git init --bare #{path}` # not secured, I didn't escape path
        # Do any configuration here
    end
    exec 'git-shell', '-c', "#{command} '#{path}'"
end

# If you want to preserve shell access
exec '/bin/bash', '-c', orig_command

You can also pass an argument to this script in the authorized_keys to identify users and choose whether they should have shell access. I also do this to control access on a per-repository basis. If you want to carry this argument to the git hooks, just create an environment variable.


  1. Checkout and track the branch from the remote:

    git checkout -t origin/funbranch
    
  2. Branch off of it:

    git checkout -b mybranch
    
  3. Push your new one up, it will create a new branch automatically on the remote:

    git push origin mybranch
    

It should say "created new remote branch origin/mybranch"

If you are still getting "Remote end Hung up", it sounds like a security thing. Do you have SSH keys installed correctly, and do you have write permissions on the remote server?

The way most open source projects work, you have to create a fork (a clone inherently) that you use to do your work because most of the time you don't have write permissions to the repo. When you have changes, you will then send a pull request to the repository owner, and he/she will pull from your fork the changes that they want.


I know this is an old question, but I stumbled upon this while googling for something else.

The best way I've found to be able to push to a remote server and have it create a repository if it doesn't exists is to use gitolite. Look at the install guides for it, it's very easy to setup, and if you change some config settings you can have it use your exiting /var/repositories to store the repos.

0

精彩评论

暂无评论...
验证码 换一张
取 消