[技术总结] 多设备代码同步问题,目前有比较好的解决办法么?

2019-05-09 22:00:06 +08:00
 Deardrops

这篇帖子给出了一个“难题”,楼主也没有想出来好的办法,只能把自己搜集的资料和尝试过的工具总结出来,想起个抛砖引玉的作用。

问题描述

电脑的工作文件夹中有很多个 git 仓库,怎么简单高效地在多台电脑间同步这些 git 仓库?

问题剖析

  1. 多仓库批量同步 如果只有几个 git 仓库,直接传到 github 上,每天在电脑 A 和电脑 B 上执行 git pull 和 git push 就行。 但现在有超过 10 个 git 仓库,再手动执行同步操作不大现实。新的工具应该有一键批量 Push 和 Pull 的功能。

  2. 保存工作区的内容 电脑上做了一半的任务,一般是 stash 后下次接着做,但 stash 的内容并不会同步到远程分支上,所以不能用 stash 命令来同步。 也可以将做了一半的任务 push 到远程仓库的 WIP 分支中,另一台电脑 Pull 这个分支接着做。但会增加操作量。 新的工具应该帮助我们方便地同步工作区中未 commit 的代码。

  3. 过滤不必要的文件 一般仓库都带有 .gitignore 文件来过滤仓库中不需要同步的文件(夹),新的工具也应该读取或者直接使用 .gitignore。

现有方案

方案 A:网盘自动同步

网上看到有的解决方案使用 dropbox 和 syncthing 来同步代码,亲自测试了一番,效果并不好:

  1. 必须要手动设定一些 ignore 列表,把诸如 node_modules 或者 dist 这样的文件夹过滤掉。
  2. 会把 .git 文件夹给同步上去,经常提交的仓库,.git 目录下会有成千上万小文件,经常因为 I/O 导致同步很慢甚至失败。

这种同步方式并不优雅。

方案 B:git 内置命令

从 git 本身入手,寻找一种可以兼顾简单和高效的解决办法。

尝试了 git submodule 和 git subtree:

  1. 前者比较贴近这样的应用场景,每个子文件夹作为一个 submodule,子模块独立地更新,主仓库每次需要添加 submodule 最新的 commit 记录,每次手动执行也挺麻烦的,并且要求 submodule 的 commit 记录必须已经提交到远程分支上,不然主仓库没法 Pull 和 checkout。实际上,手动更新子模块并没有为我们节省多少工作量
  2. 后者就比较复杂,可以理解为对子文件夹的所有修改都是在一个主仓库中进行,当子仓库需要提交代码的时候用 git subtree push --prefix 命令把子仓库代码提交出去。这个方法有个很大的问题:子仓库无法切换分支,要切换只能先删除该 subtree 再添加。

方案 C: 多仓库管理工具

以 repo 为代表管理工具,大多是通过 python 或者 bash,实现批量 pull/commit/push 多个仓库的功能。

亲自尝试了一下 myrepos 工具,能用,可以一键 Pull,添加其他的功能配置繁琐,最关键的是文档找不到。google 家的 git-repo 也是这样的问题,摸索了一圈没有什么收货,只能看看内置的 help 文档。

相关问题

搜索了一圈发现,这个问题从 2013 年起提到现在,一直没有较好的解决办法,各位 v 友有什么见解么?

9135 次点击
所在节点    程序员
44 条回复
pmispig
2019-05-10 10:39:21 +08:00
哪有那么多事,全放到 svn 一个 repo 里面,随时提交
Hellert
2019-05-10 10:47:22 +08:00
自己用的是群晖 Cloud Station Drive,.git 文件夹都是完整上传的,自建 NAS 不像网盘,不用考虑空间容量的问题。
几个同步点都是电信网络,加之去年开始运营商的上行速度都放开了,传输非常快,NAS 优势非常明显。
goodleixiao
2019-05-10 10:47:54 +08:00
兄弟们,你们可以尝试一下 git mirror 功能,绝对满足各位的需求,包括 USB,网盘同步。别在傻傻的复制整个工程。

git clone --mirror path/project

会生成一个干净的 path/mirror/project.git 文件夹,

git remote add local path/mirror/project.git
git fetch local
git push local
同步代码简单、方便、快捷。
no1xsyzy
2019-05-10 14:36:41 +08:00
no1xsyzy
2019-05-10 14:42:48 +08:00
啊我瞎
no1xsyzy
2019-05-10 14:46:33 +08:00
myrepos 的文档在上述网址,基本上全了
实质 Makefile,甚至有 $@ 这种东西……。
zsxzy
2019-05-10 14:59:56 +08:00
我也有一堆.git , 写个批处理完事, 全传 github
uc2664360
2019-05-10 15:07:07 +08:00
我有一个想法不知道能不能实现楼主的目的:git 和 SVN 结合。
所有的 git 项目都放在一个 svn 目录下,有需要发版本的,git 上该怎么操作就怎么操作。
如果像那种在一台电脑做了一半,想在另一台电脑接着做的,又不想 push 到 git 远程仓库的,那么这时候直接全量提交到 SVN,在另一台电脑上使用 SVN 拉取。
SakuraKuma
2019-05-10 15:10:43 +08:00
onedrive+1..
前公司经常干的事情, 其它方案实在太繁琐了.
smilejava
2019-05-10 15:20:28 +08:00
这是要同步 git 仓库代码? git hook 了解下
Afanyiyu
2019-05-10 18:31:28 +08:00
Vscode remote
Azure devops+git
janxin
2019-05-10 18:36:56 +08:00
欢迎体验 VSCode Remote
secondwtq
2019-05-10 23:01:00 +08:00
@Deardrops 我昨天半夜迷迷糊糊过了一遍主楼几个链接和一堆回复之后似乎就忘了顶楼提过试过 submodules 和 repo 之类的了,写回复的时候以为楼主没仔细了解过,抱歉。

关于顶楼提到的几个问题,submodules 没仔细了解过所以不好评价,但是 repo 我觉得还不错,文档缺失实际上是大多数开源项目的通病,就算是明星项目也很难保证文档是全的(更何况文档多了甚至会有人抱怨太 overwhelming 不知从何下手),冷门项目更难说,所以在看免费 /开源方案的时候就有必要做好 DIY 的准备。我个人觉得重要的是学习整个工作流的思想。另外一个适合自己的方案很多时候是拼出来的,如果 repo 能满足批量 push 和 pull 的功能,那其实就可以考虑把这一小部分集成进自己的工作流里面。按照“重新造一个新轮子”的逻辑执行,其实不一定比 battle tested 的旧轮子效果好。按照这个逻辑还可以推导出:Chrome 太占内存了重新造一个,python 性能太慢了重新造一个,cpu 太热了要不明天去海边整点沙子也自己造一个把 ...

单独开分支存放 WIP 内容确实会造成额外的操作,但是这个额外操作是能*换来*一点好处的。比如我上个回复提到的对实时性的控制:假设有一个理想化的方法,解决了网盘同步 .git 目录很麻烦的问题。现在我在 A 机器上改了一点东西,用网盘同步,然后(出于某种原因)立马切到 B 机器上,网盘可能不能做到立即同步,你得去轮询文件的同步状态 ... 但是通过 git 一通额外操作,是可以让你确定同步完成的。在用脚本做了一定的自动化之后可能就是一个命令的事,最后对用户的负担可能还要比用网盘同步然后轮询状态更小。

因为物理法则限制,没有网盘能做到立即同步,而如果要在一个特定的时间要求特定的一部分文件做到优先同步并且以某种方式通知之类的需求,用户依然得 somehow 把这个需求描述给计算机,这就是那些“额外操作”。

这里有一个问题就是,git 这个东西并非完全针对楼主的使用场景设计,它设计的这些额外操作其实在多人协作分布式开发开源软件(或者说就是 Linux Kernel )的场景下才能做到最大的效率提升。所以楼主觉得麻烦,因为这个脚和鞋的尺码对不上。我个人的思路是可以考虑针对这一点做改进和增强,比如做一个脚本,把所有 unstaged/cached changes commit 到 WIP 分支,然后 push,写个编辑器插件,保存的时候自动运行,每台机器在打开项目的时候自动 pull。这个东西就是专门定制的,比如就没有考虑多人开发,如果把这个强行套到多人开发,只要出个 conflict,处理过程会比手动处理更麻烦,是没有带来方便的。

大致意思是最好不要期待有现成的方案,确实有不少,但是就像楼主说的有这样那样的问题,没有万能的。就算真有,哪天换个公司,换个条件,场景又变了,可能就没那么有用了
secondwtq
2019-05-10 23:06:09 +08:00
另外 VSCode Remote 是不开源的。我个人虽然反对逢微软就反,但是这个事情依然给我一种微软把 VSCode 开源拿来钓鱼,鱼上钩了就给你套回闭源环境的感觉

客观来讲 VSCode 似乎被大家广泛黑的只有 Electron 一个黑点(除了是微软出的这种无理取闹以外),并且我觉得这不是 VSCode 的原罪。所以其实这个饵还是下了血本的,然而依然改变不了钓鱼的本质

VSCode 这个饵我吃了,该占的便宜要占。Remote ?抱歉,坚决不上钩

话说 VSCode 图标就是俩圈,真的挺适合挂钩上的
hst001
2019-05-10 23:17:33 +08:00
vs code remote 可能会成为开发趋势,特别是省掉大量环境配置问题,不过养个 vs code remote 硬件可能要花费不少
weixiangzhe
2019-05-11 00:07:09 +08:00
我的项目里也是一堆包,一个前端项目能分 7 8 个 npm 包,烦死人的,现在是简单手写的个 python 搞了一下,我的目录是这个

├── updateReps.py
├── rep1
├── rep2
├── rep3
├── rep4
├── rep5
└── rep6


每次跑下 python3 ./updateReps.py 这样
```python
import os
from os import path

git_dirs = [
"rep1",
"rep2",
"rep3",
"rep4",
]


class bcolors:
HEADER = '\033[95m'
OKBLUE = '\033[94m'
OKGREEN = '\033[92m'
WARNING = '\033[93m'
FAIL = '\033[91m'
ENDC = '\033[0m'
BOLD = '\033[1m'
UNDERLINE = '\033[4m'

def printGreen( str ):
print(bcolors.OKGREEN + str + bcolors.ENDC)

cur_dir = path.dirname(path.abspath(__file__))


if __name__ == "__main__":
for git_dir in git_dirs:
git_dir_path = path.join(cur_dir, git_dir)
if os.path.isdir(git_dir_path):
os.chdir(git_dir_path)
printGreen('[run] [git pull] in ' + git_dir_path)
os.system("git pull")

print('-------------------------')
printGreen('finished')

```
dai640
2019-05-11 00:19:19 +08:00
学习,这个帖能让人少走很多弯路
janus77
2019-05-11 00:29:38 +08:00
直接做成一个大 git repo。
理由:你有这个需求吗:每个小仓库要分别控制是否都同步?比如今晚 2 个仓库都有代码改动,但是 repo A 需要同步 而 repo B 不同步?
如果有,那如何用「一次性」实现?要知道这个规则是动态的,你原来传统的方式是 git 分别 push,哪个 push 哪个不 push 是随时有变动的,一次性根本实现不了(因为每次的规则都不一样。如果你每次把规则定义好,那么工作量和你原来的传统方式基本上没区别。)
如果没有,那就是统一同步了,为何要分多 repo ?
所以比较好的方法是直接单 repo。
feelapi
2019-05-11 00:38:44 +08:00
直接单 repo,很多大公司也是这么搞的。还有相应的工具。比如 ms 的 rush,可以用在多 project,单一 repo 的前后端合成的环境中。
icylogic
2019-05-11 04:28:35 +08:00
看了这么多楼没有提 worktree 的,我现在的方案就是 nfs + worktree ( nfs 可以换成任意可靠的自动同步工具),前者解决“在本地和远程上同时编辑和运行同一份代码“的问题,后者解决”本地和远程开发不同分支”的问题。

例如,我现在本地写得差不多,准备发布一个版本,那我需要 checkout 一个 release 分支出来,在开发服务器上做一些 pre release 的测试,这个过程中,我是很有可能发现问题,又返回去修改一些代码,再反复在本地和远程测试的,那我就可以从 .git 里 用 git worktree 命令,把这个 release 分支放在 nfs 下,这样本地和远程就自动同步了。这种需求下,**你往往需要同步的只是是 checkout 出来的这份代码,而不是整个 .git 目录**,而 worktree 正好避免了同步整个 .git 目录,你放在 nfs/sshfs/网盘上放的一切都正好是你需要同步的所有文件,不多也不少。

而你用 git 本身去解决这件事就很麻烦,首先你很难处理 unstaged files,因为一部分你暂时并不想提交上去,一部分却是需要马上同步的,而 git 提供的最小同步粒度一般就是 commit 而不是 file,你用 commit 和 stash 去模拟 file level 的同步,就一定会比 nfs rsync 网盘这些别扭,人家就是专业干这个的。而且 git 你至少需要手动 push fetch,如果你经常有这种远程调试的需求就知道这种手动同步有多恶心了,本来从逻辑上讲,虽然有多个机器,但只有你自己一个人在动代码,那自然就是最新的更改直接自动覆盖过去就好了。用这些工具同步 repo 的唯一问题是你并不想把.git 目录传来传去,那 worktree 出来解决了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/562666

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX