在 BASH 如何递归地只复制由 Git 控制版本的内容?

In BASH How Can One Recursively Copy Only Content Version-Controlled by Git?

有没有办法在 bash 终端批量递归复制(cp -rf 等效)从一个子目录到另一个子目录,保留目录结构但仅复制 files/directories 是版本控制的通过 git?

天真的策略是...

cp -rf <targetDir> variantDir/; git add variantDir;

...但这会拾取一堆文件,这些文件是 IDE 删除的数据文件,等等。我正在处理的文件目前在 [= 中不受版本控制17=].


作为背景,我有以下目录结构:

${baseDir}/
${baseDir}/variantA

基本上,${baseDir}/ 包含所有原始版本控制的内容,${baseDir}/variantA 包含针对目标变体的不同内容。对于原始目标文件夹 ${baseDir}/variantA 将被忽略。对于第二个目标,文件夹 variantA 被包含在内,有效地取代了除路径的 variantA 部分以外的任何匹配内容。

即如果我有:

${baseDir}/someFolder/someStuff.cpp
${baseDir}/variantA/someFolder/someStuff.cpp

它将为第二个目标使用第二条路径,为第一个目标使用第一条路径。

现在我要添加 variantB,它是一个完整的变体(不像 variantA 有一些落入基本目标的文件)。它更接近 variantA 所以我想先复制基本文件夹中的所有内容,然后将 variantA 子文件夹中的所有内容复制到 variantB 子文件夹中......这样我就有了一个新的将所有内容(包括失败内容)复制到版本提交,并优先选择 variantA 文件版本,当存在此类重叠时。

我会使用上面的天真片段,但我有一个更根本的问题,我的 IDE 已经丢弃 *.xml 文件和其他垃圾 git 在某种程度上足够聪明来标记因为不是未提交的内容(可能是特定于语言的),但 cp 会忽略。我相信 git 会在明确要求的情况下复制这些文件,因此,我想排除所有非 git 控制的内容,同时使用之前所述的一般策略。

仅将源代码管理下的文件从变体 A 复制到变体 B:

cd variantA
rsync --files-from <(git ls-files .) . ../variantB

这通过仅包含由 git ls-files 返回的文件来实现。

编辑:<() 语法称为 process substitution

如果你有 GNU cp,你可以使用 --parents 选项:

mkdir variantB
cd variantA
cp --parents $(git ls-files .) ../variantB
git ls-files | tar Tc - | tar Cx /path/to/destination

这会获取您在工作树中当前位置的内容。要使用提交的子目录,请使用 git archive 解决方案

git archive master:path/to/subdir | tar Cx /path/to/destination

要处理您当前添加但未提交的内容,您可以将 $(git write-tree) 替换为上面的 master

为什么不创建一个新的工作树(显然其中只有源代码控制的文件,因为它是从源代码管理生成的)?

有几种方法可以做到这一点(使用克隆或工作树),但我认为

git worktree add -b variantB path/where/variantB/will/be/created master 

会让您开始使用相关文件(受源代码控制的文件)。然后你只需将 path/where/variant/B/will/be/created/variantA 复制到 path/where/variant/B/will/be/created

并且由于 -b 选项,您已经在一个新的分支上 - 这就是您可能希望保留此变体的方式,因为它是一个完整的替代品。 (对于 varientA,这是值得商榷的,因为您希望 variantA 与它不变的文件的基线更改保持同步...)

但是如果你不想为此维护一个新的分支,没什么大不了的。使用克隆或工作树添加命令(不带 -b)创建上述 variantB 的工作树图像,然后将生成的文件移动到 .../variantB 目录下的默认工作树中