Reputation: 35301
Certain git
commands, such as git add ...
modify the state of the .git/index
file, but I imagine that some such operations may be thought as a sequence of smaller operations. For example,
git add foo bar
may be decomposable into
git add foo
git add bar
In fact, there may be (for all I know) the commands above may be broken down into even "finer-grained" (but still ".git/index
-modifying") git
commands.
My question is, what are the finest-grained modifications that can be performed on the .git/index
file using git
commands? IOW, what are the "atomic" command-line operations on .git/index
?
I imagine that all these commands will be plumbing commands. Also, if I had to guess, I'd imagine that gid add <file>
and git rm --cached <file>
would approximate two of those operations. On the other hand, git mv <old> <new>
may be a composite of an "atomic" deletion followed by an "atomic" addition...
EDIT: The motivation for this question is the following.
The aspects of git
's behavior that I find most confusing are those that result in a modification of the .git/index
file. Everything else that git
those is a bit more open to inspection. The .git/index
file, however, is pretty opaque.
For this reason, I'd like to get a better understanding of how the .git/index
file gets modified.
Upvotes: 3
Views: 96
Reputation: 78653
The main index is composed of several index entries, and the collection of entries represents the contents of the next commit. When you git add
a file, it adds (or updates) the index entry for the given filename.
The index entry itself contains several fields both related to the staged change (the object ID and mode) as well as related to the contents in the working directory (the timestamp, file size, etc). You can see both of these with the git ls-files
command:
C:\Temp\TestRepo>git add file.txt
C:\Temp\TestRepo>git ls-files --stage
100644 9b72baa6b025e0eb1dd8f1fd23bf5d5515012cd6 0 file.txt
C:\Temp\TestRepo>git ls-files --debug
file.txt
ctime: 1391645170:0
mtime: 1391645172:0
dev: 0 ino: 0
uid: 0 gid: 0
size: 7 flags: 0
Generally speaking, one simply uses the git add
and git rm
commands to add, update and remove entries from the main index. However, certain commands will update only parts of the index entries. For example, git checkout
and git status
will write the working directory cache contents of an index entry. For example:
C:\Temp\TestRepo>touch file.txt
C:\Temp\TestRepo>git status
# On branch master
nothing to commit, working directory clean
C:\Temp\TestRepo>git ls-files --debug
file.txt
ctime: 1391645170:0
mtime: 1391645458:0
dev: 0 ino: 0
uid: 0 gid: 0
size: 7 flags: 0
(Note the updated mtime
(modified time) field in the index entry).
The smallest single change you can make to the index in a single command is to flip the assume-unchanged bit on a file:
C:\Temp\TestRepo>git update-index --assume-unchanged file.txt
C:\Temp\TestRepo>git ls-files --debug
file.txt
ctime: 1391645170:0
mtime: 1391645458:0
dev: 0 ino: 0
uid: 0 gid: 0
size: 7 flags: 8000
(Note the change to the flags
field from 0x0000 to 0x8000, flipping a single bit.)
Upvotes: 2
Reputation: 165222
Generally speaking, git is nothing more than a sophisticated key-value store, which essentially has object blobs which are stored in trees.
You might want to read about Git Objects, taken from the official Git Internals documentation to understand exactly how it all fits together.
Specifically, regarding your question:
... what Git does when you run the
git add
andgit commit
commands — it stores blobs for the files that have changed, updates the index, writes out trees, and writes commit objects that reference the top-level trees and the commits that came immediately before them.
Upvotes: 0