Reputation: 105499
I was having an issue with renaming a file and was given a solution which included two git commands - git read-tree -i HEAD
and git checkout-index -a -f
. I seems to have figured out what the second one does and tested it, but I can't grasp why I would need the first one even for the simplest case. I thought that it somehow could substitue git add
command and add a file to index, however when I created a new file and run the command and then checked the contents of index with ls-files --staged
it didn't show this files as added, so probably my assumption about the purpose of the command is wrong. I also visited the manual page but still don't understand why I would need that command.
Upvotes: 7
Views: 12593
Reputation: 1324178
Git 2.34 (Q4 2021) illustrates what git read-tree
is used for, through a bug fix for that feature.
See commit 0e29222, commit 94b7f15, commit 56d06fe, commit 1fdd51a, commit 480d3d6, commit 1b5f373, commit c42e0b6, commit 04988c8, commit 491a757, commit c512d27 (27 Sep 2021), and commit 446cc55 (24 Sep 2021) by Elijah Newren (newren
).
See commit 04d3761 (20 Sep 2021) by Junio C Hamano (gitster
).
(Merged by Junio C Hamano -- gitster
-- in commit a7c2daa, 13 Oct 2021)
read-tree, merge-recursive
: overwrite ignored files by defaultSigned-off-by: Elijah Newren
This fixes a long-standing patchwork of ignored files handling in read-tree and merge-recursive, called out and suggested by Junio long ago.
Quoting from commit dcf0c16 (core.excludesfile clean-up, 2007-11-16, Git v1.5.4-rc0 -- merge) ("core.excludesfile clean-up" 2007-11-16):
git-read-tree
takes--exclude-per-directory=<gitignore>
, not because the flexibility was needed.
Again, this was because the option predates the standardization of the ignore files....
On the other hand, I think it makes perfect sense to fix
git-read-tree
,git-merge-recursive
andgit-clean
to follow the same rule as other commands.History shows each of these were partially or fully fixed:
clean
was taught the new trick in 1617adc ("Teachgit clean
(man) to usesetup_standard_excludes()
", 2007-11-14, Git v1.5.4-rc0 -- merge).read-tree
was primarily used bycheckout
&merge
scripts.
checkout
andmerge
later became builtins and were both fixed to use the newsetup_standard_excludes()
handling in fc001b5 ("checkout,merge
: loosen overwriting untracked file check based on info/exclude", 2011-11-27, Git v1.7.9-rc0 -- merge).
So the primary users were fixed, thoughread-tree
itself was not.- merge-recursive has now been replaced as the default merge backend by
merge-ort
.
merge-ort
fixed this by usingsetup_standard_excludes()
starting early in its implementation; see commit 6681ce5 ("merge-ort
: add implementation of checkout()", 2020-12-13, Git v2.31.0-rc0 -- merge listed in batch #1), largely due to its design depending oncheckout()
and thus being influenced by the checkout code.
However,merge-recursive
itself was not fixed here, in part because its design meant it had difficulty differentiating between untracked files, ignored files, leftover tracked files that haven't been removed yet due to order of processing files, and files written by itself due to collisions).Make the conversion more complete by now handling
read-tree
and handling at least theunpack_trees()
portion ofmerge-recursive
.
While merge-recursive is on its way out, fixing theunpack_trees()
portion is easy and facilitates some of the later changes in this series.
Note that fixingread-tree
makes the--exclude-per-directory
option toread-tree
useless, so we remove it from the documentation (though we continue to accept it if passed).
Upvotes: 1
Reputation: 55453
git read-tree
goes like this:
Parses a "tree-ish" passed to it to find an object existing in the Git repository describing a tree.
A tree is what represents a directory in Git: this kind of object lists the SHA-1 and filesystem names of blobs (files) and nested trees (of nested directories) comprising the tree. Each commit references exactly one tree which represents the state of the top-level project directory itself.
A "tree-ish" is a specification whish Git is able to parse down to the name of a tree object. For instance, HEAD
is first parsed as the name of a reference, then the branch it points to is chased to get its tip commit, then it's parsed to get the name of its tree object.
Reads the acquired tree object, recursively, and populates the index with the information on these objects. The index does not contain the actual data of the files—only meta information on them.
IOW, the index is like a miniature filesystem kept in a single file. Its format is optimized for super-fast access over a huge nested sets of files.
Now another command, git checkout-index
can be used to bring the work tree in sync with the index. Commands like git checkout <commit>
do exactly this: call git read-tree
to populate the index and then git checkout-index
to sync the work tree with it.
That's the basics. The command is able to do more than that:
-m
command line option, it's able to merge the tree(s) passed to it into the index.--prefix
).--empty
).In the simplest form we've called it when we've been dealing with your original problem, it just replaced the contents of the index with what was referenced by HEAD
at the moment.
Note that git read-tree
is a plumbing command, not intended to be routinely used by users. It's called automatically when you do things like git checkout <commit>
. I've advised to call it directly because who knows if running git checkout HEAD
would really update your index or it would decide that since it anyway reflects the state of the HEAD
nothing should be done. Calling it by hand ensured the index started to contain exactly the state we needed. In the general case you don't need this program and hence that's why it's hard to come up with a trivial usage example.
Upvotes: 15
Reputation: 33203
The read-tree command takes a git tree object and copies its state into the index. In your case you are taking the tree currently marked as HEAD and resetting the index to match this tree - that is equivalent to git reset --mixed HEAD. The first command can be used when you need to bring in a discontinuous history from some other repository (see this blog entry) such as a converted CVS repository. Once you have the index in a state that matches what you need you can create a commit as normal. The read-tree command is not going to be like add - it will not look at anything in the current working folder set. It is doing reset.
Upvotes: 2