如何使用git-bundle来保持开发同步?

75
我需要在不同电脑上同步我的开发树,这些电脑之间没有网络连接。我们有一个中央Git存储库,我通常在办公室电脑上使用自己的克隆版本进行工作。有时候我需要在另一台从未连接到办公室网络的电脑上进行开发。这些电脑都从未连接到互联网。在同步之间,可以在两台电脑上执行开发。我已经阅读了git-bundle的帮助页面,这似乎是最好的工具,但我不确定如何设置良好的工作流程。你能给我一些建议或指针吗?

1
如果他们连接到互联网,您可以使用DropBox与它们一起使用:请参见https://dev59.com/OXA65IYBdhLWcg3wyR2k#3633346 - VonC
1
抱歉,它们中的任何一个都永远不会连接到互联网。我已经将此添加到问题中。 - matli
2个回答

125

捆绑包!

使用git bundle的工作流程与任何其他工作流程基本相同。这似乎并不是非常有帮助的建议,但是这就是它:使用您通常使用的任何工作流程,并将“push / pull”替换为“在闪存驱动器上携带一个捆绑包,然后进行pull”。

实际上,手册中有一个非常好的入门指南,尽管它更像是单向示例。为了完整起见,这里是稍微修改过的版本,展示如何双向移动信息:

# on hostA, the initial home of the repo
hostA$ git bundle create hostA.bundle --branches --tags

# transfer the bundle to hostB, and continue:
hostB$ git clone /path/to/hostA.bundle my-repo
# you now have a clone, complete with remote branches and tags
# just to make it a little more obvious, rename the remote:
hostB$ git remote rename origin hostA

# make some commits on hostB; time to transfer back to hostA
# use the known master branch of hostA as a basis
hostB$ git bundle create hostB.bundle ^hostA/master --branches --tags

# copy the bundle back over to hostA and continue:
hostA$ git remote add hostB /path/to/hostB.bundle
# fetch all the refs from the remote (creating remote branches like hostB/master)
hostA$ git fetch hostB
# pull from hostB's master, for example
hostA$ git pull

# make some commits on hostA; time to transfer to hostB
# again, use the known master branch as a basis
hostA$ git bundle create hostA.bundle ^hostB/master --branches --tags
# copy the bundle to hostB, **replacing** the original bundle
# update all the refs
hostB$ git fetch hostA

# and so on and so on
关键是注意到你可以将一个 bundle 添加为远程,然后像其他远程一样进行交互。要更新该远程,只需放入一个新的 bundle,替换之前的即可。
我还采用了稍微不同的选取基础的方法。手册使用标签,始终与转移到另一台主机的最后一个 ref 保持更新。我只是使用了远程分支,它将指向从另一个主机传输的最后一个 ref。这有点低效;由于落后一步,你将打包比你需要的更多内容。但闪存很大,bundle 很小,使用已经存在的 refs 而不是要多走一步并小心处理标签,可以节省很多精力。
使 bundle 有点麻烦的一件事是你不能对其进行推送(push),也不能对其进行“变基”(rebase)。如果你想让 bundle 基于一个新的基础,你必须重新创建它。如果你想在其中添加新的提交,你必须重新创建它。这种麻烦引发了我的下一个建议...

放在一个闪存上的仓库

老实说,除非你的仓库真的很大,否则这可能同样容易。在闪存上放置一个裸仓库(clone),你可以从两台计算机上进行推送(push)和拉取(pull)。将其视为你的网络连接。需要传输到中央仓库?插上它即可!

1
git remote add 的正确参数顺序是先 name,然后才是 url - shytikov
5
顺便提一下,这种方法只有在hostB上提交的内容与hostA/master的提交记录关系较近时才有效。例如,如果您要在一个很长时间前从master分叉出来的分支experimental上工作,那么命令git bundle create hostB.bundle ^hostA/master --branches --tags将创建一个包含所有experimental历史记录的大型捆绑包。这并不是此方法的根本问题,只是需要小心处理。顺便说一下,如果其他人对于“^commit”语法感到困惑,它的意思是“不是commit祖先的所有提交记录。(请参见git-rev-parse,SPECIFYING REVISIONS)”。 - opqdonut
我怎么两个月前搜索离线git同步时没找到呢... 我一直在使用format-patch,并且(由于CRLF与LF的头疼问题以及我的团队中每个人都坚持有自己的行尾符策略)感到很麻烦。 赞!你节省了我数小时的工作时间。 - Félix Cantournet
2
git bundle create hostA.bundle --branches --tags 创建的捆绑包在我尝试从中克隆时会出现错误,"remote HEAD refers to nonexistent ref, unable to checkout"。使用 git bundle create hostA.bundle --all 对我来说似乎是有效的。 - Michael Burr
2
我编写了一个(希望)用户友好的Bash实现这个技术 - 参见 https://github.com/cxw42/git-tools/blob/master/wormhole。欢迎评论 - 个人体验可能有所不同 - 不提供保证 :) 。 - cxw
显示剩余4条评论

16

@Jefromi的回答非常好 - 比git文档要好10倍,后者详细介绍了难以理解的要求和操作。

虽然还是有些复杂,但这里是最简单的情况,只需要同步一次(在我的情况下:从一个没有WiFi卡的离线笔记本电脑同步到一个具有网络访问权限的台式机)。根据@Jefromi的回答,这似乎可以正常工作:

AHEAD = 一个比另一个机器超前一些提交的机器。 BEHIND = 你想要将提交复制到的机器。

1. AHEAD: git-bundle create myBundleName.bundle --branches --tags

同时:复制 myBundleName.bundle 文件(使用邮件、USB 或其他方式)

背后:(将文件 myBundName.bundle 放在项目文件夹外部的任何位置)

2. BEHIND: cd [the project folder]
3. BEHIND: git pull [path to the bundle file]/myBundleName.bundle master
只要在末尾包含分支名称(默认情况下,如果您不使用分支,则为“master”),这似乎很好地工作,并且不会替换BEHIND上的任何内部引用-因此仍然可以将其与源主同步。 换句话说,如果BEHIND具有Internet访问权限,则执行以下操作仍然安全:
(OPTIONAL) 4. BEHIND: git push

...并且它会更新主仓库,就好像你的更改已经像平常一样在本地完成了,在BEHIND上。


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