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

31
我有两个GitHub存储库。
我希望能够在将文件推送到第一个存储库时自动(可能使用钩子和/或GitHub API)将其提交和推送到第二个存储库。
第二个存储库不是第一个存储库的克隆,它们的文件夹布局不一定相同,只是有一堆共同的文件。
最简单的做法是什么?
如果我不需要安装http服务器或学习Perl,那就更好了 :)

1
第二个仓库应该是第一个的克隆,还是你只是想同步某些文件? - Chris
@Chris 的主要想法是,第一个存储库的用户不需要做任何额外的工作,只需进行正常的提交/推送操作,同时仍然可以将文件正确复制到另一个位置的另一个存储库中。在现实生活中,“第一个”存储库实际上是多个存储库,我想从中提取特定文件并将它们重新组合在一个部署存储库中。 - Drax
你说“部署仓库”。听起来像是你在尝试使用Git运行一个构建步骤(例如缩小源代码,连接JS文件,编译源文件等)? - Chris
@Chris 如果你需要细节:我正在将多个子项目的多个构建结果重新分组到一个存储库中,其中包含安装程序的资源文件 :) - Drax
@hek2mgl 没错,我认为很多人已经想过这样做了,所以可能存在一些常见的方法来实现它(甚至希望它是GitHub的本地功能),但我可能高估了人类的实现速度 :) - Drax
显示剩余9条评论
6个回答

17
如果您正在寻找一个坚固且易于维护的方案,我建议您开发一个基于GitHub Webhooks的解决方案。是的,它需要您部署一个HTTP服务器,比如一个Node.js服务器,并且需要进行一定量的开发(因为您的需求相当特定),但是如果您需要可靠且低维护的东西,我认为这将会有所回报。如果您考虑了各种方法和设置工作之后,仍然认为这个文件镜像的方法是正确的选择,那么就采用它吧。请注意,保留HTML标签。

让源代码库(在GitHub上)为 S1S2 ...,文件集为F1F2 ... 不重叠,以镜像的方式发送到一个目标存储库T(也在GitHub上),其中相应的文件被视为只读。你的要求很特殊,因为SnT听起来并不是从彼此克隆而来,它们甚至可能没有任何共同的提交,这种情况下就不是推送/拉取场景。你也没有保证源文件更新是每个提交一次,甚至可能与非复制更改分组但隔离,因此这不涉及挑选提交。

触发复制的条件是将某些文件推送到 S1S2 等,而不是在任何开发者克隆这些仓库时提交,因此客户端钩子无法帮助(并且可能难以维护)。当然,GitHub 不允许通用钩子,因此 Webhooks 是您最好的解决方案。您可以考虑另一个轮询克隆,它定期从 S1 ... 拉取,执行逻辑,然后提交到 T,但与 Webhooks 相比,这听起来很棘手,Webhooks 将为您提供可靠的交付、重播能力、良好的审计跟踪等。
好处是已经有很多支持这种设置的基础设施,因此实际上您需要编写的代码可能非常少。假设您选择了 Node.js 类型的设置:
  • 部署 github-webhook-handler。这个小型库是GitHub Webhooks的预构建处理程序,可处理HMAC X-Hub-Signature验证并为所有Webhooks事件提供简单的事件监听器钩子。您可以为每个S设置一个端点,或者将它们分散开来更容易管理。
  • 有一些本地文件(保留在Git存储库中),将Sn映射到Fn
  • 注册一个X-GitHub-Event:push的处理程序,并检查repository/namecommits[]/modified[]以匹配本地映射的路径。
  • 部署 node-github,这是适用于Node.js的GitHub APIv3的实现。
  • 对于每个匹配的文件:
    • 调用getBlob以从Sn读取文件的utf-8base64副本。
    • 调用createBlob以在T中重新创建该文件。
    • 进行一系列对T的调用,包括getReference(当前提交)、getTreecreateTree(从基础版本和新的blob创建一个新的树)、createCommit和最后是updateReference。这是一种工作流程,更低冲突的方法是进行分支/合并。
这种方法使你无需本地克隆 T 即可完成所有操作。你可能会发现使用本地克隆更好,但我建议先尝试使用 API 方法,看看事情是否容易实现。

enter image description here


很好的答案,如果在悬赏结束之前没有更好的答案出现,我会接受这个。"这是非常相关的 :)"。只有在您考虑了各种方法和设置工作后,决定继续使用文件镜像方法时才会这样做。 - Drax
@javabrett,我知道这是一个相当古老的帖子,但在尝试解决我们遇到的类似问题时偶然发现了它。你所说的看起来不错,但我唯一看到的问题是事件传递失败。例如由于某种原因Webhook无法联系服务器,我们如何确保重新传递事件。我知道GitHub中有手动重新传递的选项,但在处理多个存储库时可能不可扩展。您是否知道是否有API可以频繁轮询失败的事件,然后调用另一个API以重新传递? - user320550

10

我们遇到了类似的问题 - 我们想要在项目和常用文档存储库之间自动复制文档文件。我们开发了一个工具,监听GitHub的Webhooks,解析提交并创建拉取请求到目标存储库。

Copycat schema

我们已经将它开源了 - https://github.com/livechat/copycat - 它可以在任何Node平台服务器上使用。


7

编辑:我现在意识到这个问题是关于GitHub的。我的答案是关于你有文件访问权限的标准git存储库。

我假设第二个存储库是第一个的克隆,类似于以下方式创建:

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

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

谢谢您的回答,但第二个代码库不是第一个代码库的克隆。我会编辑问题并添加这个精确信息。 - Drax

6

如果没有第三方服务器监听webhook事件,两个GitHub仓库不能相互镜像。

您需要在一个GitHub仓库上注册一个webhook以侦测推送事件,并将其推送到第二个GitHub仓库。

这意味着需要一个服务器来侦听webhookjson负载

类似于dustin/gitmirror这样的工具可以帮助做到这一点(使用Go语言)。


-1

由于您有不同的存储库,您可以尝试使用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)

-2

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

例如:

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

这并不会对任何人的工作流程产生太大影响,但所有推送仍然会在两个存储库中有效地重复。更详细的解释可以在这里找到。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接