尝试将存储库镜像到远程服务器时,服务器拒绝了树对象4e8f805dd45088219b5662bd3d434eb4c5428ec0。这不是顶级树,而是一个子目录。
我该如何找出间接引用该树对象的提交,以便避免推送链接到这些提交的引用,从而使我的存储库的所有其他内容都能正确推送?
尝试将存储库镜像到远程服务器时,服务器拒绝了树对象4e8f805dd45088219b5662bd3d434eb4c5428ec0。这不是顶级树,而是一个子目录。
我该如何找出间接引用该树对象的提交,以便避免推送链接到这些提交的引用,从而使我的存储库的所有其他内容都能正确推送?
正如你所指出的,你只需要找到具有所需 tree
的提交。如果它可能是顶层树,你需要一个额外的测试,但由于它不是,所以你不需要。
你想要:
这可以通过两个 Git "plumbing" 命令加上 grep
轻松实现。
这是我原始脚本的稍微更新版本(更新为接受参数,并默认为 --all
,就像 badp 的编辑一样):
#! /bin/sh
#
case $# in
0) echo "usage: git-searchfor <object-id> [<starting commit>...]" 1>&2; exit 1;;
esac
searchfor=$(git rev-parse --verify "$1") || exit 1
searchfor=$(git rev-parse --verify "$searchfor"^{tree}) || exit 1
shift
git log ${@-"--all"} --pretty='format:%H' |
while read commithash; do
if git ls-tree -d -r --full-tree $commithash | grep $searchfor; then
echo " -- found at $commithash"
fi
done
git cat-file -p $commithash
命令,并查看其中是否包含该哈希值。git ls-tree
中删除了-d
选项)。但是,树不能具有blob的ID,反之亦然。 grep
将打印匹配的行,因此您将看到例如:040000 tree a3a6276bba360af74985afa8d79cfb4dfc33e337 perl/Git/SVN/Memoize
-- found at 3ab228137f980ff72dbdf5064a877d07bec76df9
git cat-file -t
以获取它的类型。git diff-tree
有一个--find-object
选项。 这是在Git 2.17中引入的(在此问题最初发布之后的2018年)。 git log
命令也有此选项,但我们通常更关心哪个特定提交添加了文件或树。 通过删除试图强制searchfor
哈希ID成为树的额外行,我们可以得到一个更快的脚本,找到任何树或blob对象的每个出现(虽然您必须小心指定正确的哈希ID或自己使用^{tree}
后缀如果您要提供提交哈希ID)。 然后我们只需要运行:git log --all --find-object=$searchfor
git rev-list --all | git diff-tree --stdin --find-object=$searchfor
寻找我们要找的内容。(如果需要,添加${2-"--all"}
。)
git rev-list
接受与 git log
相同的参数。实际上,它们基本上是相同的命令!它们都是从一个源文件构建而来,只是在作为 git log
与 git rev-list
运行时更改默认设置。Rev-list 旨在供脚本使用,而 log 则旨在供人类使用。无论如何,A..B
的意思是 B ^A
,因此 origin/master..master
和 master ^origin/master
在这里完全相同。在这种情况下,您可以使用 git rev-list --branches ^origin/master
(或者也许是 --branches --tags
)。 - torekgit rev-list --all | git diff-tree --stdin --find-object=4e8f805dd45088219b5662bd3d434eb4c5428ec0
命令查找引入该树的所有提交,然后使用 git branch --contains
命令避免推送任何包含该树的提交。 - jthill--find-object
(Git 2.17中新增)现在是最好的选择。我会稍微调整一下答案。 - torek如果您想通过GNU Parallel加速操作,以下是由torek提供的优秀答案变体:
#!/bin/bash
searchfor="$1"
startpoints="${2-HEAD}"
git rev-list "$startpoints" |
parallel "if git ls-tree -d -r --full-tree '{}' | grep '$searchfor'; then echo ' -- found at {}'; fi"
git fsck
,希望它将在恢复的过程中删除对它的所有引用。但我也不知道如何从packfile中删除一个对象。 - Andrew Arnott