kjo
kjo

Reputation: 35301

What are the finest-grained operations on the .git/index file?

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

Answers (2)

Edward Thomson
Edward Thomson

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

Yuval Adam
Yuval Adam

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 and git 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

Related Questions