【问题标题】:Git create remote repository on pushGit 在推送时创建远程存储库
【发布时间】:2011-05-05 16:02:07
【问题描述】:

我一直在努力解决这个问题,但我很难做到。我目前正在开发一个开源项目,该项目要求我允许用户推送到远程存储库而不它已经存在。我想避免手动登录到服务器并运行git initgit init --bare

由于显而易见的原因,我在尝试将本地存储库推送到不指向远程服务器上现有存储库的路径时收到以下错误:

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

但我希望能够运行例如以下命令:

git push origin master

如果 /myrepo 尚不存在,则在 /var/repositories 中创建它。我怎么能做到这一点?我会假设它是您可能会在远程服务器上设置的某种 (global) git config 设置,或者是本地的 (repository specific) git config 设置,但我想不通。

任何帮助将不胜感激!

谢谢!

【问题讨论】:

    标签: git git-push git-remote git-config


    【解决方案1】:

    目前无法使用git push 在远程创建存储库。你能做的最好的就是写一个像这样的单行脚本:

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

    希望你可以通过 ssh 登录;如果不能,您可以使用某种文件系统访问权限,通过转储到适当的文件/目录结构中手动创建存储库(可能在本地创建并复制)。您还可以在此过程中创建一个命名远程。

    这实际上是 2010 年 Git 调查中requested features 最多的人之一 - 所以也许你会在明年的某个时候实现你的愿望!

    【讨论】:

    • 感谢您的回复,对于我迟到的回复感到抱歉。你说的应该确实有效。是的,我有 SSH 的能力。我实际上使用 GitHub 上的 PushAnd 库解决了这个问题。我不完全确定为什么它可以与安装的这个库一起使用,但确实如此!我相信它安装了一个 post-push 钩子/脚本,它运行一些命令来初始化存储库等。
    • 为了避免&&超过两行,为什么不使用bash -e?你也可以运行git init --bare /path/to/$2
    • @Eric 这只是一个例子,但我通常更喜欢显式错误处理(不必担心 bash 使用 -e 做什么和不允许做什么)并且能够调整、复制-粘贴到其他脚本中,等等,而不用担心改变行为。
    【解决方案2】:

    您可以在遥控器上编写一个包装脚本,并将 command="/path/to/wrapper" 添加到授权密钥的行中。

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

    在这个包装器中,您将检查 SSH_ORIGINAL_COMMAND。 Git 发出这些命令:

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

    如果 SSH_ORIGINAL_COMMAND 不为空并且以其中之一开头,则检查路径,如有必要,创建存储库,在其中安装所需的任何配置,然后执行命令。

    如果 SSH_ORIGINAL_COMMAND 为空,并且您想为用户提供 shell 访问权限,则调用 shell。

    如果 SSH_ORIGINAL_COMMAND 不为空但不以 git 命令开头,如果你想让用户有 shell 访问权限,你只需执行提供的命令即可。

    这里有一些 Ruby 代码来演示。请注意,我没有对其进行测试,还有改进的余地(例如,我们不应该对 /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
    

    您还可以在 authorized_keys 中将参数传递给此脚本,以识别用户并选择他们是否应具有 shell 访问权限。我也这样做是为了在每个存储库的基础上控制访问。如果你想将此参数带到 git hooks,只需创建一个环境变量。

    【讨论】:

    • 这个答案应该被投票。这个我没试过,但是很合理。
    【解决方案3】:
    1. 从远程结帐并跟踪分支:

      git checkout -t origin/funbranch
      
    2. 分支:

      git checkout -b mybranch
      
    3. 推送你的新分支,它会自动在远程创建一个新分支:

      git push origin mybranch
      

    应该说“创建了新的远程分支 origin/mybranch”

    如果您仍然收到“远程端挂断”,这听起来像是一个安全问题。您是否正确安装了 SSH 密钥,并且您在远程服务器上是否具有写入权限?

    大多数开源项目的工作方式是,您必须创建一个用于完成工作的 fork(本质上是一个克隆),因为大多数时候您没有对 repo 的写入权限。当您有更改时,您将向存储库所有者发送拉取请求,他/她将从您的复刻中拉取他们想要的更改。

    【讨论】:

    • 嗨。谢谢回复!虽然这对于大多数查看此问题的人来说是一个有效的答案,但它并不是我正在寻找的完全。我需要能够将我的本地 develop 分支推送到例如远程 staging 分支。但我不希望仅仅为了完成跟踪而创建一个新分支。您是否知道在不更改我的本地存储库的情况下可以实现的任何其他方式?抱歉,如果问题有点不清楚,我想做的可能不是很常见。 :)
    • @Michael:您在这里的评论听起来完全不像您的问题。在这里,您正在谈论将一个本地分支推送到另一个远程分支(可能存在也可能不存在)。但是,您的问题是关于推送到 repository 尚不存在且必须创建的远程位置。
    【解决方案4】:

    我知道这是一个老问题,但我在搜索其他内容时偶然发现了这个问题。

    我发现能够推送到远程服务器并让它创建一个存储库(如果它不存在)的最佳方法是使用 gitolite。查看它的安装指南,它很容易设置,如果您更改一些配置设置,您可以让它使用现有的 /var/repositories 来存储 repos。

    【讨论】:

      猜你喜欢
      • 2018-06-24
      • 2010-10-25
      • 1970-01-01
      • 1970-01-01
      • 2014-01-25
      • 1970-01-01
      • 2013-03-28
      • 2017-10-01
      相关资源
      最近更新 更多