2

我在化石结帐中有一个包含多级子目录的目录,我想将其移动到不同子目录中的另一个位置并保留多级目录结构。

例如,将 a1 移动到下面的 a2 中,从具有(手写,类似于缩写的 find 命令输出):

a1/
a1/b/
a1/b/files
a1/c/
a1/c/d/
a1/c/d/more-files
a2/

我想fossil mv --hard a1 a2导致:

a2/a1/
a2/a1/b/
a2/a1/b/files
a2/a1/c/
a2/a1/c/d/
a2/a1/c/d/more-files

就像正常的 unixmv命令一样。理想情况下,保留 mv 的历史记录,这样它就可以合并到另一个分支中,对文件和更多文件的任何更改都完好无损;因为我可以删除文件然后将它们重新添加为新文件,但这是一个比我想要的更丑陋的解决方案。

fossil mv命令(在 Linux 上的 v1.33 中)丢失了多个级别,我最终将来自较低级别子目录的所有文件移动到新位置的顶级目录中。

4

2 回答 2

1

我认为有一个更简单的解决方案(这是在 Windows 下,但对于 Linux 类似)

md a2\a1
fossil mv a1 a2/a1 --hard
于 2016-01-19T15:15:06.850 回答
1

一种解决方案是编写一个脚本来单独移动每个目录,一次移动一个级别,因此它保留了结构。我想向化石开发者推荐这个功能。我可能会在某个时候将脚本(下面,其中包含另一个依赖脚本)发布到我的 github(用户 jgbreezer),但现在,这个脚本(我称之为化石mvtree)。它会忽略结帐中的文件而不是化石,并将旧文件/目录留在有的地方(我不相信它会删除它们):

#!/bin/bash
# $1=source tree
# $2=dest. dir
# supports fossil mv options
# moves single source tree as-is to under/new dest.dir (not reducing dir levels to flat structure under dest dir)
exclude=''

usage () {
    cat >&2 <<EOF
Usage: fossilmvtree [-x|--exclude= exclude_dirname] source dest"
-x option may be specified multiple times; do not specify full paths, just last
(filename/aka basename) of a directory to exclude from the move.
Command-line arguments are always included.
EOF
}

while [ -z "${1##-*}" ]
do
    case "$1" in
    -x|--exclude|--exclude=*)
        if [[ "${1#--exclude=}" == "$1" ]]
        then
            # separate arg, '--exclude=' not used
            shift
            arg="$1"
        else
            arg="${1#--exclude=}"
        fi
        excinfo="$excinfo $arg"
        # pruning is efficient
        exclude="$exclude -type d -name '${arg//\'/\\\'}' -prune -o"
        ;;
    --case-sensitive)
        fossilopts="$fossilopts $1 $2"; shift;;
    -*)
        fossilopts="$fossilopts $1";;
    esac
    shift
done
echo "excluding paths: $excinfo"
echo "fossil mv options: $fossilopts"

[ $# -eq 2 ] || { usage; exit 1; }
mv="$(which fossilmvrev 2>/dev/null)" || { usage; echo "error:Missing fossilmvrev" >&2; exit 1; }
src="$1"
srcdir="$(basename "$src")"
dst="$2"
if [ -f "$dst" ]
then
    # move src to new subdir of dst; otherwise we're renaming and moving
    [ -d "$dst" ] || { echo "error:Destination '$dst' exists but is not a directory" >&2; exit 1; }
    dst="$dst/$srcdir"
fi
#could set safe PATH (-execdir is cautious of relative/empty paths in $PATH but fossil binary might not be in std.location): PATH=/bin:/usr/bin:/usr/local/bin
eval find "$src" $exclude -type d -printf '%P\\n' | { 
    while read -r dir
    do
        [ -z "$dir" ] || [[ "$src/$dir" == "$dst/$dir" ]] && continue
        echo
        echo "fossil mv $src/$dir/* $dst/$dir/"
        mkdir -p "$dst/$dir" || exit 1
        find "$src/$dir" -maxdepth 1 \! -type d -exec "$mv" $fossilopts "$dst/$dir" '{}' +
        rmdir "$src/$dir" # tidy up, as we only moved the files above (fossil doesn't really manage dirs)
        # if rmdir fails due to remaining files, let user manage that (rmdir will complain to stderr if so) -
        # likely to be unversioned files they might have forgotten about, shouldn't delete without user's knowledge.
    done
}

它只在我的特定化石结账中真正测试过一次或两次,尽管它已准备好成为可重复使用的脚本;请检查差异(建议在其他地方进行干净的检查并在其上运行它,然后使用“diff -qr”或其他东西与您的常规检查进行比较,然后再承诺检查它的行为)。

如果使用 -x/exclude 选项要小心,我不确定它是否正常工作。

这取决于化石mvrev 脚本:

#!/bin/sh
# switch order of move arguments around to work with find -exec ... +
opts=''
while [ -z "${1##-*}" ]
do
    case "$1" in
    --case-sensitive) opts="$opts $1 $2"; shift 2;;
    *) opts="$opts $1"; shift;;
    esac
done
destdir="$1"
shift
fossil mv $opts "$@" $destdir
于 2015-10-14T16:03:14.907 回答