git - Can I read a tree directly into a working directory going over the index -
i'm exploring git internals. , i'm wondering if there's git command can allow me read tree working tree directly without using index
. example i've created tree:
$ 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
and want read tree e05d9daa03229f7a7f6456d3d091d0e685e6a9db
2 files f1.txt
, f2.txt
directly working directory. know can use following combo:
$ git read-tree e05d9daa03229f7a7f6456d3d091d0e685e6a9db $ git checkout-index -a
but i'm wondering if there's single command that.
the short answer "no": git operations read complete tree index.
the phrase an index, opposed the index, main escape hatch makes long answer qualified "yes". can avoid using the index using an index—as in, alternative index instead of "the" index. make other index take place of "the" index putting alternative index's path-name in environment variable git_index_file
. , in cases, can bypass index entirely, ... well, read on. :-)
there are, think, 2 main reasons git "wants" read series of trees commit index, before copying files work-tree. first 1 has resolving full path names: within tree object, inside git repository, each stored sub-object—sub-tree or blob—has mode (which 40000
sub-tree),1 hash, , name. name not full path name of object, though: it's name component, bar
part of foo/bar/baz.txt
instance.
by extracting linearly through each tree, recursing on each sub-tree, git can build index in each name stored in index full path name. is, kick off tree extraction with, in pseudo-code:
build_index('', top_level_tree_hash)
where build_index
(in pseudo-python):
def build_index(path_so_far, tree_hash): tree = get_object('tree', tree_hash) 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)
when recursion finishes, cache aspect of index has in of full path names, modes, , hashes each non-tree object, , ready extracted.
without index, though, if have tree read, have no idea leading path-name components point should be. need recursion above maintain our path-names us.
the second reason git "wants" read index has end-of-line , filtering (smudge , clean filter) processing done on blob objects representing files. (blob objects representing symlinks , gitlinks need neither eol hackery nor smudge filtering.) git defers processing point file copied index repository. @ point, git has full path name of file (because it's stored way in index2) , hash id. looks appropriate eol or filtering in appropriate .gitattributes
file(s), in work-tree and/or index and/or globally. work-tree files, if present, override index-only files, , attribute files "more local" directory holding file override higher in directory hierarchy, again easier achieve if git has entire index , work-tree in place this. can find correct eol , filter attributes easily, , apply them blob contents during copy index-stored hash, location-in-work-tree determined index-stored path name.
the upshot of of extract files "the easy way", git needs an index, which—for duration of command it's running @ least—acts the index. if have 1 particular file path name know in advance, , willing risk eol/filtering bit (or forego them entirely), can use git cat-file -p
or git show
extract blob contents:
git cat-file -p [--textconv | --filters] $commithash:$fullpath
for instance. when using --textconv
or --filters
, must provide path, if have raw hash must use:
git cat-file -p $filteropt --path=$path $rawhash
(where $filteropt
1 of above --textconv
or --filters
options).
if want contents unfiltered, none of above caveats apply @ all. should omit --textconv
or --filters
, , git cat-file -p
not need path name @ all. acceptable git rev-parse
locates blob object suffices, and:
git cat-file -p $hash > $path
suffices extract raw blob contents, writing them $path
.
1the repository object's type implied mode , later matched against underlying repository object's actual type. if ignore symlinks , gitlinks, there 2 blob/file modes (100644
, 100755
) , 1 sub-tree mode (40000
). symlink or gitlink represented blob object, if mode 40000
recurse , fetch tree object, otherwise have hit leaf , write hash, had best represent blob, cache.
2path names in index compressed, not entirely true. there several index formats, though, it's particularly complicated. it's best think of each index/cache entry representing <full_path_name, flags, hash_id, cache_statistics> tuple.
Comments
Post a Comment