13 ms·
Do we think of Git commits as diffs, snapshots, and/or histories?
- kadoban 3y agoYes. It depends what you're doing. Most of the basic commands, they're snapshots. When you get into things like rebase especially, you have to think in terms of diffs. I'm not sure what "histories" are, as a distinct thing from snapshots, kind of seems like the same thing.
- gavinhoward 3y agoI agree with you, just want to explain what a history is. A "history" is what other version control systems call a "branch." It's the commit and all of its ancestors. Some people think of things this way because the commit ID does depend on its ancestors by depending on its parent (which depends on its parent, which depends on its parent...). This is why, if you rebase a commit, and the content ends up exactly the same (maybe someone already made the equivalent change in both branches), the commit ID still changes: the parent has changed, so the hash changes, so the ID changes. I hope that makes sense.
- Evidlo 3y agoSnapshots and diffs aren't enough. They don't describe the DAG structure.
- GauntletWizard 3y agoThere's not a lot more to Git's DAG in a commit besides "Snapshot", "Comment", and "Pointer to previous commits". Even signatures are just a bit of porcelain to the data structure.
- cerved 3y agoRegarding rebase, I disagree. Thinking about a branch as a series of diffs can lead to a lot of unexpected outcomes
- dado3212 3y agoThat’s interesting! I think of them as diffs, though I know they’re snapshots. More familiar with Mercurial though, which may influence my thinking.
- kelnos 3y agoI've used git nearly since it was first released, and I also have (more or less) always known how git implements commits. But to me, they are still diffs.
- gjvc 3y agocommit == snapshot + reference to parent commit
- kelnos 3y agoHow it's implemented in git, yes, but I don't think that's useful as a mental model. A commit is a change -- diff -- from the previous version of the state of the repository. When I make a commit, I don't think of it as making a copy of my repository, adding my changes, and storing the entire result (though that's exactly what many people used to do before version control was common!). I think of it as storing the change that I made, and only the change.
- AndrewDucker 3y agoYou may think of it that way, but it is actually storing a snapshot of the current state, with a pointer to the previous state. And that's what a commit is, it's a snapshot.
- kelnos 3y agoI'm well aware of how it actually works, but I don't think git's implementation details are a useful mental model of source control in general.
- gjvc 3y agoHow it's implemented in git, yes, but I don't think that's useful as a mental model. pointers to content, right. "Remember, git does not track changes, it tracks content." I kept telling myself when I learned how the system works. As conceptually great as that is, in the early days of learning git, I found the terminology in the command-line interface VERY off-putting, and it played havoc with my mental model. (I say this lest you think I'm unconditionally cheerleading git or the implementation.) BTW, perhaps because effective use of a VCS is so vital to programming without stress, people tend to think they can learn it on the fly, which leads to all sorts of insecurities about not really knowing how a certain operation works. (I've worked in toxic places, so seen how fear has myriad weird manifestations.) Anyway, not intending to disagree or correct you, just offering my experience while I suffer winter flu.
- adrianmonk 3y agoWell, git makes a distinction between a delta and a diff, and it uses both. A delta is a lot like a diff, and loosely speaking, you could say it's one kind of diff. And deltas are used (in packfiles) for storing git objects, so in that sense, a commit is (sometimes) stored as a delta. But each commit takes a snapshot of the entire tree, so in that sense it is a complete snapshot. However, even without delta object storage, if a file does not change between one commit and another, then its blob object will be reused because its hash will match, so in that sense, a commit stores (loosely speaking, again) a kind of diff. Also, a commit object refers to a tree object but also zero or more parent commit objects, and via these parent object(s), you can reach past commits, so a commit does also, in a sense, store (loosely speaking) a history of every past commit. (Well, not every, but every one reachable from this branch.) So, none of the options is 100% wrong, depending on your interpretation and how you define terms.
- tsimionescu 3y agoCommits are also used as diffs by several git commands - rebase, cherry-pick, patch, probably others. These commands take a commit and a target branch, but they use the commit as a diff from its parent, not as a snapshot. So it's fair to say that git's own API treats commits as diffs in some situations.
- IshKebab 3y agoI think you're getting a bit confused. The delta compression of commits in packfiles is purely a storage optimisation. It has zero effect on the semantics of git. It's completely invisible to users and has nothing to do with diffs between commits and their parents. Git doesn't use diffs at all, except ephemerally for some operations (e.g. displaying diffs between commits, or rebases). Diffs are never stored.
- adrianmonk 3y agoI understand all that. I'm saying, if you write a survey and one of the possible answers is "diff", but you don't clearly define what you mean by "diff", then don't be surprised if respondents use any reasonable definition that makes sense to them. Ask an ambiguous question, get a mishmash of answers. The thing that Git uses for packfiles is called a "delta" by Git, but it's also reasonable to call it a "diff". After all, Git's delta algorithm is "greatly inspired by parts of LibXDiff from Davide Libenzi"[1]. Not LibXDelta but LibXDiff. Yes, how Git stores blobs (using deltas) is orthogonal to how Git uses blobs. But while that orthogonality is useful for reasoning about Git, it's not wrong to think of a commit as the totality of what Git does, including that optimization. (Some people, when learning Git, stumble over the way it's described as storing full copies, thinking it's wasteful. For them to wrap their heads around Git, they have to understand that the optimization exists. Which makes sense because Git probably wouldn't be practical if it lacked that optimization.) The reason I'm bringing all this up is, if you're trying to explain Git, which is what the original article is about, then it's very important to keep in mind that someone who is learning Git needs to know what you mean when you say "diff". Most people who already know Git would tend to gravitate toward the definition of "diff" that you're assuming (the thing that Git computes on the fly and never stores), but people who already know Git aren't the target audience when you're teaching Git. --- [1] https://github.com/git/git/blob/master/diff-delta.c https://github.com/git/git/blob/master/diff-delta.c
- o11c 3y ago"history vs snapshot" is a kind of weird distinction that could use some pulling apart. A commit is a snapshot, but that snapshot includes a reference to prior history. It "isn't" the history per se, but includes a way to get it. When we `git log` it's clearly thinking in terms of a sequence of commits, not a single commit with multiple snapshots. A commit is not a full history; a lot of stuff is only in the reflog, and the reflog isn't permanent. Losing the branch name is a big deal but there are no good solutions and mercurial's attempt is definitely worse (flashbacks of `svn rename`, which I'm not sure I ever used personally but heard enough horror stories about that I basically refused to actually use any VCS until git saved the world) A commit (or more often, a series of commits) can be used as a diff by virtue of looking at the history pointer. But there are enough footguns that thinking in terms of diffs alone is clearly harmful.
- krupan 3y agoIf you don't like losing branch names then I'm genuinely curious what you think is wrong with Mercurial's solution?
- o11c 3y agoMercurial branches get in the way. Branches should be recorded in commits, not contain or constrain commits. `git` records one side's branch name for merge commits, which is great ... except it doesn't record the other, or record anything for fast-forward or rebase. And what it does record isn't directly machine-readable.
- krupan 3y agoHmm. Are we both talking about Mercurial branches and not maybe bookmarks or something different? It's been a while since I've used mercurial but from what I remember the branch name is recorded as part of the commit? I'm not sure I understand what you mean by containing or constraining or being in the way, either, sorry. If you are rebasing you are modifying history generally to purposefully remove a branch in the DAG. I'm not sure you'd want to keep a branch name in that case?
- 3y ago
- nickm12 3y agoDepending on the context, I definitely think of commits as all three of diff, snapshot, or history. When I'm coding, I think of myself as "authoring a change" and the commit I post for code review, and later rebase, is the change I'm pushing. (but simultaneously the commit I'm developing against is a snapshot!). Once code is pushed, I flip over to "history". At that point, I'm using the commit as an identifier for a release, which generally contains multiple changes. The primary questions at that point are "what's in this release?" and "How does it differ from the previous release?" and mentally I see that as a set of changes rather than a single diff, even though production doesn't care how many commits are in the difference. The unscientific poll excluded "all three". I guess I have to go with "diff" as "most true" but it simply makes no sense when using a commit id to identify what to check out or release.
- p-e-w 3y ago> is “how Git implements it” really the right way to explain it? Of course not, and nowhere outside of software engineering will you find such widespread confusion between concepts and their implementation. Do we think of pressing the gas pedal in a car as "accelerate", or as "regulate the intake manifold"? Commits are one of the most high-level concepts in Git. If an explanation for them resorts to implementation details, it's a bad explanation.
- charcircuit 3y agoI think if it as "regulate the intake manifold" or revving the engine because I feel it makes more sense. I don't really understand the relationship between how much you push the pedal and how much acceleration it produces. I've given up on trying to understand that, so I don't think of it as acceleration.
- ikari_pl 3y agoI'd argue that you intuitively do. When driving, you know when to press it lightly, and when more, as well as what the expected result will be. That would mean, I think, that the implementation details are irrelevant, because it's abstracted well enough to serve its purpose - and it's so easy that usually the FIRST driving lesson takes you into actual traffic (at least in Poland).
- charcircuit 3y agoI disagree. I see it as a control system. I have a target acceleration and I have to change the input to the system to hone in on my target acceleration. I don't intuitively know how to accelerate at 10 mph / s. But by watching a guage I could be the control system that tries to do so.
- kqr 3y agoOr even worse -- regulating the manifold pressute. A resting gas pedal means the engine is suctioning a vacuum in the manifold, whereas a fully depressed pedal means the manifold is restored to atmospheric pressure!
- Joel_Mckay 3y agosnapshots in time where all the bits should work... many small tested changes with people coordinating to keep out of each-others way. Or... a dumpster fire as that one guy we all know breaks the build with a backlog of commits on a Friday... 1 hour before the end of the week. We all meet "that one guy" eventually. =)
- nioj 3y agoLess commented ongoing discussion (currently 1 comment) https://news.ycombinator.com/item?id=38884498 https://news.ycombinator.com/item?id=38884498
- fragmede 3y agoI wonder why that didn't get deduped
- krupan 3y agoWow, I just realized that I've been playing around with git and mercurial for nearly 17 years! And people are still confused about git! That's amazing. I still love that it's distributed, fast, and it handles branches and merges better than anything before it. I do wish the UI was better.
- goku12 3y agoHow often do you use Mercurial, compared to Git? > I do wish the UI was better. The times I use Mercurial, it feels like it manages to abstract away the gory details while still achieving almost everything git does. Mercurial even has queues built-in, whereas Git needs something like stgit or topgit to achieve the same. Would you say that Mercurial meets your expectations?
- krupan 3y agoI wish mercurial had won and we were all using it instead of git. I used hg exclusively from 2009-ish to 2016-ish and I still believe it has the better UI (but not perfect). I will say that git made mercurial better over the years, and quite probably mercurial made got better. It's too bad mercurial has all but died, I think general VCS progress has probably slowed without it.
- devsda 3y agoInteresting but for me reading the article left more questions than it answered. If you are curious about the internals, the referenced blogpost[1] has a detailed explanation of object file reperesentation(s) and I cannot recommend it enough. [1] https://codewords.recurse.com/issues/three/unpacking-git-packfiles https://codewords.recurse.com/issues/three/unpacking-git-pac...
- cerved 3y agoor the git book
- DannyBee 3y agoOne issue with the "diff" model is that in GIT (and most all VCs these days) there is no "one true answer" to the question "how did this old file change to become this new one". Instead, what is stored is "what is the smallest/fastest/simplest way to create new file from old file". (depends on tradeoff) Which is not the same as what you may have actually done to change old file into new one. One result is that the textual representation you see in "diff" is just one interpretation of how the file changed - since it is reconstructing it from first principles. I mention this because the author mention the following positive of the diff mental model: "most of the time I’m concerned with the change I’m making – if I’m just changing 1 line of code, obviously I’m mostly thinking about just that 1 line of code and not the entire current state of the codebase when you click on a Git commit on GitHub or use git show, you see the diff, so it’s just what I’m used to seeing" Of course, you see "a diff", not "the diff", because there is no "the diff". and when you change 1 line of code, the diff may or may not show it as having changed one line of code. It is likely to in most cases because that usually meets the definition of longest common subsequence that common diff algorithms optimize for. But not always. Which leads to interest results when you were thinking about a change one way, but the diff doesn't show what you actually did to the code in your editor :)
- samus 3y agoGit stores states of the repo across time. The diff is something created for the user. Internally, Git might or might store it in an optimized way, but not necessarily.
- dclowd9901 3y agoOk so I think I at least understand now that “git diff” isn’t just showing me some stored information in the repo’s metadata. But still, I can’t reason about how so many changes to a repo can be recorded in a way that’s so efficient that it’s almost imperceptible in time cost. And I’ve yet to see a satisfactory answer to this question. I need concrete examples.
- federiconafria 3y ago
- rtpg 3y agoReading through this and then thinking about rebases in particular.... I think whoever comes up with a good mechanical explanation of rebasing deserves a prize. I just imagine it as "it figures out diffs and then tries to apply them over at another place" but this runs up against reality way too often.
- juped 3y agoHow does this "run up against reality", it is the reality, full stop, not even eliding tricky details. Whatever made you say that is the part of you that's confused here.
- krupan 3y agoIt's not the reality. It is a 3-way merge of each commit you are rebasing, not just applying diffs. Except sometimes when I'm resolving conflicts git mergetool doesn't seem to supply 3 files to kdiff3 (just two) which really really bothers me. Never saw that with Mercurial
- juped 3y agoIt's the reality, it's just applying diffs. The OP's blog actually has an earlier post about how applying diffs uses a 3-way merge; before ort and its more versatile API which can handle just applying diffs, rebase literally used apply machinery.
- krupan 3y agoSorry, when I think of applying diffs I think of using the patch command that literally takes a set of files and a diff and applies the diff to the files. patch doesn't know any history and doesn't do 3-way merges. In my mind a 3-way merge is different than just "applying diffs" I'll look for her post about rebase, it sounds interesting, thanks!
- juped 3y ago
- juped 3y ago> It gets a little weird with merge commits, but maybe you just say it’s stored as a diff from the first parent of the merge. Depending on the specific operation it can act like a diff from any of the parents (though the first is special) or all of them; it's (typically, and the way operations treat it) the result of a three-way merge using the parents and the most recent common ancestor found via graph walking, eliding some complexity. To the author, refer back to your earlier post about three-way merging in this section, perhaps?
- goku12 3y agoThe exact way in which git handles commits is very muddied - it's snapshots on the surface, a bit of diffs when packed and a lot of operations on commits are actually 3-way merges (including merges, rebases, cherrypicks and reverts). Keeping track of all these matter (esp the operations that use diffs), but it can also get overwhelming for a tool. In my opinion, it's probably good enough to understand the model git is trying to emulate. Commits are stored more or less like snapshot copies of the working tree directory with commit information attached. The fact that there is de-duplication and packing behind the scenes is more a matter of trying to increase storage efficiency than of any practical difference from the directory snapshot model. Meanwhile, the more complex git operations (merges, rebases, reverts, etc) use actual diff algorithms and 3-way merges (way more often than you'd imagine) to propagate changes between these snapshots. This is especially apparent in the case of rebases, where the snapshot model falls completely on its side (modifying a commit will cause the same change in all subsequent commits). This actually makes sense if you consider the development workflow of linux kernel before git. Versions were directories or on CVS and a lot of development was based on quilt, diffutils and patchutils. Git covers all these use cases, though it may not be immediately apparent. Added later: It's also interesting to look at Mercurial's model. Like Git, Mercurial uses both snapshot and diffs for storage. But unlike the Git way of layering these two, Mercurial interleaves them - as diffs with full snapshots occasionally. This is more like the video codec concept of keyframes (I think that's what inspired it). This means that Mercurial, unlike Git, doesn't need repacking. And while Git exposes its internal model in its full glory, Mercurial manages to more or less abstract it away.
- nerdponx 3y agoWell-said, although I disagree that it's "muddled". The data model is that commits are snapshots, and diffs between snapshots are computed as needed. The whole system is designed around this. Packing is an implementation detail. The fact that internally it can store snapshots as diffs is more or less unrelated to the user-facing diffs. IMO it's confusing to even mention it in an educational context, except in response to the question of "how does Git prevent repo size from exploding?".
- 3y ago
- OscarCunningham 3y agoIf we don't care about implementation details then isn't it mathematically equivalent to say that a commit is a diff or a snapshot? Each commit knows its parent. So from the diff you can calculate the snapshot, and from the snapshot you can calculate the diff.
- danielheath 3y agoAs it turns out, we care about details like “does diffing two branches show output inside of a week”. Diff-based systems were very slow at constructing a diff between divergent branches.
- OscarCunningham 3y agoSure, but in terms of understanding what to expect git to output, the two points of view should be equally valid.
- nerdponx 3y agoIn a merge commit with 4 parents, what diff does the commit represent?
- OscarCunningham 3y agoThe diff from the first parent. This isn't breaking any symmetry between the parents, since git already treats the first parent as special.
- IshKebab 3y agoYeah I think you're mostly right though the snapshot mental model is definitely simpler IMO. Also there are some behaviours that would make no sense if it was really stored as diffs, e.g. shallow clones. Also the ability to generate diffs between arbitrary commits means the mental model for that involves reconstructing a snapshot for each commit from diffs, and then calculating a diff between those snapshots, which I think is a much more complex thing to understand than the real design, even if it would be technically possible to implement it that way. Good point though!
- strken 3y agoThis feels like a false dichotomy. Is a shadow the absence of light or is it a black blob? Well: both! In a purely physical sense it's the absence of light but in your vision it's a black blob, and these are both true and useful. Given that she wrote a whole post about it the author obviously knows that both are useful, but I'd expect most people to use both frames of reference and switch as necessary rather than picking just one.
- usr1106 3y ago> the merged commit can actually be literally anything That cannot be stressed enough. Years ago a searched for a weird bug and could not find it. Of course I did not look at merge conflicts because "they don't really introduce anything new". But it turned out that a merge commit had introduced an arbitrary line, not related to its parents. Also the opposite is true: You can make a conflict free merge of two correct parents and the result is broken code. It does not seem to happen very often in real life, but it's a risk one should be aware of. I wonder how many merge commits there are in the Linux source tree that introduce something new by conflict resolution or break something existing without conflict resolution involved. At work we are a small enough organization that we don't really merge, all our merges are fast-forward. But that means you move the risks above to rebasing.
- jahnu 3y ago> You can make a conflict free merge of two correct parents and the result is broken code. It does not seem to happen very often in real life, but it's a risk one should be aware of. Correct and I would say even more than that; in a system more than minimal complexity you need to run your tests on your branch with main merged into it before you merge your branch into main. Too often CI is set up to only test HEAD of the new branch.
- layer8 3y agoYes! It is driving me insane that this is not the default setup. If you do the merge of main into the branch yourself, there is a race condition where by the time the tests are completed and you want to merge the branch into main, main has changed again, so you have to repeat. Exactly because of that it would be nice if CI guaranteed a correct sequencing of merging and testing.
- IshKebab 3y agoYou need to use a merge queue (aka merge train). It should be completely standard at this point (though it unfortunately isn't). Doesn't help that it's a Gitlab Premium feature.
- kelnos 3y agoA git commit is a change from one state of the repository to another. A change is a diff, because... that's what a diff -- difference -- is, by definition. So a commit is a diff. (However, the reverse is not true: a diff is not a commit! A diff can be a commit, but a diff can also be a representation of a series of commits, or something else entirely.) A git tree is a snapshot. A snapshot is, by definition, a view of the world at a point in time. A commit doesn't show you the world: it only shows you what's changed between the previous world and the next world. The state of the tree -- a checkout that comprises all the files in a project, at a particular time, is a snapshot. I guess I can see how a commit might be confused for this: you can check out a tree at a particular commit, and that would be a snapshot. But the commit is not the tree! The commit is not the snapshot! You could also look at it this way: you are not checking out a commit; you are checking out a tree that happens to be identified by the ref that points to a commit. (Technically that's not even the case, or rather it is, but only coincidentally: while we can check out trees by giving git a commit ref, in reality the tree itself has a different object name.) To relate the two paragraphs above, a commit is the description of the change between two different trees (aka snapshots). Note that I am deliberately ignoring how git actually implements these things, as I don't think git's implementation is remotely useful as a mental model. Consider: git implements commits as snapshots, but is your mental model of "making a commit" that you make a fresh, empty directory, and then retype all your code from scratch, but with the changes you want to make in the commit? No, of course not, that's nonsense. (Ok, maybe that's too extreme, but I think it's still nonsense to think about it as making a copy of your repository, making your changes to the copy, and then storing the entire new copy.) A (single) commit is sort of a history, but not really in a useful sense. To me, history is a progression over time. Sure, a single commit gives you the "history" (meh) of a single change, over a short period of time. But when I think of my "git history" or my "commit history", I'm thinking about a series of changes (commits) over some longer period of time. Like "the list of commits between these two tags show the history of changes between these two releases", or, more generally, "all the commits on the main branch show the entire history of the project". > is “how Git implements it” really the right way to explain it? No, I don't think so. Implementation details (in the general sense, not specific to git) often don't represent the mental model that's most useful for understanding a system. Git is a little interesting in that it actually is a lot easier to understand how to use git and be productive using git if you understand a bit about its implementation. But that doesn't mean your mental model of a version control system should depend on implementation details.
- mikewarot 3y agodiff model - considered harmful For me, the incongruity between the way git was supposed to work, based on the idea that it stored deltas, and actual observed behavior was maddening. More than once I completely ripped out a git repo just so I could get around the stupid merge conflicts I would end up with on a single user project. We should always teach that git stores snapshots, and shows diffs as a convenient fiction for the user.
- kelnos 3y agoI suppose that depends on what matters to the user. I'm not trying to deny you your experience, but I don't think (in 15+ years of use) that knowing that git stores snapshots (and not diffs) has ever really made much of a difference to me. A commit to me is still a diff. When I commit something, conceptually -- to me, at least -- I'm storing a change, not a new snapshot. Because I didn't create a new empty directory on my hard drive and then retype everything, in the new state that I wanted. I took the existing code and modified it to the new state. How git stores that is not relevant to what I actually did.
- Karellen 3y agoOK, but if you do some work, and make a backup with `tar -cf ../.tars/backup-001.tar .`, then do some more work, and make another backup with `tar -cf ../.tars/backup-002.tar .`, then you also didn't create a new empty directory and retype everything, but you'd still be storing snapshots, not changes. (Which is also one way to think about how git conceptually handles it.)
- mikewarot 3y agoI often had "merge conflicts" which I didn't know how to resolve. I thought I had to undo any changes before the delta could be applied. I've wasted more energy and effort as a result, than I like to think about. Had I known I could just force a new snapshot, I wouldn't have had to nuke the .git folder and it's contents to start a new repo, trash the GitHub copy, and start it over, etc.
- deleted 3y ago[deleted]
- ahepp 3y agoIs “both” an option? The guy who invented git uses it to serialize code as diffs over email, so I think that speaks for itself. At the same time, merge commits basically insist on being understood as snapshots. My understanding is that for efficiency and performance, what’s under the hood is a little bit of both.
- infensus 3y ago>The guy who invented git What an inefficient way to spell Linus
- dncornholio 3y agoIt feels like OP is a bit stuck in their own preconceptions? I almost feel offended when I read: > I feel like there’s a whole very coherent “wrong” set of ideas you can have about git I feel like there's much opportunity missed where they could dive into git and figure out the concepts themself. Too much talk about what should and could left me an unsatisfied reader.
- TrianguloY 3y agoOne thing to explain git that I think it's highly useful for beginners (but I haven't been able to prove it) is to explain that commits are basically "project (copy)" folders that people without git create to "save". Then you can explain that git saves them in a highly efficient format (even better than zipping them) and allows to fast operations like comparing.
- globular-toast 3y agoI've slowly come to realise that many (perhaps even a majority as the blog suggests) think of commits as diffs. This is strange to me. You know that "report-v2-021119-final.doc" thing you see from people who don't use git? That's version control. That's all git is doing, except it gives you commit hashes, messages and tags instead of ad hoc filenames. Diffs only come into play during rebases and cherry picking. Otherwise you can and should think of them as snapshots. But not because that's how git implements it. That is indeed irrelevant. You should think of them as snapshots because that's what they are. Because git is version control.
- layer8 3y agoThis is like asking if you think of a DAG as nodes, edges, or paths. It’s all just different aspects of the same thing. This is also not specific to Git, all VCSs have that same duality (triplity?), and just different terminology for what they call a node (revision, changeset, whatever).
- jillesvangurp 3y agoThe terminology here is a bit muddled. Git commits represent a merkle tree of commits where the each commit describes changes to a graph of objects (aka files and directories) represented by the ancestor commit (or commits in case of a merge). In the case of a merge, the commit includes conflict resolutions for any lines modified by multiple ancestors. The way that is stored internally with binary deltas is clever and interesting but not all that relevant to end users. It's convenient that it's compact and fast. But otherwise it's just an implementation detail. From the outside, each commit basically represents a snapshot of the whole system. And that's exactly what you get when you check one out. It's the fluff in the git porcelain and various Git UIs that muddle the waters by giving us different tools to produce new commits, stashes, staging, tools for flaging and resolve conflicts (two commits modifying the same thing), rebasing, squashing, etc. That's where diffs, git patches, merge algorithms and other tools come in. Some of that is part of git. And some of it can be added via third party tools, uis, etc. Or even git alternatives that work in a compatible way. But in the end they just help you produce a new git commit. Most of us just use the stuff that comes with Git and our IDEs. And of course it doesn't help that most git users have not read the manual section on the Git internals, have a poor understanding of how all this works, and generally only know about and use a small fraction of the git commands and options. It's a complicated tool. And it undeniably works very well for extremely large open source communities.
- deleted 3y ago[deleted]
- ghusbands 3y ago> where the each commit describes changes to a graph of objects You're propagating misinformation, in this sentence. Each commit describes a complete snapshot and the previous snapshot. You do at least describe it correctly later.
- deleted 3y ago[deleted]
- dboreham 3y agoI think the next useful development in SCCS will be to not store/process text but instead some sort of AST type structure representing the code. This should allow more intelligent handling of history, merges, refactoring, code review than is currently achievable.
- choeger 3y agoThat's a very old idea that never really worked. There are two main objections against that concept: * Any tree structure would be highly language-specific. Your VCS wouldn't support experimental or new or propietary languages. Even worse, for most real languages, operations like refactoring require not a concrete or simple abstract syntax tree but some transformed or enriched (e.g., with type information) variant that is highly specific to the tool that performs the operation (think Eclipse internal tree structures). Language servers might help here, but they're far from the only implementation. * In practice, if I have a textual diff and a tool that can generate the required tree, I can always apply that tool to the textual representation, just paying a little bit of compute. Compute is cheap.
- keybored 3y agoI think this idea is a dead end. The Git model is already good for decently large and long-running projects like Linux (although not giant corporation monorepos). So the version control problem is solved both for all past and future languages which are textual. But with an AST system you make the storage itself much more opinionated. Java and C ASTs are different, surely? So then the same storage can’t be used directly. I have also thought that these ideas that you bring up could be built on top of Git. So Git solves the primitive task of storing code in a completely unopiniated way—doesn’t matter if “the tests pass” or whatever. Then what you propose lies on top of that primitiveness.
- bigkm 3y agoMy answer is Yes.
- deleted 3y ago[deleted]
- zen928 3y agoI think it's an error to conflate the history of commits to being the "history" of the repository, simply because you're putting an assumed expectation that each commit represents a progression from the previous to illustrate: I could create 10 different small commits from a list of unstaged changes that follow a pattern of progression, I could create 3 commits that group properties (e.g. "added interface and implementation -> lint -> add tests"), I could do all of this in a single commit, but none of those represent the reality that none of these commits werent done as the work was done and that the commits were arranged after the fact to conform to a personal standard that has nothing to do with timeline objectivity. it's not a history of anything other than of how the committer decided to layer their changes.
- seba_dos1 3y ago> I think wrong mental models are often extremely useful, and this one doesn’t seem very problematic to me for every day Git usage. In my experience of helping people with Git, this mental model is usually the main source of their every day confusion. It used to confuse me as well in the past before I realized that mental model was wrong. So yeah, I find it quite problematic.