checkout
) appear to assume that a commit is a snapshot or state of the working tree.A commit is a snapshot state. When you do git diff
, it calculates the diff to the parent. This is why there can be multiple parents (the case when there is a merge). Internally, there is delta compression going on, but the versioning model isn't patch-based.
A central concept in git is the index. This is a big object containing the tree of objects being tracked. Changes are staged when they propagate from the working copy to the index; this puts the index into a modified state. The commit operation turns that state into a new commit.
Short answer: both.
Medium answer: It depends.
Long answer: Git is a bit like quantum phenomena: Neither of the two views alone can explain all observations. Read on.
Internally, Git will use both representations, depending (conceptually) on which one it deems more efficient in terms of storage space and execution time for a given commit. The snapshot representation is the primary one.
From the user's point of view, however, it depends on what you do:
Indeed some commands simply only make any sense at all when you
think about commits as snapshots of the working tree.
This is most pronounced for checkout
, but is also true for
stash
and at least halfway for fetch
and reset
.
For other commands, madness is the likely result when you try to think of commits in this manner. For those other commands, commits are clearly treated as changes,
show
, diff
)apply
, cherry-pick
, pull
)rebase
)merge
, cherry-pick
)There is a side-effect of duality 1 that can shock Git newbies accustomed to other versioning systems. It is the fact that Git appears to not even commit itself to its commits.
Huh?
Assume you have created a branch X containing what you like to think
of as your commits A
and B
.
But master
has progressed a little, so you rebase
X to master
.
When you think of A
and B
as changes, but of master
as a snapshot
(hey, particles and waves in a single experiment!),
this is not a problem:
Just apply the changes A
and B
to the snapshot master
.
This thinking is so natural that you will barely notice that Git
has now rewritten your commits A
and B
: They now have different
snapshot content and hence a different SHA-1 ID.
In Git, the conceptual commit that you think of as a developer
is not a fixed-for-all-times kind of thing, but rather
some fluid object that changes as a result of working with your
repository.
In contrast, if you think of all three (A
, B
, and master
)
as snapshots or of all three as changes,
your brain will hurt and you will get nowhere.
The above is a much-simplified description. In Git reality,
And don't get confused by the fact that the Pro Git book's very first characterization of Git (in section "Git Basics") is "Snapshots, Not Differences".
Git is complicated after all.