#!/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 个文件。"