10 ms·
To add to this, Submodules are a hack on Git's data model. Git's data model, put simply, is this: * Branches are pointers to Commit objects * Commit objects
by AceJohnny2 3y ago
To add to this, Submodules are a hack on Git's data model.
Git's data model, put simply, is this:
* Branches are pointers to Commit objects
* Commit objects are a composite of {Commit_Comment, Tree, Parent Commit(s)}, referenced by the hash of that set
* a Tree (like a directory) is a list of Blobs and/or Trees (associating filenames with them) referenced by the hash of its contents.
* a Blob is a file, referenced by the hash of its contents.
So the set of types of objects in Git are: Commits, Trees, and Blobs.
Note that I said that a Tree can contain other Trees or Blobs... but what if... you put a Commit in it!?
That's a submodule!
Now if the Commit you reference doesn't exist in the current repo, Git can't do anything with it. That's where the .gitmodules file comes in, to associate a given path with a repo, so that Git can look up the Commit object in that repo.
- masklinn 3y ago> Branches are pointers to Commit objects Nit: the data model has refs, which are pointer to objects. Branches are the subset of refs in the special-cased heads/ namespace which should be pointing to commit objects. And there’s also tags, which are the subset of refs in the special-cased tags/ namespace, which should be pointing to commit (“lightweight”) or tag (“annotated”) objects.
- AceJohnny2 3y agoAbsolutely. Going further, the little-known git-notes [1] feature also uses its own reference namespace, `refs/notes/` Going even further, Gerrit [2] leverages the wide-open reference namespace/directories to create its own. For example, pushing under the `refs/for/` namespace creates a new review, and specific reviews can be looked up under the `refs/changes/` namespace. Even even further, Gerrit's special repos All-Users.git and All-Projects.git are "databases" for project configuration and user configuration, where for example external IDs (like usernames) are stored under the special `refs/meta/external-ids` ref/branch. This has the notable benefit that all configuration changes are tracked and auditable. I believe git-appraise [3] also leverages special reference namespaces in Git for performing its review duties (but I don't know details) Edit: actually no, it "just" leverages git-notes. [1] https://git-scm.com/docs/git-notes https://git-scm.com/docs/git-notes [2] https://gerrit-review.googlesource.com/Documentation/note-db.html https://gerrit-review.googlesource.com/Documentation/note-db... [3] https://github.com/google/git-appraise https://github.com/google/git-appraise
- masklinn 3y agoGitHub also leverages refs, for each PR there are two magical refs in refs/pull/<number>/ which point to the PR’s head and its prospective merged head
- colejohnson66 3y agoSo, one could theoretically "embed" an older commit into their repository as a pointer (submodule folder)? And because Git knows what that commit ID means it will show it fine?
- AceJohnny2 3y agoUnfortunately no, because of how it's a hack, and so extra logic had to be tacked on to support it (logic which the `git submodule` command implements). I tried it out, and the local commit object just appears as an empty folder. To try for yourself, do this: git init recursive-submodule && cd recursive submodule echo "foo" > file1 && git add file1 && git commit -m "Add file1" # this will have created an initial commit with hash 2d49d729. Then: git update-index --add --cacheinfo 160000 2d49d729fe39d1def8ce537d7efeeabbf3efb4f2 submodule && git commit -m "Add submodule" The `update-index` command is the plumbing command for adding an arbitrary object, which I used to add the previous commit object. Since we only updated the index and not the workspace, git will note that the submodule is missing. You can then run `git restore .` to set the workspace to the state the history says (ie with the missing submodule)... but that just creates an empty directory. Vanilla git won't try much further. To actually populate the submodule requires running `git submodule update --init`, and that requires a `.gitmodules` file, even for a local commit object. (To learn more about plumbing commands like update-index, look at the Git Book chapter on Internal Git Objects: https://git-scm.com/book/en/v2/Git-Internals-Git-Objects https://git-scm.com/book/en/v2/Git-Internals-Git-Objects )