Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/git/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Git 我能把一棵树直接读到一个工作目录中去吗_Git - Fatal编程技术网

Git 我能把一棵树直接读到一个工作目录中去吗

Git 我能把一棵树直接读到一个工作目录中去吗,git,Git,我正在探索git的内部结构。我想知道是否有一个GIT命令可以让我不使用index直接将树读入工作树。例如,我创建了一棵树: $ echo 'f1 content' | git hash-object -w --stdin a1deaae8f9ac984a5bfd0e8eecfbafaf4a90a3d0 $ echo 'f2 content' | git hash-object -w --stdin 9b96e21cb748285ebec53daec4afb2bdcb9a360a $ prin

我正在探索git的内部结构。我想知道是否有一个GIT命令可以让我不使用
index
直接将树读入工作树。例如,我创建了一棵树:

$ echo 'f1 content' | git hash-object -w --stdin
a1deaae8f9ac984a5bfd0e8eecfbafaf4a90a3d0

$ echo 'f2 content' | git hash-object -w --stdin
9b96e21cb748285ebec53daec4afb2bdcb9a360a

$ printf '%s %s %s\t%s\n' \
> 100644 blob a1deaae8f9ac984a5bfd0e8eecfbafaf4a90a3d0 f1.txt \
> 100644 blob 9b96e21cb748285ebec53daec4afb2bdcb9a360a f2.txt |
> git mktree
e05d9daa03229f7a7f6456d3d091d0e685e6a9db
现在我想把树
e05d9daa03229f7a7f6456d3d091d0e685e6a9db
和两个文件
f1.txt
f2.txt
直接读到一个工作目录中。我知道我可以使用以下组合:

$ git read-tree e05d9daa03229f7a7f6456d3d091d0e685e6a9db
$ git checkout-index -a
但我想知道是否只有一个命令可以做到这一点。

简短的回答是“否”:所有读取完整树的Git操作都会将其读入索引中

短语a索引,与索引相对,是您的主要逃生舱口,使长答案成为限定的“是”。您可以通过使用一个索引来避免使用索引,如中所示,使用一些替代索引而不是“the”索引。通过将替代索引的路径名放入环境变量
GIT_index_FILE
中,您可以使用另一个索引代替“the”索引。在某些情况下,您可以完全绕过索引,方法是。。。好吧,继续读下去。:-)

我认为,在将文件复制到工作树之前,Git“希望”将一系列树从提交中读入索引有两个主要原因。第一个与解析完整路径名有关:在一个树对象中,在一个Git存储库中,每个存储的子对象子树或blob都有一个模式(对于子树是
40000
),一个散列和一个名称。但是,名称不是对象的完整路径名:它只是名称组件,例如
foo/bar/baz.txt
bar
部分

通过对每个树进行线性提取,在每个子树上递归,Git可以建立一个索引,其中存储在索引中的每个名称都是完整的路径名。也就是说,我们使用以下伪代码开始树提取:

build_index('', top_level_tree_hash)
其中
build\u index
执行此操作(在伪Python中):

递归完成后,索引的缓存特性中包含每个非树对象的所有完整路径名、模式和散列,可以提取

但是,如果没有索引,只需要读取一棵树,就不知道到目前为止的主要路径名组件应该是什么。我们需要上面的递归来维护我们的路径名

Git“想要”读入索引的第二个原因与对表示文件的blob对象进行的行尾和过滤(涂抹和清除过滤器)处理有关。(代表符号链接和gitlinks的Blob对象既不需要EOL hackery也不需要污迹过滤。)Git通常将此处理延迟到文件从索引复制到存储库的时间。此时,Git具有文件的完整路径名(因为它以这种方式存储在index2中)和散列ID。它在工作树和/或索引和/或全局中的相应
.gittributes
文件中查找相应的EOL或筛选。工作树文件(如果存在)将覆盖仅索引的文件,而保存文件的目录的属性文件“更本地”将覆盖目录层次结构中较高的文件,如果Git这样做时将整个索引和工作树都放在适当的位置,这也更容易实现。它可以很容易地找到正确的EOL和filter属性,并在从索引存储的哈希复制到由索引存储的路径名确定的工作树中的位置期间将它们应用到blob内容

所有这些的结果是,为了“简单地”提取文件,Git需要一个索引,在它运行的命令期间,它至少充当索引。但是,如果您有一个特定的文件,其路径名是您事先知道的,并且愿意冒一点EOL/过滤的风险(或者完全放弃它们),那么您可以使用
git cat file-p
git show
来提取blob内容:

git cat-file -p [--textconv | --filters] $commithash:$fullpath
比如说。使用
--textconv
--filters
时,必须提供一个路径,因此如果只有原始哈希,则必须使用:

git cat-file -p $filteropt --path=$path $rawhash
(其中,
$filteropt
是上述
--textconv
--filters
选项之一)

如果您希望内容未经过滤,则上述任何警告都不适用。您应该省略
--textconv
--filters
,现在
git cat file-p
根本不需要路径名。只要找到blob对象,git rev parse就可以接受任何内容,并且:

git cat-file -p $hash > $path
足以提取原始blob内容,并将其写入
$path


1存储库对象的类型由模式暗示,稍后将与基础存储库对象的实际类型匹配。如果忽略符号链接和gitlinks,则只有两种blob/文件模式(
100644
100755
)和一个子树模式(
40000
)。符号链接或gitlink也由blob对象表示,因此,如果模式为
40000
,我们将递归并获取另一个树对象,否则我们将命中一个叶并将哈希(最适合表示blob)写入缓存


2索引中的路径名被压缩,因此这并不完全正确。不过,有几种索引格式,所以它特别复杂。最好将每个索引/缓存项视为表示一个元组。

git checkout-p e05d9daa03229f7a7f6456d3d091d0e685e6a9db
。但它是互动的<代码>是| git checkout-p e05d9daa03229f7a7f6456d3d091d0e685e6a9db,但仍然不是单个命令。另外,索引也更新了。@ElpieKay,谢谢,我会给它一个try@ElpieKay,效果很好,你能把它作为答案贴出来吗?我认为这不是一个合格的答案。让我们拭目以待,看看更多的评论/答案。@ElpieKay,好的)谢谢你详细的回答!(祝你好运)我想知道为什么我在一些与git内部和一些g相关的问题上被否决了
git cat-file -p $hash > $path