跳转至

用脚本打造更安全的 Git 工作流

在日常使用 Git 管理知识库或代码仓库时,大多数人都会使用类似下面的三连命令:

git add .
git commit -m "update"
git push

或者在开始工作前执行:

git pull

这种方式虽然简单,但实际上存在不少隐患。例如:

  • 本地工作区有未提交修改时直接 pull

  • 远程仓库已经更新,但本地没有同步就直接 push

  • 本地和远程分支已经分叉(diverged)却继续操作

  • 未跟踪文件在 pull 时导致目录混乱

  • 自动生成的文件被误提交

这些问题在 多设备同步(电脑 + 手机)、Obsidian 知识库、个人博客仓库 这种场景下尤其容易出现。

为了让 Git 工作流更安全、更可控,可以将常用操作封装成脚本,在执行 pullpush 时自动进行检查。

本文介绍两个简单但非常实用的脚本:

  • vaultpullsafe:安全拉取

  • vaultpushsafe:安全推送

它们能够在执行操作前自动检查仓库状态,从而避免很多常见问题。


一、安全拉取脚本

安全拉取脚本的目标是:
只有在仓库状态安全的情况下才允许执行 pull。

主要检查内容包括:

  1. 当前目录是否为 Git 仓库

  2. 工作区是否干净

  3. 是否存在未跟踪文件

  4. 本地和远程分支关系

  5. 是否存在分叉

脚本如下:

#!/bin/bash

set -e

echo "==> 检查当前目录是否为 Git 仓库"
git rev-parse --is-inside-work-tree >/dev/null 2>&1 || {
  echo "错误:当前目录不是 Git 仓库"
  exit 1
}

echo "==> 当前分支:$(git branch --show-current)"

echo "==> 检查工作区是否干净"
if ! git diff --quiet || ! git diff --cached --quiet; then
  echo "错误:当前工作区有未提交修改,请先提交或清理后再拉取"
  git status --short
  exit 1
fi

if [ -n "$(git ls-files --others --exclude-standard)" ]; then
  echo "错误:存在未跟踪文件,为避免 pull 时混乱,已停止"
  git status --short
  exit 1
fi

echo "==> 获取远程最新信息"
git fetch origin

BRANCH=$(git branch --show-current)

LOCAL=$(git rev-parse @)
REMOTE=$(git rev-parse "origin/$BRANCH")
BASE=$(git merge-base @ "origin/$BRANCH")

if [ "$LOCAL" = "$REMOTE" ]; then
  echo "==> 本地与远程一致,无需拉取"
  exit 0
fi

if [ "$LOCAL" = "$BASE" ]; then
  echo "==> 远程有更新,开始执行 git pull --rebase"
  git pull --rebase origin "$BRANCH"
  echo "==> 拉取完成"
  git status
  exit 0
fi

if [ "$REMOTE" = "$BASE" ]; then
  echo "==> 本地领先远程,没有必要 pull"
  git status
  exit 0
fi

echo "错误:本地与远程已分叉(diverged),不能自动安全拉取"
echo "请手动检查:"
echo "  git status"
echo "  git log --oneline --graph --decorate --all -20"
exit 1

二、安全推送脚本

安全推送脚本的目标是:

只有在远程状态安全、且本地确实存在改动时才执行 push。

主要检查逻辑:

  1. 当前目录是否为 Git 仓库

  2. 是否存在需要提交的改动

  3. 远程是否领先本地

  4. 本地与远程是否分叉

  5. 提交后远程是否发生变化

脚本如下:

#!/bin/bash

set -e

MSG="$1"

if [ -z "$MSG" ]; then
  MSG="update $(date '+%Y-%m-%d %H:%M:%S')"
fi

echo "==> 检查当前目录是否为 Git 仓库"
git rev-parse --is-inside-work-tree >/dev/null 2>&1 || {
  echo "错误:当前目录不是 Git 仓库"
  exit 1
}

BRANCH=$(git branch --show-current)
echo "==> 当前分支:$BRANCH"

echo "==> 检查是否存在改动"
if git diff --quiet && git diff --cached --quiet && [ -z "$(git ls-files --others --exclude-standard)" ]; then
  echo "==> 没有可提交的改动,停止操作"
  exit 0
fi

echo "==> 先获取远程最新信息"
git fetch origin

LOCAL=$(git rev-parse @)
REMOTE=$(git rev-parse "origin/$BRANCH")
BASE=$(git merge-base @ "origin/$BRANCH")

if [ "$LOCAL" = "$BASE" ] && [ "$REMOTE" != "$BASE" ]; then
  echo "错误:远程领先本地,请先执行安全拉取"
  echo "建议运行:vaultpullsafe"
  exit 1
fi

if [ "$LOCAL" != "$BASE" ] && [ "$REMOTE" != "$BASE" ] && [ "$LOCAL" != "$REMOTE" ]; then
  echo "错误:本地与远程已分叉,不能直接推送"
  echo "请先手动检查:"
  echo "  git status"
  echo "  git log --oneline --graph --decorate --all -20"
  exit 1
fi

echo "==> 查看当前变更概况"
git status --short

echo "==> 加入暂存区"
git add .

echo "==> 创建提交"
git commit -m "$MSG"

echo "==> 再次检查远程状态"
git fetch origin

LOCAL=$(git rev-parse @)
REMOTE=$(git rev-parse "origin/$BRANCH")
BASE=$(git merge-base @ "origin/$BRANCH")

if [ "$REMOTE" != "$BASE" ] && [ "$LOCAL" != "$REMOTE" ]; then
  echo "错误:提交后发现远程又更新了,已停止 push"
  echo "请先运行:vaultpullsafe"
  exit 1
fi

echo "==> 推送到远程"
git push origin "$BRANCH"

echo "==> 推送完成"
git status

三、脚本的核心原理

这两个脚本的关键在于判断 本地与远程的关系

主要通过三个变量:

LOCAL=$(git rev-parse @)
REMOTE=$(git rev-parse "origin/$BRANCH")
BASE=$(git merge-base @ "origin/$BRANCH")

含义分别是:

  • LOCAL:本地当前提交

  • REMOTE:远程分支提交

  • BASE:两者的共同祖先

根据三者关系可以判断:

状态 含义
LOCAL = REMOTE 本地与远程一致
LOCAL = BASE 本地落后远程
REMOTE = BASE 本地领先远程
三者都不同 本地与远程已分叉

这样脚本就可以决定是否允许继续操作。


四、如何使用

假设脚本命名为:

vaultpullsafe
vaultpushsafe

日常工作流程就变成:

开始工作前:

vaultpullsafe

完成编辑后:

vaultpushsafe "更新知识库"

如果不写提交信息,脚本会自动生成:

update YYYY-MM-DD HH:MM:SS

五、这种方式的优势

相比传统 Git 操作,这种方式具有明显优势:

1 自动安全检查

避免在以下情况误操作:

  • 本地有未提交修改

  • 远程已经更新

  • 分支已经分叉

2 减少冲突

脚本默认使用:

git pull --rebase

可以减少不必要的 merge commit。

3 操作更简单

日常只需要两个命令:

vaultpullsafe
vaultpushsafe

4 非常适合知识库仓库

例如:

  • Obsidian 笔记

  • 博客仓库

  • 多设备同步仓库


六、总结

Git 本身是一个非常强大的版本控制工具,但默认命令往往对新手不够友好。

通过简单的脚本封装,可以实现:

  • 自动检查仓库状态

  • 自动判断分支关系

  • 自动阻止危险操作

  • 自动化常见工作流程

最终让 Git 的使用更加稳定、可控。

在日常使用中,你只需要记住两个命令:

vaultpullsafe
vaultpushsafe

就可以完成一整套安全的 Git 同步流程。