自动将推送的文件从一个 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.
如果您有很多人在处理同一个存储库并希望反映他们的更改,请尝试 运行 一个脚本来为每个开发人员分配新的 pushurl
s。否则,恐怕你需要使用钩子+服务器。
因为你有不同的 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 上)为 S1
、S2
...(非重叠)文件集镜像 F1
, F2
...,将被发送到目标仓库 T
(也在 GitHub 上),其中相应的文件被认为是只读的。您的要求很不寻常,因为 Sn
和 T
听起来好像它们不是彼此克隆的,它们甚至可能没有任何共同的提交,在这种情况下,这不是 push/fetch设想。您还没有保证源文件更新每次提交都会发生一次,或者甚至分组但与非复制更改隔离,因此这与挑选提交无关。
复制的触发器是将某些文件推送到 S1
、S2
...,而不是对这些存储库的任何开发人员克隆的提交,因此客户端挂钩不会'无济于事(而且维护起来可能很尴尬)。 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/name
和 commits[]/modified[]
以查找与您的本地地图匹配的路径。
- 为 Node.js.
部署 node-github, an implementation of the GitHub APIv3
- 对于每个匹配的文件:
- 调用 getBlob 从 Sn.
读取文件的 utf-8
或 base64
副本
- 调用 createBlob 在
T
中重新创建该文件。
- 对 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 - 它可以在任何节点平台服务器上使用。
我有两个 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.
如果您有很多人在处理同一个存储库并希望反映他们的更改,请尝试 运行 一个脚本来为每个开发人员分配新的 pushurl
s。否则,恐怕你需要使用钩子+服务器。
因为你有不同的 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 上)为 S1
、S2
...(非重叠)文件集镜像 F1
, F2
...,将被发送到目标仓库 T
(也在 GitHub 上),其中相应的文件被认为是只读的。您的要求很不寻常,因为 Sn
和 T
听起来好像它们不是彼此克隆的,它们甚至可能没有任何共同的提交,在这种情况下,这不是 push/fetch设想。您还没有保证源文件更新每次提交都会发生一次,或者甚至分组但与非复制更改隔离,因此这与挑选提交无关。
复制的触发器是将某些文件推送到 S1
、S2
...,而不是对这些存储库的任何开发人员克隆的提交,因此客户端挂钩不会'无济于事(而且维护起来可能很尴尬)。 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/name
和commits[]/modified[]
以查找与您的本地地图匹配的路径。 - 为 Node.js. 部署 node-github, an implementation of the GitHub APIv3
- 对于每个匹配的文件:
- 调用 getBlob 从 Sn. 读取文件的
- 调用 createBlob 在
T
中重新创建该文件。 - 对 getReference (current commit), getTree, createTree (create a new one from the base and the new blob), createCommit and finally updateReference 进行一系列 T 调用。这是一个工作流程 - 一个较低冲突的工作流程是 branch/merge.
utf-8
或base64
副本
这种方法使您无需 T
的本地克隆即可完成所有操作。您可能会发现使用本地克隆更好,我会先看看 API 方法有多简单。
我们遇到了类似的问题 - 我们希望在项目和公共文档的存储库之间自动复制文档文件。我们已经构建了一个工具来监听 GitHub 的 webhooks,解析提交并创建 Pull Request 到选定的目的地。