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

Automatically copy pushed files from one GitHub repository to another

我有两个Github存储库。

当文件被推送到第一个存储库时,我想自动(可能使用hooks和/或github API)提交并将其推送到第二个存储库。

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

最简单的方法是什么?

如果我不需要安装HTTP服务器或学习Perl,我将获得额外的分数:)


如果您正在寻找一些健壮且易于维护的东西,我建议您围绕Github Webhook开发一个解决方案。是的,它将要求您部署一个HTTP服务器,比如node.js服务器,并且它将需要少量的开发(您的需求相当具体),但是我认为如果您需要一些可靠的、低维护的东西,它将得到回报。如果您考虑了这些方法和设置工作后,认为这种文件镜像方法仍然是正确的选择。

让源存储库(在Github上)为S1S2…使用(非重叠)文件集来镜像F1F2…,发送到目标repo T(也在Github上),在那里对应的文件被认为是只读的。您的需求是不寻常的,因为SnT听起来好像不是彼此克隆的,它们甚至可能没有任何共同的承诺,在这种情况下,这不是推/取场景。您还不能保证源文件更新每次提交一次,甚至是分组的,但与不复制的更改隔离,所以这不是关于cherry-picking提交的。

复制的触发器是将某些文件推送到S1S2…,而不是对这些repo的任何开发人员克隆进行提交,因此客户端挂钩不会起作用(它们可能难以维护)。当然,Github不允许使用通用挂钩,所以Webhooks是您最好的解决方案。您可以考虑另一个,轮询克隆,它经常从S1中提取,执行逻辑,然后提交到t,但与Webhook相比,这听起来很尴尬,它将为您提供可靠的交付、重放能力、一个体面的审计跟踪等。

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

  • 部署Github Webhook处理程序。这个很酷的小库是Github Webhook的预构建处理程序,处理HMAC X-Hub-Signature验证,并为所有Webhook事件提供简单的事件侦听器挂接。您可以每个S有一个端点,或者更容易将它们扇入。
  • 有一些本地文件(保存在git repo中),它将Sn映射到Fn
  • 注册X-GitHub-Event: push的处理程序,并检查repository/namecommits[]/modified[]以查找与本地地图匹配的路径。
  • 部署node github,node.js的github apiv3的实现。
  • 对于每个匹配文件:
    • 调用getblob从sn读取文件的utf-8base64副本。
    • 调用createblob在T中重新创建该文件。
    • 对t进行一系列调用,以获取引用(当前提交)、gettree、createtree(从基目录和新blob中创建一个新的)、create commit和finally updatecreference。这是一个工作流-较低的冲突是分支/合并。

这种方法允许您做任何事情,而不需要T的本地克隆。您可能会发现使用本地克隆更好,我先看看API方法有多简单。

enter image description here


我们也遇到了类似的问题——我们希望在项目和公共文档的存储库之间自动复制文档文件。我们已经构建了一个工具,可以监听Github的Webhook,解析提交并创建对选定目标的拉请求。氧化镁我们已经打开了它的源代码——https://github.com/livechat/copycat——它可以在任何节点平台服务器上使用。


两个单独的Github Repo(没有第三方服务器侦听Webhook事件)无法相互镜像。

您需要在一个GitHub回购上注册一个Webhook,以便检测推送事件,并推送到第二个GitHub回购。

这意味着拥有一个监听Webhook JSON负载的服务器。

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


编辑:我现在意识到这个问题是关于Github的。我的答案是关于一个标准的git存储库,您可以对它进行文件访问。

我假设第二个回购是第一个的克隆,创建了类似这样的东西

1
git clone --bare first.git second.git

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

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

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

内容应该是

1
2
#!/bin/sh
git push second

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


由于您有不同的回购,您可以尝试使用git-apply/git-am逐个应用提交,然后进行推送。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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)

一个简单的方法是在origin中添加两个(或更多)pushurls(或其他一些远程)。

例如:

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

它不会对任何人的工作流程造成很大的改变,但是对于两个回购来说,所有的推送仍然是有效的复制。这里更详细地解释了这一点。

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