更新Hexo主题升级的正确打开方式

对Hexo的主题进行升级,最头疼的莫过于配置文件(_config.yml)的处理。我们自己需要对它进行自定义配置,但是主题升级更新后它的内容也可能会有所改变,二者可能产生冲突。如果只是在升级后简单把旧的配置文件复制过去,当然是不合理的。

所以,正确的打开方式因该是:利用git的分支与合并功能,自动检查冲突或者快速合并。

1. 关键git命令解释

git checkout [-b <new_branch>] <branch>
  • 不带-b,切换到已有的分支<branch>
  • -b参数,以<branch>为起始点,新建分支<new_branch>并切换到新分支,其中<branch>缺省时采用当前分支为起始
git merge [--squash] <branch>
  • 不带--squash,将分支<branch>合并到到当前分支
  • --squash参数,同上,但是只是将<branch>中的修改内容迁移过来,而不保留其中的commit历史,也就是说,结果是一样的,但是不保留中间过程。

2. 开始使用

首先使用git clone下载主题到本地,此时只有一个默认的master分支,示意如下:

(红圆代表主题发布者的commit,绿圆表示你的commit;末端方框表示分支指针,星号标识活动分支)

graph LR
c-m1(( ))-->c-m2(( ))
c-m2(( ))-->c-m3(( ))
c-m3---m(* master)
style c-m1 fill:red,stroke:none;
style c-m2 fill:red,stroke:none;
style c-m3 fill:red,stroke:none;

但是,先不要着急进行自定义配置,先切换到一个新分支blog再说:

git checkout -b blog
graph LR
c-m1(( ))-->c-m2(( ))
c-m2(( ))-->c-m3(( ))
c-m3---m(master)
c-m3---b(* blog)
style c-m1 fill:red,stroke:none;
style c-m2 fill:red,stroke:none;
style c-m3 fill:red,stroke:none;

然后再进行配置编辑,完成后提交commit(可以多次commit):

graph LR
c-m1(( ))-->c-m2(( ))
c-m2(( ))-->c-m3(( ))
c-m3---m(master)
c-m3-->c-b1(( ))
c-b1---b(* blog)
style c-m1 fill:red,stroke:none;
style c-m2 fill:red,stroke:none;
style c-m3 fill:red,stroke:none;
style c-b1 fill:green,stroke:none;

如果之前你已经在master分支上做过了修改,那么也是有办法解决的。

只需要保存当前修改到新分支,并将master分支还原即可。

git add -A
git commit -m configed
git checkout -b blog
git checkout master
git reset --hard <commit> # 自行选择,只要是回到修改前和远程一致的版本就行

3. 升级

将远程的master分支更新拉取到本地master分支:

git checkout master
git pull origin master
git checkout blog

或者用下面的一条命令简化版,效果一样:

git fetch origin master:master
graph LR
c-m1(( ))-->c-m2(( ))
c-m2(( ))-->c-m3(( ))
c-m3(( ))-->c-m4(( ))
c-m4(( ))-->c-m5(( ))
c-m5---m(master)
c-m3-->c-b1(( ))
c-b1---b(* blog)
style c-m1 fill:red,stroke:none;
style c-m2 fill:red,stroke:none;
style c-m3 fill:red,stroke:none;
style c-m4 fill:red,stroke:none;
style c-m5 fill:red,stroke:none;
style c-b1 fill:green,stroke:none;

然后,在master基础上开一个新的分支

git checkout -b updated-blog master
graph LR
c-m1(( ))-->c-m2(( ))
c-m2(( ))-->c-m3(( ))
c-m3(( ))-->c-m4(( ))
c-m4(( ))-->c-m5(( ))
c-m5---m(master)
c-m3-->c-b1(( ))
c-b1---b(blog)
c-m5---ub(* updated-blog)
style c-m1 fill:red,stroke:none;
style c-m2 fill:red,stroke:none;
style c-m3 fill:red,stroke:none;
style c-m4 fill:red,stroke:none;
style c-m5 fill:red,stroke:none;
style c-b1 fill:green,stroke:none;

此时分支updated-blog具有远程更新的内容,但是没有自定义的配置,因此需要进行分支合并:

git merge blog

不少情况下merge可以全自动完成,但是也有的情况下会有合并冲突!例如主题开发者更新了某个_config.yml配置,而你也恰好编辑了其中内容,因此这时候需要先手动处理冲突。具体方法参见下一节。

合并完成后提交commit确认合并,此时updated-blog分支同时具有了更新和自定义配置。

graph LR
c-m1(( ))-->c-m2(( ))
c-m2(( ))-->c-m3(( ))
c-m3(( ))-->c-m4(( ))
c-m4(( ))-->c-m5(( ))
c-m5---m(master)
c-m5-->c-merge1(( ))
c-m3-->c-b1(( ))
c-b1---b(blog)
c-b1-->c-merge1
c-merge1---ub(* updated-blog)
style c-m1 fill:red,stroke:none;
style c-m2 fill:red,stroke:none;
style c-m3 fill:red,stroke:none;
style c-m4 fill:red,stroke:none;
style c-m5 fill:red,stroke:none;
style c-b1 fill:green,stroke:none;
style c-merge1 fill:green,stroke:none;

如果git merge时带了--sqush参数,那么结果还是一致的,不过不会保留来自blog分支的commit历史:

graph LR
c-m1(( ))-->c-m2(( ))
c-m2(( ))-->c-m3(( ))
c-m3(( ))-->c-m4(( ))
c-m4(( ))-->c-m5(( ))
c-m5---m(master)
c-m5-->c-merge1(( ))
c-m3-->c-b1(( ))
c-b1---b(blog)
c-merge1---ub(* updated-blog)
style c-m1 fill:red,stroke:none;
style c-m2 fill:red,stroke:none;
style c-m3 fill:red,stroke:none;
style c-m4 fill:red,stroke:none;
style c-m5 fill:red,stroke:none;
style c-b1 fill:green,stroke:none;
style c-merge1 fill:green,stroke:none;

如果有需要,可以删除旧分支blog

git branch -D blog

普通merge:

graph LR
c-m1(( ))-->c-m2(( ))
c-m2(( ))-->c-m3(( ))
c-m3(( ))-->c-m4(( ))
c-m4(( ))-->c-m5(( ))
c-m5---m(master)
c-m5-->c-merge1(( ))
c-m3-->c-b1(( ))
c-b1-->c-merge1
c-merge1---ub(* updated-blog)
style c-m1 fill:red,stroke:none;
style c-m2 fill:red,stroke:none;
style c-m3 fill:red,stroke:none;
style c-m4 fill:red,stroke:none;
style c-m5 fill:red,stroke:none;
style c-b1 fill:green,stroke:none;
style c-merge1 fill:green,stroke:none;

--squashmerge:

graph LR
c-m1(( ))-->c-m2(( ))
c-m2(( ))-->c-m3(( ))
c-m3(( ))-->c-m4(( ))
c-m4(( ))-->c-m5(( ))
c-m5---m(master)
c-m5-->c-merge1(( ))
c-merge1---ub(* updated-blog)
style c-m1 fill:red,stroke:none;
style c-m2 fill:red,stroke:none;
style c-m3 fill:red,stroke:none;
style c-m4 fill:red,stroke:none;
style c-m5 fill:red,stroke:none;
style c-merge1 fill:green,stroke:none;

观察上图,尤其是--squash合并的情况,可以看到整个git commit的图形状回到了升级之前的状态,不同的是拉取了更新并向前推进了。

如果有强迫症,可以将updated-blog分支重命名一下:

git branch -m updated-blog blog

4. 合并冲突处理

观察git merge时的输出,或者用git status命令查看一下,可以知道哪些文件中具有合并冲突,其中会将发生冲突的部分框起来,大致如下:

<<<<<<< HEAD
# 当且分支的内容
=======
# 从被合并分支迁移过来的内容
>>>>>>> blog

手动将框起来的部分斟酌修改即可。