自动将推送的文件从一个 GitHub 存储库复制到另一个

Automatically copy pushed files from one GitHub repository to another

我有两个 GitHub 存储库。

我想自动(可能使用钩子 and/or github API)在将文件推送到第一个存储库时将它们提交并推送到第二个存储库。

第二个存储库不是第一个存储库的克隆,它们的文件夹布局不一定相同,只有一堆文件是相同的。

最简单的方法是什么?

如果我不必安装 http 服务器或学习 perl,可加分 :)

编辑:我现在意识到问题是关于 GitHub 的。我的回答是关于一个标准的 git 存储库,您可以访问该存储库。

我假设第二个 repo 是第一个的克隆,创建了这样的东西

git clone --bare first.git second.git

将当前目录更改到 first.git 存储库中,并将 second.git 添加为远程。

cd first.git
git remote add second ../second.git

然后,在文件夹 first.git/hooks/ 中创建一个名为 post-receive 的文件(您可以重命名已经存在的 post-receive.sample 文件)

内容应该是这样

#!/bin/sh
git push second

现在,当您将新提交推送到第一个存储库时,将立即执行从第一个到第二个的推送,这样第二个也会接收提交。

两个 GitHub 单独的 repos(没有第三方服务器侦听 webhook 事件)不能相互镜像。

您需要在一个 GitHub 存储库上注册一个 webhook 以检测推送事件,然后推送到第二个 GitHub 存储库。

这意味着有一个监听 webhook 的服务器 json payload

dustin/gitmirror 这样的工具可以提供帮助(在 Go 中)。

一个简单的方法是将两个(或更多)pushurl添加到origin(或其他一些远程)。

例如:

git remote set-url --add --push origin url1
git remote set-url --add --push origin url2

它对任何人的工作流程都没有太大的改变,但是所有的推送仍然有效地复制到两个回购协议中。它有更详细的解释 here.

如果您有很多人在处理同一个存储库并希望反映他们的更改,请尝试 运行 一个脚本来为每个开发人员分配新的 pushurls。否则,恐怕你需要使用钩子+服务器。

因为你有不同的 repo,你可以尝试使用 git-apply/git-am 一个一个地应用提交,然后推送。

假设您在服务器上有 Repo1.git 和 Repo2,Repo1.git 是裸存储库,Repo2 是您的第二个存储库的本地克隆。

Repo1/.git/hooks/post-receive

#!/bin/sh
t=$(mktemp)
repo2_directory=/some/place/you/cloned/repo2
error=
while read line; do
  ref1=$(echo "$line"|cut -d' ' -f1)
  ref2=$(echo "$line"|cut -d' ' -f2)
  for ref in $(git log --oneline $ref1..$ref2); do
    git show -p --no-color --binary $ref > $t
    if !(cd $repo2_directory && git am -q < $t || (git am --abort; false)); then
      echo "Cannot apply $ref" >&2
      error=1
      break
    fi
  done
  [ -n "$error" ] && break
done
rm -f $t
[ -z "$error" ] && (cd $repo2_directory && git push)

如果您正在寻找健壮且易于维护的东西,我鼓励您围绕 GitHub Webhooks. Yes it will require you to deploy a HTTP server, say a Node.js server 开发一个解决方案,它需要少量的开发(您的要求相当具体),但我认为如果您需要可靠且维护成本低的东西,它会有所回报。那就是如果您认为这种文件镜像方法仍然是正确的做法,并考虑了这些方法和设置工作。

让源存储库(在 GitHub 上)为 S1S2 ...(非重叠)文件集镜像 F1F2 ...,将被发送到目标仓库 T(也在 GitHub 上),其中相应的文件被认为是只读的。您的要求很不寻常,因为 SnT 听起来好像它们不是彼此克隆的,它们甚至可能没有任何共同的提交,在这种情况下,这不是 push/fetch设想。您还没有保证源文件更新每次提交都会发生一次,或者甚至分组但与非复制更改隔离,因此这与挑选提交无关。

复制的触发器是将某些文件推送到 S1S2 ...,而不是对这些存储库的任何开发人员克隆的提交,因此客户端挂钩不会'无济于事(而且维护起来可能很尴尬)。 GitHub 当然不允许通用挂钩,因此 Webhooks 是您的最佳解决方案。您可以考虑另一个定期从 S1 拉取的轮询克隆 ...,执行逻辑然后提交给 T,但这与 Webhooks 相比听起来很尴尬,后者将为您提供可靠的交付、重放能力和体面的审计-trail 等

好处是有很多已经构建的基础设施来支持这种类型的设置,因此您需要编写的实际代码可能会非常少。假设您使用 Node.js 类型设置:

  • 部署github-webhook-handler。这个很酷的小库是 GitHub Webhooks 的预构建处理程序,处理 HMAC X-Hub-Signature 验证并为所有 Webhooks 事件提供简单的事件监听器挂钩。每个 S 可以有一个端点,或者将它们扇入可能更容易。
  • 有一些本地文件(将其保存在 Git 存储库中)将 Sn 映射到 Fn
  • X-GitHub-Event: push 注册一个处理程序,并检查 repository/namecommits[]/modified[] 以查找与您的本地地图匹配的路径。
  • 为 Node.js.
  • 部署 node-github, an implementation of the GitHub APIv3
  • 对于每个匹配的文件:
    • 调用 getBlob 从 Sn.
    • 读取文件的 utf-8base64 副本
    • 调用 createBlobT 中重新创建该文件。
    • getReference (current commit), getTree, createTree (create a new one from the base and the new blob), createCommit and finally updateReference 进行一系列 T 调用。这是一个工作流程 - 一个较低冲突的工作流程是 branch/merge.

这种方法使您无需 T 的本地克隆即可完成所有操作。您可能会发现使用本地克隆更好,我会先看看 API 方法有多简单。

我们遇到了类似的问题 - 我们希望在项目和公共文档的存储库之间自动复制文档文件。我们已经构建了一个工具来监听 GitHub 的 webhooks,解析提交并创建 Pull Request 到选定的目的地。 我们已经将它开源 - https://github.com/livechat/copycat - 它可以在任何节点平台服务器上使用。