Home >Computer Tutorials >Computer Knowledge >Are Git commits diffs, snapshots, or history?
It’s easy for me to understand how Git commits are implemented, but it’s difficult to understand other people’s views on submissions. So I asked some questions to others on Mastodon.
I conducted a very unscientific survey and asked people what they think of Git commits: is it a snapshot, a diff, or a list of all previous commits? (Of course, it's reasonable to think of it as all three, but I'm curious about people's main
turn out:
I'm surprised how close the ratios are for the two options of Difference and Snapshot. People also made some interesting but conflicting points, like
"In my opinion the commit is a diff, but I think it's actually implemented as a snapshot" and
"In my opinion , the commit is a snapshot, but I think it's actually implemented as a diff". We'll talk more about how submission is actually implemented later.
Before we go any further: What do we mean by "a difference" or "a snapshot"?
The "difference" I'm talking about is probably pretty obvious: the difference is what you get when you run git show COMMIT_ID
. For example, here's a typo fix in the rbspy project:
diff --git a/src/ui/summary.rs b/src/ui/summary.rs index 5c4ff9c..3ce9b3b 100644 --- a/src/ui/summary.rs +++ b/src/ui/summary.rs @@ -160,7 +160,7 @@ mod tests { "; let mut buf: Vec = Vec::new(); -stats.write(&mut buf).expect("Callgrind write failed"); +stats.write(&mut buf).expect("summary write failed"); let actual = String::from_utf8(buf).expect("summary output not utf8"); assert_eq!(actual, expected, "Unexpected summary output"); }
You can see it on GitHub: https://github.com/rbspy/rbspy/commit/24ad81d2439f9e63dd91cc1126ca1bb5d3a4da5b
What I mean by "snapshot" is "all the files you get when you run git checkout COMMIT_ID
".
Git usually refers to the list of submitted files as a "tree" (such as a "directory tree"). You can see all the files submitted above on GitHub:
https://github.com/rbspy/rbspy/tree/24ad81d2439f9e63dd91cc1126ca1bb5d3a4da5b (it is /tree/
instead of /commit/
)
The advice I hear most often about learning Git is probably "Just learn how Git represents things internally, and everything will become clearer." I obviously really like this perspective (if you've spent some time reading this blog, you'll know that I like
But as a method of learning Git, it was not as successful as I hoped! Normally I would excitedly start explaining "Okay, so a Git
commit is a snapshot, it has a pointer to its parent commit, then a branch is a pointer to the commit, and then...", but I tried People who help will tell me that they didn't really find this explanation very useful, they still don't get it. So I've been looking at other options.
But let’s talk about the internal implementation first.
Internally, Git represents commits as snapshots (which store a "tree" of the current version of each file). I'm in a Git repository, where are your files? I've written about this in , but here's a very quick overview of the internal format.
This is a submission representation:
$ git cat-file -p 24ad81d2439f9e63dd91cc1126ca1bb5d3a4da5b tree e197a79bef523842c91ee06fa19a51446975ec35 parent 26707359cdf0c2db66eb1216bf7ff00eac782f65 author Adam Jensen1672104452 -0500 committer Adam Jensen1672104890 -0500 Fix typo in expectation message
And, when we view this tree object, we see a list of every file/subdirectory under the root of the repository in this commit:
$ git cat-file -p e197a79bef523842c91ee06fa19a51446975ec35 040000 tree 2fcc102acd27df8f24ddc3867b6756ac554b33ef.cargo 040000 tree 7714769e97c483edb052ea14e7500735c04713eb.github 100644 blob ebb410eb8266a8d6fbde8a9ffaf5db54a5fc979a.gitignore 100644 blob fa1edfb73ce93054fe32d4eb35a5c4bee68c5bf5ARCHITECTURE.md 100644 blob 9c1883ee31f4fa8b6546a7226754cfc84ada5726CODE_OF_CONDUCT.md 100644 blob 9fac1017cb65883554f821914fac3fb713008a34CONTRIBUTORS.md 100644 blob b009175dbcbc186fb8066344c0e899c3104f43e5Cargo.lock 100644 blob 94b87cd2940697288e4f18530c5933f3110b405bCargo.toml
This means that checking out a Git commit is always fast: it's just as easy for Git to check out yesterday's commit as it is to check out a million commits ago. Git never needs to reapply 10,000 diffs to determine the current state because commits are never stored as diffs at all.
I just mentioned that Git commit is a snapshot, but when someone says "In my opinion, the commit is a snapshot, but I think it is a difference in implementation"
, this is actually also true. ! Git
commits aren't represented in the form of diffs you might be used to (they're not stored on disk as a diff from the previous commit), but the basic intuition is that if you're going to do a 10,000## If the file in line # is edited 500 times, then the efficiency of storing 500 files will be very low.
git clone a repository, Git also compresses the data.
git show SOME_COMMIT to see the diff of a certain commit is a bit counter-intuitive. My understanding is:
That said, I think Git stores commits as snapshots, and packfile is just an implementation detail to save disk space and speed up cloning. I've never actually had to know how packfile works, but it does help me understand how Git snapshots commits without taking up too much disk space.
I think this misunderstanding is sometimes very useful, and it doesn't seem to be a problem for daily Git use. I really like that it makes the things we use most (differences) the most basic elements - it's very intuitive to me.
I've also been thinking about some other useful but "wrong" understandings of Git, such as:
I think there is a range of "wrong" understandings of Git that make perfect sense, are largely supported by the Git user interface, and do not cause problems in most cases. But it can get confusing when you want to undo a change or something goes wrong.
Even if I know commits are snapshots in Git, I probably treat them as diffs most of the time because:
git show
, so it's just something I'm used to seeingBut I also sometimes think of commits as snapshots because:
git checkout COMMIT_ID
is doing (the idea of reapplying 10,000 commits stresses me out)Some of Mastodon’s replies also mentioned:
Some other words people use when talking about commits that may be less ambiguous:
I have a hard time understanding the different understandings people have of Git. What's especially tricky is that, although "wrong" understandings are often very useful, people are so keen to be wary of "wrong" mental models that people are reluctant to share their "wrong" ideas for fear of some Git interpreter Will stand up and explain to them why they are wrong. (These Git
interpreters usually mean well, but it can have a negative impact regardless)
Thanks to Marco Rogers, Marie Flanagan, and everyone at Mastodon for discussing Git commits with me.
The above is the detailed content of Are Git commits diffs, snapshots, or history?. For more information, please follow other related articles on the PHP Chinese website!