本文目录导读:

可以的,用脚本实现简易版本控制完全可行,而且是一个非常有趣且实用的学习项目。
对于个人项目或小型文件管理,有时并不需要 Git 那样完整的功能,一个轻量脚本往往更直接、更容易理解。
核心设计思路
简易版本控制本质上是保存文件在不同时间点的快照,基于这个思路,我们可以采用两种不同的策略。
快照备份(简单直观)
文件当前状态 → 复制到版本目录 → 生成带时间戳的副本
差异备份(节约空间)
保存当前文件与上次版本的差异 → 记录变更记录
这里我推荐策略一,因为它更简单、可靠,且易于实现和恢复。
核心功能模块
一个基础的版本控制系统至少需要4个操作:
| 功能 | 说明 |
|---|---|
init |
初始化版本仓库 |
save |
保存当前版本快照 |
list |
列出所有版本 |
restore |
恢复到指定版本 |
Bash 脚本实现
下面给出一份完整可用的 Bash 脚本,它实现了上述功能,并且每一步都有详细注释。
#!/usr/bin/env bash
### 文件名:version.sh
### 用法:./version.sh [init|save|list|restore]
set -euo pipefail
# 配置
VERSION_DIR=".myversions" # 版本存储目录
FILES_TO_TRACK=("note.txt") # 监控的文件列表,可按需扩展
MAX_VERSIONS=10 # 保留的最大版本数
# 颜色输出(便于阅读)
GREEN='\033[0;32m'; RED='\033[0;31m'
YELLOW='\033[1;33m'; NC='\033[0m'
version_init() {
# 创建版本目录结构
mkdir -p "$VERSION_DIR/logs"
echo "✅ 已初始化版本仓库: $VERSION_DIR/"
}
version_save() {
# 检查文件是否存在
for file in "${FILES_TO_TRACK[@]}"; do
if [ ! -f "$file" ]; then
echo -e "${RED}❌ 文件 $file 不存在,跳过${NC}"
continue
fi
# 生成唯一版本号(时间戳+随机数)
TIMESTAMP=$(date +%Y%m%d%H%M%S)
RANDOM_SUFFIX=$RANDOM
VERSION_FILE="$VERSION_DIR/${file}_${TIMESTAMP}_${RANDOM_SUFFIX}"
# 复制当前版本
cp "$file" "$VERSION_FILE"
# 记录版本信息
echo "$TIMESTAMP $(md5sum "$file")" >> "$VERSION_DIR/logs/${file}.log"
echo -e "${GREEN}✅ 已保存版本: ${file}_${TIMESTAMP}${NC}"
# 自动清理旧版本(超过MAX_VERSIONS)
clean_old_versions "$file"
done
}
version_list() {
echo -e "${YELLOW}📋 版本列表:${NC}"
for file in "${FILES_TO_TRACK[@]}"; do
echo -e "\n${YELLOW}文件: $file${NC}"
# 匹配该文件的版本
if compgen -G "$VERSION_DIR/${file}_*" > /dev/null; then
for version in "$VERSION_DIR/${file}_"*; do
# 提取时间戳
TIMESTAMP=$(echo "$version" | grep -o '[0-9]\{14\}')
echo " 📌 $TIMESTAMP"
done
else
echo " (暂无版本)"
fi
done
}
version_restore() {
if [ $# -lt 2 ]; then
echo -e "${RED}❌ 用法: restore <文件名> <时间戳>${NC}"
return 1
fi
FILE=$1
TIMESTAMP=$2
# 查找匹配的版本文件
VERSION_FILE=$(ls "$VERSION_DIR/${FILE}_${TIMESTAMP}_"* 2>/dev/null | head -1)
if [ -f "$VERSION_FILE" ]; then
cp "$VERSION_FILE" "$FILE"
echo -e "${GREEN}✅ 已恢复到 $TIMESTAMP 版本${NC}"
else
echo -e "${RED}❌ 找不到版本 $TIMESTAMP${NC}"
fi
}
clean_old_versions() {
FILE=$1
# 统计该文件的版本数量(排除日志)
COUNT=$(ls "$VERSION_DIR/${FILE}_"* 2>/dev/null | wc -l)
if [ "$COUNT" -gt "$MAX_VERSIONS" ]; then
# 按时间排序,删除最旧的
TO_DELETE=$((COUNT - MAX_VERSIONS))
ls -t "$VERSION_DIR/${FILE}_"* | tail -n "$TO_DELETE" | xargs rm -f
echo -e "${YELLOW}🧹 已清理 $TO_DELETE 个旧版本${NC}"
fi
}
# 主逻辑
case "${1:-}" in
init)
version_init
;;
save)
version_save
;;
list)
version_list
;;
restore)
# 支持两种调用方式:restore [文件] [时间戳] 或 直接交互
if [ $# -eq 3 ]; then
version_restore "$2" "$3"
else
# 交互式恢复
version_list
echo -e "\n请输入要恢复的文件名:"
read -r RESTORE_FILE
echo "请输入时间戳:"
read -r RESTORE_TIME
version_restore "$RESTORE_FILE" "$RESTORE_TIME"
fi
;;
*)
echo -e "${YELLOW}简易版本控制脚本 v1.0${NC}"
echo -e "用法: $0 {init|save|list|restore}"
echo ""
echo " init — 初始化版本仓库"
echo " save — 保存当前文件快照"
echo " list — 查看所有版本"
echo " restore — 恢复指定版本"
exit 1
;;
esac
使用示例
# 1. 初始化 ./version.sh init # 2. 修改文件后保存版本 ./version.sh save # 3. 查看所有版本 ./version.sh list # 4. 恢复到指定时间戳的版本 ./version.sh restore note.txt 20250101120000
进阶优化建议
如果你想要更完善的功能,可以考虑以下方向:
| 增强方向 | 实现思路 |
|---|---|
| 中文兼容 | 使用 while IFS= read -r line 处理含空格文件名 |
| 分支支持 | 增加分支目录隔离 |
| 版本对比 | 使用 diff 实现差异查看 |
| 加密存储 | 使用 openssl 加密版本文件 |
| 远程备份 | 增加 rsync 到远程服务器 |
| 跨平台支持 | 改用 Python 增强兼容性 |
注意事项
- 备份策略:即使有版本控制,也建议定期异地备份
- 性能优化:对超大文件,Python 可能比 Bash 更适合
- 安全考量:敏感文件应加密存储
- 扩展性:如果需求变复杂,建议转向 Python/Node.js 实现
Python 版本(更灵活)
如果觉得 Bash 不够灵活,这里也提供一个更简洁的 Python 版本思路:
import os, shutil, hashlib, json
from datetime import datetime
class MiniGit:
def __init__(self, repo_dir=".minigit"):
self.repo_dir = repo_dir
self.versions_dir = os.path.join(repo_dir, "versions")
self.logs_file = os.path.join(repo_dir, "logs.json")
def init(self):
os.makedirs(self.versions_dir, exist_ok=True)
if not os.path.exists(self.logs_file):
with open(self.logs_file, 'w') as f:
json.dump([], f)
def save(self, filepath):
if not os.path.exists(filepath):
raise FileNotFoundError(filepath)
content = open(filepath, 'rb').read()
hash_val = hashlib.md5(content).hexdigest()
timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
# 保存版本文件
filename = os.path.basename(filepath)
snapshot = f"{filename}_{timestamp}_{hash_val[:8]}.snap"
with open(os.path.join(self.versions_dir, snapshot), 'wb') as f:
f.write(content)
# 记录日志
with open(self.logs_file) as f:
logs = json.load(f)
logs.append({
"file": filepath,
"timestamp": timestamp,
"hash": hash_val,
"snapshot": snapshot
})
with open(self.logs_file, 'w') as f:
json.dump(logs, f, indent=2)
用脚本实现简易版本控制绝可行,而且是一个很好的学习实践,它不仅解决了实际问题(文件备份),还能帮你深入理解 Git 等现代版本控制工具的核心原理,为将来使用真正的 VCS 打下坚实基础。