多台电脑间的 Hexo 博客同步

    Hexo

由于文化程度低,所以只能靠使用多台电脑来满足随时写文章的需要。这里记录一下多电脑间同步博客的方法。


配置第一台电脑

确保你在 ~/Documents/blog 文件夹里

$ pwd
~/Documents/blog    ## 确保在正确的目录下

使用 Mac 自带的 Git 对 ~/Documents/blog 文件夹进行追踪

$ pwd
~/Documents/blog    ## 确保在正确的目录下

$ git init
$ git add .
$ git commit -m "initial commit"

到 Github 上新建一个 repository,命名为 blog(可以选自己喜欢的名字),然后把本地的 blog 文件夹推送到 Github 上

$ pwd
~/Documents/blog    ## 确保在正确的目录下

$ git remote add origin git@github.com:你的用户名/blog.git
$ git push -u origin master

找到自己喜欢的 Theme(主题),然后 fork 一份 Theme 的代码到自己的 Github 账户下面

之所以要 fork 一份,是因为你很可能要进一步开发这个 Theme,把它改成你想要的样子。比如我的博客的主题选择的是 Gaoryrt 老师开发出来的主题 pln,但该主题只有 60% 的部分是我喜欢的,要改的地方非常多。

有些玩家是主题(Themes)和文章(Posts)混在一起进行版本控制的,我则喜欢将两者分开维护,即「内容」和「样式」分离。所以接下来的操作就是要把 Theme 独立成为一个模块,在 Git 的版本控制下进行维护和修改。

这里使用 Git 的 Submodule 功能,将博客的 Theme(主题样式)模块化出去

$ cd ~/Documents/blog/themes
$ git submodule add git@github.com:你的用户名/hexo-theme-pln.git

上面的两条命令会把你 fork 过来的主题下载到 ~/Documents/blog/themes 目录下,由于主题名为 pln,所以我们会看到 ~/Documents/blog/themes 目录下多了一个文件夹 pln,主题就存在这个文件夹里。

此外 git@github.com:你的用户名/hexo-theme-pln.git 这串地址可以在你的 Github 账户下对应的 repository 中找到(当 fork 某个 project 之后,会在你的 Github 账户下生成一个 repository

仔细的你可能已经注意到 ~/Documents/blog/themes/pln 目录下有个 .git 文件,因为 pln 文件夹在被生成之后就被 Git 追踪了,这也意味着无需再在 pln 文件夹里使用 git init 来对它开启追踪。

注意!这时我们面对的是一个普通玩家从未遇到的情况:

一个被 Git 追踪的文件夹里(blog 文件夹)存在着另一个同样被 Git 追踪的文件夹(pln 文件夹),这两个文件夹的根目录下都有一个 .git 文件

Don’t panic! 这正是 Git 的 Submodule 功能的效果,目前一切正常。现在我们暂时先不管细节,带着这些看起来很重要的不自在继续前行。

好,我们接着进入 pln 文件夹,并使用 git checkout master切换到 Git 的主分支 Master(之所以需要切换,是因为新生成的 Submodule 文件夹,即 pln 下,默认不在任何分支上,不像平时我们对某个文件夹 git init 之后就默认在主分支 Master)

$ cd ~/Documents/blog/themes/pln
$ git checkout master

然后修改 pln 文件夹里的内容得到满意的风格(如果已经满意可以不修改)

$ pwd
~/Documents/blog/themes/pln  ## 当前在 pln 目录下

$ git branch
* master                     ## 确保在 master 分支上,不然 commit 就跑到 detached HEAD 上了

## 对主题的样式做各种改动(和平时的 Git 操作一样)
## 注意若是修改了 CSS 样式,要压缩生成 m.min.css 才能生效,网站因为最终采用的 CSS 是 m.min.css
## main.scss 和 m.min.css 文件都在 blog/themes/pln/source/css 目录下
$ sass --style compressed source/css/main.scss:source/css/m.min.css

$ git add .
$ git commit -m "change pln theme to meet my taste"

pln 里各种 commit 之后,我们终于感觉可以 push 了,于是

$ pwd
~/Documents/blog/themes/pln     ## 确保在正确的目录下

$ git push

这样一来,Github 上我们之前 fork 过来的主题 pln 就成功同步更新了。

这时我们切换到 blog 文件夹,运行 git status,可以看到 Terminal 提示 pln 文件夹有新的改动需要 commit

$ cd ~/Documents/blog
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)
  (commit or discard the untracked or modified content in submodules)

  modified:   themes/pln (modified content)

no changes added to commit (use "git add" and/or "git commit -a")

于是我们

$ pwd
~/Documents/blog     ## 注意当前目录是 blog

$ git add themes/pln
$ git commit -m "change submodule pln theme to meet my taste"
$ git push

完成后,我们 Github 上 blog 所对应的 repository 也就成功和同步更新了。


中场解说

感谢各位玩家勇敢地保持疑惑直到现在,对于已经迷路的各位我准备用一个简单的总结把大家拉回来:

  • 以上对第一台电脑的各种操作一共涉及 3 个 Github 上的 Repository

    • 你的用户名.github.io(如 chpwang.github.io)
    • blog
    • pln
  • Hexo 会把 blog 文件夹里的各种内容转化成 html 文件部署到 你的用户名.github.io 这个 repository 上,所以互联网上通过 http://你的用户名.github.io这个网址看你的博客的人实际上看到的是 你的用户名.github.io 这个 repository 里的内容

  • blog 这个 repository 是用来在别的电脑上同步博客内容的。Hexo 每次部署博客都要使用 blog 文件夹里的内容来生成相应的 html 文件。如果我们选择通过 你的用户名.github.io 这个 repo 而不是 blog 来同步博客的话,这意味着我们需要直接编辑 html(你的用户名.github.io 这个 repo 里全是 html 文件),进而无法享受 Markdown 格式排版带来的便利。

  • 作为 Submodule 的文件夹(也就是 pln)如果改动了,则需要 commit 两次来保存(pln 文件夹里 commit 一次,blog 文件夹里也要 commit 一次),相应的也要通过两次 git push 来同步远程的两个 repo

  • blog 文件夹里的改动仅需要 commit 一次保存


配置第二台电脑和之后的电脑

搞定了第一台电脑的配置,之后就简单多了。

首先必须确保第二台电脑安装了 Hombrew , Node.js, HexoSASS

## 这条命令安装 Homebrew
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

## 上条命令完成后,就可以通过 Homebrew 安装 Node.js
$ brew install node

## Node.js 安装后,会附带 npm(node package manager)工具,可用它来搜索、下载、管理 Node.js 套件
## 接下来使用 npm 安装 Hexo
$ npm install hexo-cli -g

## 然后确保你安装了 Ruby - 因为接下来要使用 gem install 命令
## 安装 SASS - 使用 Ruby 语言写的 CSS 的开发工具,后面会用于压缩整合 main.scss 文件,命令为: sass --style compressed main.scss:m.min.css    
$ gem install sass

然后在第二台电脑上 git clone,先拉 parent repository,也就是 blog

$ pwd
~/Documents    
## 选择一个目录准备 git clone

$ git clone git@github.com:你的用户名/blog.git
## 这条命令会在当前目录下生成一个 blog 文件夹

注意git clone 之后,虽然 ~/Documents/blog/themes/pln 文件夹存在,但里面是空的,因为这是我们第一次在这台电脑上建立 blog 这个文件夹。这第一次,需要我们使用以下两条命令同步作为 Submodule 的文件夹,也就是 pln

$ pwd
~/Documents/blog

## 注意此时的目录是 blog,我们要在这个 Parent Directory 下运行下两条命令

$ git submodule init       ## 这条命令会读取所有 submodule 的远端地址,这里是 pln 这个 repo 的地址
$ git submodule update     ## 这条命令会把 pln 这个 repo 的内容从远端拉下来

第一次建立之后,如果远端的 pln 文件夹有更新,只需使用 git submodule update 来同步即可,不必再运行 git submodule init

## 如果不是第一次建立属于 Submodule 文件夹,只需要运行 git submodule update 命令即可(文件夹已存在,例如本例子中的 pln 文件夹就属于 Submodule 文件夹)
$ pwd
~/Documents/blog

## 注意此时的目录是 blog,我们要在这个 Parent Directory 下运行 git submodule update
$ git submodule update

接下来这步很重要,因为非常反直觉。
第一,第一次使用 git submodule update 同步后,我们需要手动切回 master 分支。

之所以要运行 git checkout master 手动切分支,是因为每当我们运行 git submodule update 后,submodule 文件夹(即文件夹 pln)的 Git 默认会指向一个 detached HEAD,也就是说,我们当前并没有处于任何分支上,所以我们需要 git checkout 切换回 master 分支,否则我们的在 pln 文件夹下的所有 commit 都不在任何分支上。

如果不是第一次使用 git submodule update,当远端有更新内容被拉下来时,所更新的内容会在一个 detached HEAD 上,我们要通过下面的操作将它合并到 master 分支上。

$ cd ~/Documents/blog/themes/pln     ## 注意 pln 是作为 submodule 的文件夹
$ git status                         ## 查看状态可看到当前处在一个 detached 的 commit 上
* (HEAD detached at e522ed6)
  master

$ git checkout master         ## 手动切回 master 分支
Previous HEAD position was e522ed6... change logo again
Switched to branch 'master'

$ git merge e522ed6           ## 将 detached 的 commit 合并到 master 分支上

假设你忘了切回 master 分支就改动 pln,那怎么办?别怕,先 commit 保存你的改动,然后像上面一样切回 master 分支,再把 commit 合并到分支上

$ git add .
$ git commit -m "make some change but forget changing to branch master"

$ git checkout master         ## 手动切回 master 分支
Warning: you are leaving 1 commit behind, not connected to
any of your branches:

  bcfc7fb make some change but forget changing to branch master

If you want to keep it by creating a new branch, this may be a good time
to do so with:

 git branch <new-branch-name> bcfc7fb

Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.

$ git merge bcfc7fb           ## 使用 hash 值 bcfc7fb,将其对应的 commit 合并到 master 分支上

这样,就可以救回你对 pln 文件夹的改动了。

大致对以上有印象后,现在切换回 blog 文件夹运行 npm install 。这里需要注意的是,如果使用代理运行 npm install 可能会报错乃至失败(例如 proxychains4 npm install),如果失败请不要使用代理。一些其他报错可参考这里这里

$ cd ~/Documents/blog
$ npm install         ## 执行这条命令,npm 会根据 package.json 文件安装所有需要的套件

## 刚才 git clone 把云端的文件拉下来之后,blog 文件夹下一个叫 package.json 的文件也被拉了下来,npm install 命令会通过它得知需要安装的套件

# 可以使用以下两个命令来更新和查看 package.json 里所记录的套件
$ npm update    ## 更新套件
$ npm outdated  ## 查看哪些套件过期(即有新版本)

这里要提示一下,npm 这种东西,安全性其实很可疑,个人博客将就着用就行了,但不建议用在敏感产品上,参见这篇帖子

至此,第二台电脑就同步配置完成,可以继续写文章发布了。总结一下:

  1. 使用以下命令写文章和发布

    $ hexo new "文章标题"
    
    ## 编辑文章
    
    ......
    
    $ hexo clean   ## 清空缓存
    $ hexo g       ## 生成静态页面至 public 目录
    $ hexo server  ## 开启 Server(默认网址 http://localhost:4000/,'ctrl + c' 退出)
    $ hexo d       ## 部署到 GitHub
    
  2. 更改 Submodule 文件夹后(比如 pln 文件夹)需要 commit 两次,里外各一次。同样地,此时需要两次 git push 来同步远程的两个 repo

  3. 更改 parent 文件夹 blog 后只需要 git commit 一次,git push 一次

  4. 更新本地文件时,先在外层文件夹 blog 中运行 git pull 来更新 blog,然后运行 git submodule update 来更新 submodule 文件夹

  5. 每次运行 git submodule update 后,submodule 文件夹里的 Git 默认会指向一个 detached HEAD,要记得切回 master 分支合并一下从远程更新过来的 commits 再继续。确实不小心忘记了可以回到上面的教程看一下怎么救回来。

  6. 有时运行 git submodule update 同步子模块时会出现以下报错。这是因为前一台设备在改动 submodule 文件夹之后(本例中为 themes/pln ),忘记使用 git push 推送到远程服务器了,所以命令在请求远程 Server 时,就找不到 commit e8e0dc...(总之,更新 submodule 文件夹需要两次 git push,别忘了哈)

    ## 由于只在 blog 文件夹里 git push,忘记在 blog/themes/pln 里 git push,所以 Git 知道 commit e8e0dc... 的存在,但是却找不到它
    $ git submodule update
    error: Server does not allow request for unadvertised object e8e0dc399b38f6ba01720c65bd64a1bdb9b68755
    Fetched in submodule path 'themes/pln', but it did not contain e8e0dc399b38f6ba01720c65bd64a1bdb9b68755. Direct fetching of that commit failed.
    
  7. 如果 Node.js 的套件在前一台设备上有更新,则意味着 Git 记录了新的 package.json 文件,此时从 submodule 文件夹里切换回 blog 文件夹运行 npm install 更新即可(命令参考上面的代码)


打赏