Live data from Hacker News

Commits are shapshots, not diffs

github.blog

31–40 of 154 posts

Re: Commits are shapshots, not diffs

#31

Earlier quoted context omitted.

A snapshot is easy to understand. It's just the contents of a file at a point in time. Diffs can have different definitions, and I've never seen a complete rigorous one for whatever git uses, if anything. Loosely a "diff" is the changes between one version an another. But to understand what cherry-pick does, we (or maybe just I) need more than a loose definition. Using snapshots makes `rebase` trivial. The contents o…

> Using snapshots makes `rebase` trivial. The contents of a commit doesn't change. Just the link to its predecessor. It's the exact opposite. When you rebase, you want to apply the changes you're rebasing atop other existing changes. If you just copy over the snapshot, you break everything. Rebasing a snapshot basically smashes your history and is utterly useless. That would make a rebase-pull… implicitly revert ever…

Warning: When I made this comment, I was under some false assumptions. Here's the original.

---

A snapshot is the aggregate of all previous changes. I don't see what could be broken by copying the snapshot.

I'm not familiar with rebase-pull, but I don't see why any revert would be involved. The snapshot before the rebase is exactly the same as the snapshot after the rebase. Only the predecessor is changed. The contents of the predecessor doesn't matter, since a snapshot contains the entire state of the tree.

Re: Commits are shapshots, not diffs

#32
post #9

Git is the leakiest abstraction in the history of abstractions. Diffs are a "natural" object for version control yet got doesn't actually use them and as we can see in this article, multiple git commands leak this implementation detail.

And good thing it's leaked, as anyone who's ever maintained, say linux kernel drivers for multiple distros knows. Easy to maintain a stack of commits on Linus's kernel and patch them into the various distro kernels. Well, for some value of "easy". But it would be a hell of a lot harder if you didn't have access to diffs and what I think of as "patch arithmetic." (i.e. source - patch3 + patch1 + patch2 == source + patch2 + patch1 - patch3). Patches are commutative (barring conflicts).

Re: Commits are shapshots, not diffs

#33

Why does thinking about commits as snapshots make cherry-pick and rebase easier to understand? I've always thought of and taught commits as diffs because git does a good job of abstracting away the distinction. EDIT: To be clear, I think this is one of the _few_ abstractions that git doesn't leak. It does a pretty bad job everywhere else.

It highlights why they're generally bad ideas that should be used sparingly, and certainly not as the default.

Re: Commits are shapshots, not diffs

#34

Earlier quoted context omitted.

You're right that the commit produced by the cherry-pick operation won't be identical to the commit being cherry-picked. It's the diffs that are identical, not the final result. It's analogous to how the difference between 5 and 15 is equal to the difference between 105 and 115.

That doesn't help. The result of subtraction is defined to be a number. The result of a diff is... a nebulously defined concept that somehow describes the changes. It's not clearly (to me) defined which parts of the files are considered to part of the diff and which parts are to be excluded.

> The result of subtraction is defined to be a number.

A diff shows the difference between two commits (i.e. snapshots). Perhaps a better math analogy: one point can be subtracted from another to give a vector.

> It's not clearly (to me) defined which parts of the files are considered to part of the diff and which parts are to be excluded.

You're right that it's not precisely defined in that way, but there's a good reason for this.

If you move the top line of a file to the bottom, should the diff tool show you that one line was deleted and one new line was added (i.e. that one line having been moved), or should it show all the other lines in the file as having been deleted and re-added in a different place? Both are valid interpretations of the difference between the two snapshots, but of course a real-life diff tool will show the former, as that's what's helpful to the user.

Re: Commits are shapshots, not diffs

#35

Why does thinking about commits as snapshots make cherry-pick and rebase easier to understand? I've always thought of and taught commits as diffs because git does a good job of abstracting away the distinction. EDIT: To be clear, I think this is one of the _few_ abstractions that git doesn't leak. It does a pretty bad job everywhere else.

It does a good job in simple scenarios. It breaks down often. I've seen plenty of horribly botched merges and rebases that took many hours to fix up. We learn to work around this by adapting and limiting our workflows. Most devs are just so used to git that a different model like Pijul is hard to reason about or see the benefits of, but improvement is definitely possible.

To be clear, git has a horrible interface and is the leakiest abstraction. But I don't think that the snapshot-diff distinction is one of those leaks.

Re: Commits are shapshots, not diffs

#36

Earlier quoted context omitted.

> Using snapshots makes `rebase` trivial. The contents of a commit doesn't change. Just the link to its predecessor. It's the exact opposite. When you rebase, you want to apply the changes you're rebasing atop other existing changes. If you just copy over the snapshot, you break everything. Rebasing a snapshot basically smashes your history and is utterly useless. That would make a rebase-pull… implicitly revert ever…

Warning: When I made this comment, I was under some false assumptions. Here's the original. --- A snapshot is the aggregate of all previous changes. I don't see what could be broken by copying the snapshot. I'm not familiar with rebase-pull, but I don't see why any revert would be involved. The snapshot before the rebase is exactly the same as the snapshot after the rebase. Only the predecessor is changed. The conten…

> A snapshot is the aggregate of all previous changes. I don't see what could be broken by copying the snapshot.

If you copy the snapshot, you lose all the intermediate commits you're rebasing onto, because they're not in the snapshot you're rebasing.

> The snapshot before the rebase is exactly the same as the snapshot after the rebase.

Which is exactly what you do not want.

> The contents of the predecessor doesn't matter, since a snapshot contains the entire state of the tree.

Which, again, is exactly what you do not want:

    a - b - c - d
              \ e - f
If I rebase `d` onto `f`, I want the changes performed by `e` and `f` as well as those performed by `d`. If I just copy over the `d` snapshot to d', I get the exact same state I had at `d` with a different history, losing the changes performed in e and f, thus reverting them.

That's why when you rebase a commit, not only does the commit id change (makes sense, different parent) the tree also changes, which also makes sense because the content changes.

Re: Commits are shapshots, not diffs

#37

Earlier quoted context omitted.

A snapshot is easy to understand. It's just the contents of a file at a point in time. Diffs can have different definitions, and I've never seen a complete rigorous one for whatever git uses, if anything. Loosely a "diff" is the changes between one version an another. But to understand what cherry-pick does, we (or maybe just I) need more than a loose definition. Using snapshots makes `rebase` trivial. The contents o…

> I've never seen a complete rigorous one for whatever git uses, if anything Isn't that the point of a conceptual model? Thinking of commits as diffs abstracts away the actual implementation, which allows me to understand cherry picks and rebasing without worrying about object OIDs and trees. I can think of those actions as "applying the diffs onto other commits", even though technically it can't be implemented that…

> Isn't that the point of a conceptual model?

Probably, but my understanding of the conceptual model is full of holes. There are many scenarios to which I don't know how cherry-pick would react. Maybe I should just try them.

"applying the diffs onto other commits" is all well and good for simple scenarios where there are not multiple interpretations of changes. But for other scenarios, it requires one to know what's actually in a diff, which I don't know. In fact, different git clients present diffs differently. Is that evidence that diffs aren't a real thing? I don't know.

Re: Commits are shapshots, not diffs

#38

Earlier quoted context omitted.

Warning: When I made this comment, I was under some false assumptions. Here's the original. --- A snapshot is the aggregate of all previous changes. I don't see what could be broken by copying the snapshot. I'm not familiar with rebase-pull, but I don't see why any revert would be involved. The snapshot before the rebase is exactly the same as the snapshot after the rebase. Only the predecessor is changed. The conten…

> A snapshot is the aggregate of all previous changes. I don't see what could be broken by copying the snapshot. If you copy the snapshot, you lose all the intermediate commits you're rebasing onto, because they're not in the snapshot you're rebasing. > The snapshot before the rebase is exactly the same as the snapshot after the rebase. Which is exactly what you do not want. > The contents of the predecessor doesn't…

Ok I see. I actually misunderstood what rebase actually did. So I guess it's a good thing then that I've never used it. Thanks for your persistence.

Re: Commits are shapshots, not diffs

#39

Earlier quoted context omitted.

That doesn't help. The result of subtraction is defined to be a number. The result of a diff is... a nebulously defined concept that somehow describes the changes. It's not clearly (to me) defined which parts of the files are considered to part of the diff and which parts are to be excluded.

> The result of subtraction is defined to be a number. A diff shows the difference between two commits (i.e. snapshots). Perhaps a better math analogy: one point can be subtracted from another to give a vector. > It's not clearly (to me) defined which parts of the files are considered to part of the diff and which parts are to be excluded. You're right that it's not precisely defined in that way, but there's a good r…

I'm glad that real-life diff tools work in ways that they deem to be useful. But they don't always produce the most sensible result. In fact different algorithms produce different diff visualizations for the same input. I'm just a little uncomfortable with a feature that uses diffs for purposes other than display for humans, since they don't seem to be consistently defined.

Re: Commits are shapshots, not diffs

#40
post #7

Conceptually, a git commit is a snapshot. Simple as that. The user doesn't need to worry about how git manages its data internally. > I believe that Git becomes understandable if we peel back the curtain and look at how Git stores your repository data. This strikes me as misleading in the same way this StackOverflow answer [0] is misleading. In terms of how git stores data, commits are not always snapshots. Internall…

The delta compression in Git is about storing the file contents of an object as a diff against another object. This changes the literal size on-disk, but it doesn't change the logical unit. In fact, the delta chains used by Git for space compression have no direct relation to the object model DAG. From the perspective of a user using Git, these deltas are completely invisible. Edit: perhaps to help this point... If G…

Respectfully, I already made all of those points quite explicitly.
Post reply on HN