文章摘要
GPT 4o

本文适用于需要使用两台及以上 Mac 进行办公的用户,且拥有一定限制条件,这些限制是由 Anaconda 自身限制所带来的。

前言

台式机一般都是在家里用,笔记本则用于外出携带,桌面和文稿可以由 iCloud 进行同步,代码则交由 GitHub 托管。那么问题就来了,开发环境该如何同步呢?使用GitHub CodeSpace 构建云端开发环境或者使用 Docker 封装开发环境都是一些可选的解决方案,但总归还是直接在本地来的方便。命令行历史同步同理,在电脑 A 上使用过的命令,在电脑 B 又要输入一遍,有时候记不起来,降低了整体效率。之前其实也饱受该问题的折磨,但也懒得折腾,不过随着天气越来越冷,笔记本的适用范围又扩充到了被窝,终于下定决心来搞定这两个问题。

既然 iCloud 可以同步文件,自然可以同步这些开发环境。本质上命令行历史记录以及开发环境都是一些文件,只需要进行合理设置就可以了。所用的 [zsh]{.label .info}就是使用[~/.zsh_history]{.label .info}来进行命令行历史的记录的,而 Anaconda 则是安装时候的文件夹。具体思路是这样子,但在实际操作时有一些细微的问题需要处理。

命令行历史同步

[~/.zsh_history]{.label .info}中的内容举例如下:

: 1606565794:0;cat ~/.zsh_history

前面的是时间戳,后面的是执行的命令。最开始的思路就是写个脚本将不同电脑上的文件进行合并,之后放置于 iCloud 上,将[zsh]{.label .info}的历史记录文件指向 iCloud 上的文件即可,这样还有一个好处,在电脑 A 上使用新的命令之后,在电脑 B 上也可以马上更新,不过这取决于 iCloud 的服务质量,但大部分时间应该都是可以马上响应的。

之后在 GitHub 上发现了一个功能稍加丰富的插件,即zsh-histdb,原理就是将命令行历史导入 sqlite 数据库,并将 zsh-autosuggestions 的查询指向该数据库,不同的机器之间同步则采用 GitHub 的形式。

插件安装

mkdir -p $HOME/.oh-my-zsh/custom/plugins/
git clone https://github.com/larkery/zsh-histdb $HOME/.oh-my-zsh/custom/plugins/zsh-histdb

并在 [~/.zshrc]{.label .info}中添加如下内容:

HISTDB_TABULATE_CMD=(sed -e $'s/\x1f/\t/g')
source $HOME/.oh-my-zsh/custom/plugins/zsh-histdb/sqlite-history.zsh
autoload -Uz add-zsh-hook
_zsh_autosuggest_strategy_histdb_top_here() {
    local query="select commands.argv from
history left join commands on history.command_id = commands.rowid
left join places on history.place_id = places.rowid
where places.dir LIKE '$(sql_escape $PWD)%'
and commands.argv LIKE '$(sql_escape $1)%'
group by commands.argv order by count(*) desc limit 1"
    suggestion=$(_histdb_query "$query")
}

ZSH_AUTOSUGGEST_STRATEGY=histdb_top_here

导入命令行历史

go-histdbimportts-histdbimport 是用于导入的工具,根据 Star 数我选择了前者。

安装 go 环境及运行导入命令行历史工具命令如下:

brew install go
go get github.com/drewis/go-histdbimport
go run ~/go/src/github.com/drewis/go-histdbimport/main.go

使用

正常使用的时候配合 zsh-autosuggestions 与原本的方式无异,比之前要方便的是可以使用 histdb 来进行历史命令的查看,后面还可以输入关键词进行搜索,比原本更高效一些,还可以使用通配符 %

同步数据库

使用 [histdb-sync]{.label .info}命令会将[~/.histdb]{.label .info}下进行 Git 的初始化,之后再 push 到 GitHub 上即可。我做的有点丑陋,在电脑 A 同步至 GitHub 之后,将电脑 A 的文件夹 AirDrop 给电脑 B,之后同样的方式导入命令行历史记录,再推送至 GitHub,电脑 A 再进行一遍 Fetch 即可。

iCloud 同步 Anaconda 环境

非常清楚地记得在安装完 Anaconda 之后有一个 conda init 的环节,就是在 shell 配置文件中添加关于 conda 的内容。一开始我以为使用 iCloud 同步 Anaconda 环境非常的简单,只需要将 Anaconda 的安装时候的文件夹移动到 iCloud 上,并将 shell 配置文件中的指向改为 iCloud 上的文件夹即可,但事实并不是这样。

失败的尝试

该部分属于失败的尝试,可以直接拉到该小节结尾看总结,节省时间

当我将 Anaconda 文件夹移动到 iCloud 之后,我发现有 10 多个 G 的文件,于是我准备删除一些不用的环境,但是在删完之后发现,命令确实执行成功了,但被删除的环境竟然是原来的 Anaconda 上的,iCloud 上的依然还在,这让我开始有点疑惑了,于是查看 shell 配置文件中关于 conda 部分的内容:

# >>> conda initialize >>>
# !! Contents within this block are managed by 'conda init' !!
__conda_setup="$('/Users/xyzlab/anaconda3/bin/conda' 'shell.zsh' 'hook' 2> /dev/null)"
if [ $? -eq 0 ]; then
    eval "$__conda_setup"
else
    if [ -f "/Users/xyzlab/anaconda3/etc/profile.d/conda.sh" ]; then
        . "/Users/xyzlab/anaconda3/etc/profile.d/conda.sh"
    else
        export PATH="/Users/xyzlab/anaconda3/bin:$PATH"
    fi
fi
unset __conda_setup
# <<< conda initialize <<<

发现两个比较关键的部分,一个是 conda 文件,另一个则是 conda.sh,看着像配置文件,打开这两个文件看看到底有什么问题(只显示关建行):

#!/Users/xyzlab/anaconda3/bin/python
# -*- coding: utf-8 -*-
export CONDA_EXE='/Users/xyzlab/anaconda3/bin/conda'
export _CE_M=''
export _CE_CONDA=''
export CONDA_PYTHON_EXE='/Users/xyzlab/anaconda3/bin/python'

好家伙,发现这两个文件下的路径还是指向原来的 Anaconda 文件夹,所以之前能够正常运行 conda 且能删除原先 Anaconda 文件夹下的环境。

以为通过修改这个路径就可以实现环境同步的时候,我又遇到了一个新的错误,iCloud 所在的路径是

/Users/xyzlab/Library/Mobile Documents/

而 Anaconda 不支持带有空格的路径,我加了转义符或是通过字符串的形式都不行,于是将 iCloud 上的 Anaconda 文件移动到 Mac 上的「文件」文件夹下,这样一来既可以解决路径名称存在空格(桌面其实也可以,但是放在桌面太不优雅了,眼不见为净),又可以解决同步问题。

就当我以为要成功的时候,又遇到了一个错误,问题的出错形式跟上面的类似,也是路径问题,所以如果要实现 Anaconda 的迁移的话差不多需要把整个 bin 文件夹下的路径都修改了,一是工程量太庞大了且容易出错,二是可能会存在一些隐患,比如说没有处理到的问题,在未来某一天就出现了,埋下祸根。

总之直接迁移 Anaconda 文件夹来实现环境的同步实现不了,具体限制跟 Anaconda 自身也有关系,主要是:

  1. Anaconda 安装包会调用当初安装时的路径,且 bin 目录下的文件都会根据当初安装的目录结构进行文件的寻找,在移动之后该条件被破坏,导致 Anaconda 运行失败;
  2. Anaconda 安装路径中不能出现空格,使用转义符也没有效果,而 iCloud 云盘的路径中存在空格。

虽然直接的方法没有,但还是可以使用间接的方法来实现,不说应该也猜到了,就是重新安装一遍 Anaconda 并进行环境的克隆即可。但是,这个方式需要满足以下的条件:

  1. 多台电脑使用者的名称应该一致,如文中使用的用户名称是 xyzlab,则电脑 A,B 都需要使用 xyzlab,这是因为若出现用户名称不一致的情况会导致之前 Anaconda 迁移同样的问题;
  2. 将 Anaconda 安装于「文件」文件夹下,当然也可以安装在桌面,不过太丑了不推荐。

成功了(个屁)

最新更新:同步之后会存在莫名其妙的错误,如不能创建环境等,该方法作废。

基于上述的两个条件,在满足了之后只需要将 Anaconda 安装于「文件」文件夹即可,新的 Anaconda 中的环境也可以从原先的 Anaconda 环境中克隆,具体使用如下命令即可:

conda create -n 环境名 --clone 原先环境的路径 # 一般在 ~/anaconda3/envs/环境名称

自此,只需要等待 iCloud 完成同步(经测试会出错){.danger} AirDrop 之后,更改对应机器上的 shell 配置文件至「文件」文件夹的 Anaconda 即可。