gpt4 book ai didi

git - 如何将以编程方式生成的文件列表传递给 `git filter-branch`?

转载 作者:太空狗 更新时间:2023-10-29 14:47:22 26 4
gpt4 key购买 nike

我正在拆分 git 存储库的一部分以创建一个新的存储库,并尝试使用 git filter-branch 来维护正在移动到新项目的文件的历史记录.我知道 --subdirectory-filter 但这不是一个好的解决方案,因为我提取的文件没有完全映射到一个子目录。目前我找到的最好的选择是--index-filter,用法如下:

git filter-branch -f --index-filter 'git read-tree --empty && git reset -q "${GIT_COMMIT}" -- <list of files>' --prune-empty -f

这似乎可行,但我希望能够以编程方式生成要保留的文件列表,以便我可以迭代地优化此列表。我目前正在尝试获取我想保留在另一个文件中的文件列表,并将其附加到代表每次提交要执行的命令的字符串中,如下所示:

tmp=$(cat ~/to_keep.txt) && git filter-branch -f --index-filter 'git read-tree --empty && git reset -q "${GIT_COMMIT}" -- '$tmp --prune-empty -f

不幸的是,这会导致

fatal: bad flag '--prune-empty' used after filename

即使只是回显文件似乎也会造成麻烦:

tmp=$(echo a.txt b.txt) && git filter-branch -f --index-filter 'git read-tree --empty && git reset -q "${GIT_COMMIT}" -- '$tmp --prune-empty -f
fatal: ambiguous argument 'b.txt': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'

我之前也尝试过连接字符串:

tmp1=$(echo a.txt b.txt) && tmp2='git read-tree --empty && git reset -q "${GIT_COMMIT}" -- ' && tmp3=${tmp2}${tmp1} && git filter-branch -f --index-filter $tmp3 --prune-empty -f
fatal: ambiguous argument 'read-tree': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'

我假设这只是串联,并没有像我在 shell 中预期的那样发生。有谁知道我怎样才能使这项工作?如果您也能解释这些错误的含义,那就太好了。谢谢。

最佳答案

各种...-filter的每个参数s 必须是单个字符串。该字符串保存为 shell 变量:

    --index-filter)
filter_index="$OPTARG"
;;

在适当的时候,过滤器分支脚本(位于 git-core 子目录中,例如 /usr/libexec/git-core/usr/local/libexec/git-core)执行以下操作:

    eval "$filter_index" < /dev/null ||
die "index filter failed: $filter_index"

(使用 /bin/sh -c "$filter_commit" ... 运行的提交过滤器除外)。

因此您的假设是正确的,您需要做的是使文件列表成为单个以空格分隔的字符串的一部分。

最简单的方法是从您的原始命令开始:

git filter-branch -f --index-filter \
'git read-tree --empty && git reset -q "${GIT_COMMIT}" -- <list of files>' \
--prune-empty -f

(当您有静态列表时有效)并修改它以从 ~/to_keep.txt 中提取动态列表.我将原件分成三行,部分原因是出于展示目的,但也是因为我们现在可以只关注中间那一行。

[编辑以修复评论中提到的换行问题。让我们创建一个别名或 shell 函数,xc , 将换行符转换为空格]

xc() {
tr '\n' ' '
}

"git read-tree --empty && git reset -q \"\${GIT_COMMIT}\" -- $(xc < ~/to_keep.txt)" \

或:

'git read-tree --empty && git reset -q "${GIT_COMMIT}" -- '"$(xc < ~/to_keep.txt)" \

或者,正如您尝试的那样(但有一个变化):

'git read-tree --empty && git reset -q "${GIT_COMMIT}" -- '"$tmp" \

(已设置 tmp=$(xc < ~/to_keep.txt) )。

请注意,如果任何文件名包含空格,则这些都无法纠正。例如,假设一个文件名为 a file (嵌入空白)。 eval将在空格处打断参数,git reset命令将获取名称 afile作为两个单独的参数。

只要您没有任何此类文件名,就无需担心解决这个问题。

另一个潜在的问题是如果这个文件列表变得很长。您可能会遇到内核对可以发送到一个文件的参数数量的限制。您应该可以使用 xargs解决这个问题(并且,就此而言,通过一些工作和使用 -0 来处理文件名中的空白)。

关于git - 如何将以编程方式生成的文件列表传递给 `git filter-branch`?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19507282/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com