99 lines
2.9 KiB
Bash
Executable File
99 lines
2.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# 将 SOURCE_DIR 中未提交的变更(修改/新增/删除)以 cp/rm 的方式同步到 TARGET_DIR。
|
||
# 两个目录是同一份项目源码的独立 git 仓库副本,只做文件级复制/删除,不做任何内容编辑。
|
||
set -euo pipefail
|
||
|
||
SOURCE_DIR="${1:-$(pwd)}"
|
||
SOURCE_DIR="$(cd "$SOURCE_DIR" && pwd)"
|
||
TARGET_DIR="${2:-$(dirname "$SOURCE_DIR")/air-cargo}"
|
||
MODE="${3:-preview}" # preview | apply
|
||
|
||
if [ ! -d "$SOURCE_DIR/.git" ]; then
|
||
echo "错误:$SOURCE_DIR 不是一个 git 仓库根目录" >&2
|
||
exit 1
|
||
fi
|
||
if [ ! -d "$TARGET_DIR" ]; then
|
||
echo "错误:目标目录不存在:$TARGET_DIR" >&2
|
||
exit 1
|
||
fi
|
||
|
||
# 只同步工程项目本身的文件,Claude Code 相关的配置/记忆文件(CLAUDE.md、.claude/ 目录,
|
||
# 包括其中的 skills/commands 等)两个仓库各自独立维护,不参与同步。
|
||
is_excluded() {
|
||
local path="$1"
|
||
case "$path" in
|
||
.claude/*|.claude) return 0 ;;
|
||
CLAUDE.md|*/CLAUDE.md) return 0 ;;
|
||
esac
|
||
return 1
|
||
}
|
||
|
||
# --no-renames:把 rename 拆成"删除旧路径 + 新增新路径"两条记录,避免解析组合格式
|
||
# --untracked-files=all:新增的整个目录也会逐个文件列出,而不是折叠成一行目录
|
||
# -z:以 NUL 分隔,规避文件名转义/含空格的问题
|
||
copy_list=()
|
||
delete_list=()
|
||
excluded_list=()
|
||
|
||
while IFS= read -r -d '' entry; do
|
||
status="${entry:0:2}"
|
||
path="${entry:3}"
|
||
[ -z "$path" ] && continue
|
||
if is_excluded "$path"; then
|
||
excluded_list+=("$status|$path")
|
||
continue
|
||
fi
|
||
if [ -e "$SOURCE_DIR/$path" ]; then
|
||
copy_list+=("$status|$path")
|
||
else
|
||
delete_list+=("$status|$path")
|
||
fi
|
||
done < <(git -C "$SOURCE_DIR" status --porcelain=v1 -z --no-renames --untracked-files=all)
|
||
|
||
echo "源目录: $SOURCE_DIR"
|
||
echo "目标目录: $TARGET_DIR"
|
||
echo ""
|
||
echo "=== 待复制/覆盖(${#copy_list[@]})==="
|
||
for item in "${copy_list[@]+"${copy_list[@]}"}"; do
|
||
echo " [${item%%|*}] ${item#*|}"
|
||
done
|
||
|
||
echo ""
|
||
echo "=== 待删除(${#delete_list[@]})==="
|
||
for item in "${delete_list[@]+"${delete_list[@]}"}"; do
|
||
echo " [${item%%|*}] ${item#*|}"
|
||
done
|
||
|
||
echo ""
|
||
echo "=== 已忽略,不参与同步(${#excluded_list[@]})==="
|
||
for item in "${excluded_list[@]+"${excluded_list[@]}"}"; do
|
||
echo " [${item%%|*}] ${item#*|}"
|
||
done
|
||
|
||
if [ "$MODE" != "apply" ]; then
|
||
echo ""
|
||
echo "(预览模式,未执行任何操作。确认无误后加 apply 参数执行同步)"
|
||
exit 0
|
||
fi
|
||
|
||
copied=0
|
||
deleted=0
|
||
|
||
for item in "${copy_list[@]+"${copy_list[@]}"}"; do
|
||
path="${item#*|}"
|
||
mkdir -p "$(dirname "$TARGET_DIR/$path")"
|
||
cp -f "$SOURCE_DIR/$path" "$TARGET_DIR/$path"
|
||
copied=$((copied+1))
|
||
done
|
||
|
||
for item in "${delete_list[@]+"${delete_list[@]}"}"; do
|
||
path="${item#*|}"
|
||
if [ -e "$TARGET_DIR/$path" ]; then
|
||
rm -f "$TARGET_DIR/$path"
|
||
deleted=$((deleted+1))
|
||
fi
|
||
done
|
||
|
||
echo ""
|
||
echo "同步完成:复制/更新 $copied 个文件,删除 $deleted 个文件。"
|