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

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 友有什么见解么?

8589 次点击
所在节点    程序员
44 条回复
Kahnn
2019-05-09 22:08:13 +08:00
"保存工作区的内容 电脑上做了一半的任务,一般是 stash 后下次接着做,但 stash 的内容并不会同步到远程分支上,所以不能用 stash 命令来同步。" 这个我觉得转变思路就好,做了一半也可以提交 commit 啊
Deardrops
2019-05-09 22:11:44 +08:00
@Kahnn 接下来的后面半句 “也可以将做了一半的任务 push 到远程仓库的 WIP 分支中” 就是这个意思。
nimrc
2019-05-09 22:16:20 +08:00
icloud
raynor2011
2019-05-09 22:55:42 +08:00
ssh 到一台机器上去写
version
2019-05-09 23:09:55 +08:00
git flow 中 feature 没到 pr 前不要每天 commit 多个.隔几天再 pr..依赖更新最新的分支后会处理冲突都老半天
如今微服务年代..调试服务的 rpc 脚本.导入数据.改 bug 重现.各种服务加起来.数据库.消息队列.定时器各种.
本地电脑起完还是很累的..
单个服务调试.用跳板机连线上测试服微服务..然后本地调试自己的模块服务 bug.
但是这种难免会写一些脚本.这种代码在两台电脑同步就纠结了.我一般代码会写在 dist 然后打包 icloud.同步.
复杂的就自己服务器跑一套完整的流程.传自己的 git.改代码 bug.打 log 提交.然后 webhook 全部服务自动重启.打 log 看看错误..留意自己服务器安全就好.一般偷偷摸摸..然后改完的代码..在对比复制到公司的代码库.提交就好..神不知鬼不觉..这样改 bug 效率会高很多.也不扯犊子占用测试服务器.也不干扰其它同事..如果公司 git 日志看到一堆 debug 提交记录.不知道会不会被骂死...vscode 的 web 服务器版本也是不错的.未来趋势发展.
今天累想划水带 MacBook12 寸.写服务端代码 (出门旅游.回老家带 12 寸+手机 4g 网络)
有心情加班带 MacBook15 寸高配主力+再写点前端代码
能迁移到自己服务器编写的都远程自己服务器..
yuanfnadi
2019-05-09 23:13:15 +08:00
projj 可以实现 开源项目
SoloCompany
2019-05-09 23:29:46 +08:00
买一台 12 寸 MacBook 工作机随身带
cht
2019-05-09 23:56:30 +08:00
都放 onedrive 不知行不行,自己日常需要多设备的文件基本都放在 onedrive 上
foobar2000
2019-05-10 00:26:32 +08:00
没有优雅的办法,.git 文件夹同步,想想就恐怖

随身携带个 msata 组的 u 盘,解决多设备同步
hlwjia
2019-05-10 00:33:00 +08:00
问题 1. 多仓库批量同步

Makefile 不行吗?
jss
2019-05-10 01:12:59 +08:00
哪那么多事,谁生产随管理
randyzhao
2019-05-10 01:37:13 +08:00
我就好奇是什么导致了这种需求。
同一个人,多台电脑,频繁切换。

我觉得实在不行,可以自己写脚本,用脚本来完成 pull push commit 之类的操作。脚本通过网盘同步,每次切换电脑前,执行一下批量提交;切换电脑后,执行一下批量更新。
secondwtq
2019-05-10 03:05:35 +08:00
@randyzhao 我这两天就正好有这样的需求,首先我是在 server 上开发,但是公司 server 有些小问题,比如三天两头挂或者下线维护,工具链不统一,一些服务和工具只有部分 server 可以访问,server 分布在全球网络状况不一样,特定的测试需要独占 server 被分配到其他 server 上等等。另外我在不同 server 上配置的环境也有一些区别,比如有的我配了完整的 VNC+VSCode,有的我配了 code-server,有的我配了 Emacs,有的我连 .vimrc 都没碰过,虽然我意识到问题之后在尽量做统一,不过不是三两天就能改的。有些工作也会在本地 Debian Desktop 上处理(然而 server 是 RHEL,并且使用的模式完全不同 ...)

第一,如果无法接受同步 .git 文件夹的话,那其实已经不是小项目了,就算没有 git 之类的东西,项目本身的文件数量也会造成不小的压力,所以并不完全是 .git 文件夹的问题。另外 git 有一个 pack 的特性( https://git-scm.com/book/en/v2/Git-Internals-Packfiles ),可以把 .git 里面的 objects 打包成若干大文件,你看下你从 GitHub 上直接 clone 下的 repo,.git 文件夹下其实是没有几个文件的

第二,用过 git submodules 么?“一键批量 Push 和 Pull ”之类的根本不需要什么“新的工具”。虽然我觉得我不会选择 git submodules (所以这个例子只是描述类似的通用的方法)。Android 用了一套 Python 脚本叫 repo 做得更完善一点,虽然我觉得有点慢还依赖 Python 大概也是不会用的 - -

第三,一个 WIP 的 patch 不是必须 stash,也不是必须 commit,也不是只能放着不管——上面提到的 repo 工具提供了一个新思路,就是专门开一个 branch,把半成品 commit 上去,这个 branch 只有这一个 commit,只拿来当 (某种意义上) stash 的替代品,没有其他任何功能。这样就可以利用 Git 分布式 push 和 pull,当你迁移到另外一台机器上,pull & checkout,干活,完后 git commit --amend,push (这个需要 -f),当然你觉得 push -f 不 clean 可以选择单独 commit,反正是专门的 branch 可以随便搞事,全 done 之后 squash 到一个 commit 就是。这是充分利用 git 的优势

第四,我觉得这个问题没有一个万能的方案,应该针对不同的情况具体分析。比如如果一个人不用 git 或者多种 VCS 混用,网盘的通用性就更有好处。我的很多私人数据一直是 syncthing 同步的,因为首先个人数据不止是软件项目,就算有一些很像软件项目,其实并不一定适合用 VCS 的方式来管理(比如 Word 文档和 Sketch 稿),所以我不能依赖 git 这一特定的系统,其次并不是所有的代码都会被 git 管理的,就算是 git 仓库,利用 git 做同步的优势其实也并不明显(特别是考虑到前段时间 GitHub 没有免费 private repo 的情况),另外 push pop 乃至于偶尔处理 conflict 都是额外的 overhead,网盘基本就是扔在那就不用管,至于同步速度之类的那是实现细节的问题,理念上来讲我觉得网盘还是占优的。

我自己还是遇到了一些问题,比如在家里用 desktop 改了东西想要立刻在 laptop 上面测试,syncthing 是没办法实时同步的。另外公司环境下是不能乱用软件的,尤其不能用第三方云服务。但是机器环境比我个人的还要复杂一点。我有一些替代方案:
NFS/sshfs/Samba,这个用好了可以很 versatile,首先家里 NFS 可以随时访问整个文件库这个大家都知道。我还会单独做一个共享用来放临时文件,包括一些 demo 啊截图啊之类的,这个还可以当 poor man's Airdrop 解决上面的实时性的问题(有实时性的需求一般都是需要额外操作的,git 和 Airdrop 都是,所以这个没有本质区别,还不依赖 Apple 的生(jiu)态(cai)圈)。
另外我还会把代码仓库在本地 mount 一份,这个可以直接在本地用 native 的方式操作远程文件(抽象真的是很神奇的东西)。在网络可以的条件下,对于中小型仓库而言性能的损失不明显(所以也是楼主问题的一个可能解决方案)。大仓库问题就比较大,就算开大缓存(这个会牺牲实时性,基本等于 read only 了) git status 都要半天,但是需要利用本地工具操作较多文件的时候还是有用的(比如里面有一堆的 pdf 或者 md 或者 office 文档,本地的阅读器是用着最顺手的)。
这个当然不局限于两台机器,所以你可以把做好的 test case,脚本或者 patch 放在里面,立马就可以在网络上任何机器上用。
在公司中心的代码仓库是限制 commit 的(我也没有用某台 server 做中心库),所以用上面说的开 branch 来替代 stash 的做法不是特别现实。我的解决方案是在 A 机器上改完之后本地 commit (不 push 也没法 push ),在 B 机器上把 A 机器的仓库地址添加为新的 remote,然后 git fetch A 机器的仓库,git cherry-pick FETCH_HEAD,更改就拉过来了。我觉得这个流程绝大多数人都用不到(一个中心库就能搞定),在我这确实解决了问题,所以说要根据自己需求定制。
Deardrops
2019-05-10 08:33:18 +08:00
@randyzhao 很普通的需求,实验室一台电脑,家里一台电脑,手上一台笔记本,三台电脑随时拿来码代码。

@secondwtq 大概这就是想引的玉吧,很感谢你的回复。git gc 命令之前我是真的不知道,如果可以先 gc 再用 syncthing 同步,应该可以解决小文件同步的问题。另外,本地 mount 一份远程代码库也是一个比较好的办法。
yzkos
2019-05-10 09:01:54 +08:00
不知道我理解的对不对,
你可以写个脚本,放在工作目录下,遍历 git 仓库然后循环执行 git pull ? 每次开发要离开或者关闭电脑的时候把代码 git push 到 WIP 分支中。
这样在另一台电脑上执行你的脚本,批量拉取一下,就可以继续之前的代码工作?
carlclone
2019-05-10 09:16:06 +08:00
我是 TeamViewer 远程 , 只在一台上写,反正公司的电脑从来不关
Fule
2019-05-10 09:21:35 +08:00
@cht1995 我就是这么做的。所有的项目代码都建在 OneDrive 的控制的文件夹里(主要项目所有文件包括.git 里的超过 2G )。而且开了 File On Demand。不过好像核心的目的不是为了多设备同步,而是为了备份。

毕竟速度再快,同步也是需要时间的。不太可能这台设备写了一些代码,然后马上换另一台设备就能立刻同步到之前的更改。。。搞不好还是有文件内容冲突的风险。

所以,我觉得解决问题的根本方法,还是弄一台好笔记本电脑配上合适的附件吧。我就是一台 Surface Book 2,公司和家里各配上 Surface 拓展坞 + 2 台显示器,然后外面用 SB2,家里和办公室只需要把 SB2 插上拓展坞就行了,永无同步之忧。
yrom
2019-05-10 10:08:36 +08:00
把一台电脑当 server,其他电脑远程连上去,如用 VS Code Remote
luozic
2019-05-10 10:09:59 +08:00
nvme 固态外置硬盘。ide 和代码统统放硬盘上
crackhopper
2019-05-10 10:36:47 +08:00
一个 git 项目就行了吧。放到子文件夹里面。其实我搞 node 的时候,就用 lerna 组织代码,一个项目包含所有的。很难理解拆分一堆项目怎么想的。一个就够了。

git 的 submodule 也比较坑,很多工具不支持。

而且就算一个项目未来想要把某个子文件夹拆分出来给别人,也有 filter-branch 命令可以形成 repo

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

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

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

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

© 2021 V2EX