是否可以保持 2 个具有不同文件名的相似 git 存储库同步?
我们有 2 个 git 存储库,其中一个我们向第三方库公开,我们希望在其中共享我们的变更集作为 git 历史记录的一部分,但它们的文件名略有不同。
目前我们有一个 shell 脚本,它将复制所有文件并处理重命名,但是,这并不理想,因为当我们在另一个存储库中提交时,它会作为一个大提交进入(因此它会丢失更改,以及这些变化的原因)。
我们所做的事情类型的一个例子是: 假设在存储库 A(我们日常工作的源代码)中,我们的结构如下:
module-x/
module-x.js
在存储库 B(我们要将提交复制到的位置)中,结构如下所示:(
gallery-module-x/
gallery-module-x.js
此外,还有其他可编写脚本的文件内容也会发生变化)。
有没有办法复制历史记录并在文件上运行脚本以同步它们(但保留内容更改和提交消息,因此在第三方存储库中创建新的提交)?
我正在考虑在本地设置一个提交后挂钩,或者在 github 上设置一个接收后挂钩,但不确定是否可以做到这一点,或者是否有更好的方法来做到这一点。
有什么建议吗?提前致谢,
We have 2 git repos, one of which we expose to a third party library where we want to share our changesets as part of the git history, but their filenames are slightly different.
Currently we have a shell script that will copy over all of the files and handle the renaming, however, this is not ideal because when we go to commit in the other repository, it goes in as one large commit (so it's missing the changes, as well as the reasons for those changes).
An example of the type of stuff we do would be:
Let's say in repo A (our source that we work in day to day) we have a structure like:
module-x/
module-x.js
In repo B (where we want to copy our commits into), the structure looks like this:
gallery-module-x/
gallery-module-x.js
(in addition, there are other scriptable changes in the content of the files as well).
Is there a way to either copy of the history and run the script on the files to sync them up (but keeping the content changes and commit message, so creating a new commit in the third party repo)?
I was thinking of setting up either a post-commit hook locally, or a post-receive hook on github, but wasn't sure if it's possible to do that, or if there's a better way to do this.
Any advice? Thanks in advance,
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
你所做的任何事情都会变得非常难看,因为 Git 从根本上知道文件名应该是什么。具有不同文件名的树具有不同的 SHA1,因此提交也是如此,并且没有任何内容会匹配。这意味着您实际上无法在 GitHub 上做任何合理的事情,因为必须进行大量历史重写。
您可以尝试做两件主要的事情。
一:使用
git filter-branch
与树或索引过滤器重写一个存储库中的所有历史记录,重命名文件。您可以阅读文档或在线搜索或在此处查找相关示例。手册页中有一个与您的用例相当接近的示例,即示例部分中的最后一个示例,它将所有文件移动到子目录中,这样做的方式基本上相当于删除或添加前缀。您的版本可能类似于:(sed 替换模式是您需要小心的地方。)您希望在新的克隆中运行它,以避免实际重写原始存储库中的分支。
如果您在两个存储库中工作,则需要进行大量仔细的工作才能保持同步,避免两个存储库之间的不匹配,并且您必须进行相反的转换才能以其他方式恢复内容。但如果暴露/共享的是只读的,那么这个选项就很棒了;将过滤器分支视为导出的先驱。保存一个脚本来执行此操作,您所要做的就是克隆、过滤分支和推送。
二:手动传输补丁。您可以使用 git format-patch来创建补丁,然后对这些补丁中的文件名进行一些自动替换,然后将它们应用到其他存储库中。它很丑陋,但确实有效。
我想您可以在本地从提交后挂钩中触发这些事情,但它们可能比您想要的更耗时,因为您可能会经常提交并希望继续前进立即地。另一种选择(我假设您已经考虑过并由于某种原因而被驳回)是使用现有脚本(从提交后挂钩启动)将文件复制/重命名到另一个存储库中,然后立即在那里提交。 (每次提交一次提交,而不是多次提交一次大提交。)
Anything you do is going to be pretty ugly, since Git at a fundamental level knows what the filenames are supposed to be. A tree with different filenames has a different SHA1, so the commits do too, and nothing will ever match up. This means that there's not really anything reasonable you can do on GitHub, since there's a lot of history rewriting that has to take place.
There are two primary things you could try doing.
One: use
git filter-branch
with a tree or index filter to rewrite all of history in one repo, renaming the files. You can read the documentation or search online or here to find examples of that. There's an example in the manpage that's fairly close to your use case, the last one in the example section, which moves all files into a subdirectory, doing so in a way that's basically equivalent to removing or adding a prefix. Your version might be something like:(The sed replacement pattern is where you need to be careful.) You'd want to run it in a fresh clone, to avoid actually rewriting the branches in your original repo.
If you're working in both repositories, this will require a lot of careful work to stay in sync, avoiding mismatches between the two repos, and you'd have to do the opposite transformation to bring things back the other way. But if the exposed/shared one is read-only, then this option is wonderful; think of the filter-branch as a precursor to exporting. Save a script to do this, and all you'll have to do is clone, filter-branch, and push.
Two: manually transfer patches. You can use
git format-patch <revision-range>
to create patches, then do some automatic replacement of filenames in those patches, then apply them in the other repository. It's ugly, but it does work.I suppose that you could trigger either of these things off of a post-commit hook locally, but they might be more time-consuming than you want, since you'll probably commit often and want to move on immediately. One other option, which I assume you've already considered and dismissed for some reason, is to use your existing script, kicked off from a post-commit hook, to copy/rename files into the other repo, and immediately commit there. (One commit per commit, not one large commit per several commits.)
如果只有 git 存储库(目录)具有不同的名称,您可以通过设置另一个 git 远程来使自己更轻松:
git remote add;
。我希望您的情况也是如此,因为这是一种更简单的方法。但是,如果文件名也不同,但这些文件中的代码相同,您可以创建一个 git patch 并运行 sed 或其他查找替换命令更改该单个补丁文件中的文件名,然后将补丁
git apply
到其他存储库。这确实可以使用提交后挂钩和脚本来完成。If only the git repository (directory) has a different name, you could make it easier on yourself by setting another git remote:
git remote add <their-remote> <git-remote-url>
. I would hope this is the case for you as it's a far easier method.However, if filenames differ as well, but the code within those files are the same, you could create a
git patch
, and run ased
or other find-replace command to change the filenames within that single patch file, and thengit apply
the patch to the other repository. This could indeed be done using a post commit hook and scripted.