我可以直接将树读入索引的工作目录

时间:2017-08-21 06:54:47

标签: git

我正在探索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

现在,我想将具有两个文件e05d9daa03229f7a7f6456d3d091d0e685e6a9dbf1.txt的树f2.txt直接读入工作目录。我知道我可以使用以下组合:

$ git read-tree e05d9daa03229f7a7f6456d3d091d0e685e6a9db
$ git checkout-index -a

但我想知道是否只有一个命令可以做到这一点。

1 个答案:

答案 0 :(得分:2)

简短的回答是" no":所有读取完整树的Git操作都会这样做到索引中。

短语 索引,而不是 index ,是你的主要逃生舱,使得长答案成为合格的"是"。您可以使用 索引来避免使用 索引,例如,使用某些替代索引而不是&#34 ;所述"指数。你让这个其他索引代替""通过将替代索引的路径名放在环境变量GIT_INDEX_FILE中来建立索引。在某些情况下,你可以完全绕过索引,嗯,请继续阅读。 : - )

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

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

build_index('', top_level_tree_hash)

其中build_index执行此操作(在伪Python中):

def build_index(path_so_far, tree_hash):
    tree = get_object('tree', tree_hash)
    for mode, hash, name in tree:
        if mode == MODE_TREE:
            build_index(path_so_far + name + '/', hash)
        else:
            cache_this_object(path_so_far + name, mode, hash)

当递归完成时,索引的缓存方面在其中包含每个非树对象的所有完整路径名,模式和散列,并且可以提取。

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

Git"想要的第二个原因"读入索引与在表示文件的blob对象上完成的行尾和过滤(涂抹和清理过滤器)处理有关。 (表示符号链接和gitlinks的Blob对象既不需要EOL hackery也不需要涂抹过滤。)Git通常会将此处理推迟到将文件从索引复制到存储库的位置。此时,Git具有文件的完整路径名(因为它以这种方式存储在索引 2 中)和哈希ID。它在相应的.gitattributes文件中,在工作树和/或索引中和/或全局中查找相应的EOL或过滤。工作树文件(如果存在)覆盖仅索引文件和属性文件"更本地"保存文件的目录覆盖目录层次结构中较高的目录,如果Git具有完整的索引和工作树,那么实现就更容易了。它可以轻松找到正确的EOL和过滤器属性,并在从索引存储的散列到索引存储的路径名所确定的工作中位置树的复制过程中将它们应用于blob内容。

所有这一切的结果是提取文件"简单方法",Git需要一个索引,在命令持续时间内它是至少运行 - 作为 索引。但是如果您有一个特定的文件,其路径名称是您事先知道的,并且愿意冒险EOL /过滤(或完全放弃它们),您可以使用git cat-file -pgit 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 / file模式(100644100755)和一种子树模式(40000)。符号链接或gitlink也由blob对象表示,因此如果模式为40000,我们会递归并获取另一个树对象,否则我们会点击一个叶子并将最好代表一个blob的哈希写入缓存。

2 索引中的路径名被压缩,所以这不完全正确。但是,有几种索引格式,因此它特别复杂。将每个索引/缓存条目视为表示< full_path_name,flags,hash_ID,cache_statistics>是最好的。元组。