5

Where can I see the gitlink entry mentioned in gitsubmodules(7)?

For a submodule with working directory at path/to/bar/, the gitlink entry should be located at /path/to/bar and contain the SHA-1 hash of the submodule's commit?

$ git submodule status
 139dedcb98fca8fb69d70305709783ff40316cd4 tabulous (0.5.0-2-g139dedc)
 24afe922e6a05891756ecf331f39a1f6743d3d5a vim-repeat (v1.2-9-g24afe92)
 f51a26d3710629d031806305b6c8727189cd1935 vim-surround (v2.1-18-gf51a26d)
$ ls -la tabulous/
total 72
drwxr-xr-x  8 nlykkei  staff   256B Apr  5 17:25 ./
drwxr-xr-x  5 nlykkei  staff   160B Apr  4 12:00 ../
-rw-r--r--  1 nlykkei  staff    67B Apr  4 12:00 .git
-rw-r--r--  1 nlykkei  staff    21B Apr  4 12:00 .gitignore
-rw-r--r--  1 nlykkei  staff    18K Apr  4 12:00 LICENSE
-rw-r--r--  1 nlykkei  staff   5.0K Apr  5 17:25 README.md
drwxr-xr-x  4 nlykkei  staff   128B Apr  5 17:25 doc/
drwxr-xr-x  3 nlykkei  staff    96B Apr  5 17:25 plugin/
$ cat tabulous/.git
gitdir: ../../../../../.git/modules/vim/pack/bundle/start/tabulous

man 7 gitsubmodules:

   ...
   Assuming the submodule has a Git directory at $GIT_DIR/modules/foo/ and a working directory at path/to/bar/, the superproject tracks the submodule via a gitlink entry in
   the tree at path/to/bar and an entry in its .gitmodules file (see gitmodules(5)) of the form submodule.foo.path = path/to/bar.

   The gitlink entry contains the object name of the commit that the superproject expects the submodule's working directory to be at.
Shuzheng
  • 11,288
  • 20
  • 88
  • 186

2 Answers2

3

Git records the commit id for added submodule content the same way it records the blob id for added file content, as an id, listed in the index or a recorded tree. That's a gitlink: your content is in another commit, that you can check out at that path if you want. The git submodule helper command helps you hunt down and wrangle a repo that has that commit but it's nothing more than helpers, a grab bag of arbitrary names for handy little one-to-five-liners you'd otherwise wind up writing yourself.

git rev-parse @:tabulous      # HEAD commit entry: "the current checkout had this here"
git rev-parse :tabulous       # index entry, "last thing added or checked out here"

git -C tabulous rev-parse HEAD   # what's actually checked out here

and you can of course do any of the further checks normally, a lowlevel version for tracked content is

git -C tabulous diff-index --quiet --cached @ || echo staged changes in tabulous
git -C tabulous diff-files -q                 || echo unstaged changes in tabulous

I don't know a one-command quick "any untracked content at all" check, I think you still need ls-files and some scaffolding for that, e.g.

stdbuf -oL git -C tabulous git ls-files --exclude-standard -o  | grep -q . \
&& echo untracked, unignored files in tabulous

stdbuf -oL git -C tabulous git ls-files --exclude-standard -oi | grep -q . \
&& echo untracked, ignored files in tabulous

(the stdbuf -oL part only matters in Really Big Work Trees where it's worth keystrokes to avoid walking enough of it to find a whole buffer full of names)

Note that individual directories exist as objects in the object db but not in the index, writing new ones every time anything they contain changes is one of the things the index is there for, to not splatter new trees for every change, but it can help to stay aware of that when you're writing scripts: if "tabulous" in your example is just a directory and not a submodule, it won't have its own index entry (because keeping that id up to date would be one of the needless overheads the index exists to avoid).

jthill
  • 55,082
  • 5
  • 77
  • 137
  • Thank you. Isn't the documentation wrong to say *gitlink entry in the tree at `path/to/bar`*? Your explanation of a *gitlink* differs from that. – Shuzheng Apr 06 '21 at 07:07
  • Consider the output of `git ls-tree -rd`: `160000 commit 139dedcb98fca8fb69d70305709783ff40316cd4 vim/pack/bundle/start/tabulous`. Is "commit" a synonym for "submodule"? I.e. `git` knows the object ID refers to a submodule, because of its type "commit" (or can "commit" mean other things that "submodule"?) – Shuzheng Apr 06 '21 at 07:54
  • It doesn't matter what you call it or whether you use the `git submodule` helpers. What that entry is, is a commit id. That's what "gitlink" refers to: an entry that holds a commit id rather than a blob or nested tree id. But its still the id that was recorded for, added at, that path. It's what should be there to make the work tree match the committed content. – jthill Apr 06 '21 at 16:37
0

Although it's been a year and a half, I happen to be able to answer this question. :)

What is gitlink entry?

Basically, it's a record for the superproject to remember the commit of submodule.

Where is gitlink entry?

From the DESCRIPTION:

the superproject tracks the submodule via a gitlink entry in the tree at path/to/bar

It's an entry which means literally it's an item of a list.

So, this tree mentioned above is the tree of the superproject where the gitlink entry resides in.

In Git, tree is a snapshot of a directory (Aka a list).

An simple experiment to find gitlink entry

➜  hustnzj git init super
Initialized empty Git repository in /hustnzj/super/.git/
➜  hustnzj cd super
➜  super git:(main) git init sub
Initialized empty Git repository in /hustnzj/super/sub/.git/
➜  super git:(main) ✗ cd sub
➜  sub git:(main) touch 1
➜  sub git:(main) ✗ git add 1
➜  sub git:(main) ✗ git commit -m 'first'
[main (root-commit) a1a76ac] first
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 1
➜  sub git:(main) ..
➜  super git:(main) ✗ git status
On branch main

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)
    sub/

nothing added to commit but untracked files present (use "git add" to track)
➜  super git:(main) ✗ git submodule add ./sub sub
Adding existing repo at 'sub' to the index
➜  super git:(main) ✗ git status
On branch main

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
    new file:   .gitmodules
    new file:   sub

➜  super git:(main) ✗ git commit -m 'add submodule'
[main (root-commit) d48efa0] add submodule
 2 files changed, 4 insertions(+)
 create mode 100644 .gitmodules
 create mode 160000 sub
➜  super git:(main) git cat-file commit main
tree 32d1e97cda3fc75ad358b18a7c938fccc3be2a88
author hustnzj hustnzj@example.com 1663992891 +0800
committer hustnzj hustnzj@example.com 1663992891 +0800

add submodule
➜  super git:(main) git ls-tree 32d1e97
100644 blob c489803d5bdec1755f650854fe7ef5ab7a3ee58d    .gitmodules
160000 commit a1a76ac0bc49478d5bce1b1b598dc6c290c28003  sub

Notice the 160000 mode for the sub entry. That is a special mode in Git that basically means you’re recording a commit as a directory entry rather than a subdirectory or a file.

To check if the a1a76ac0bc49478d5bce1b1b598dc6c290c28003 commit is the commit of sub submodule:

super git:(main) git -C sub rev-parse HEAD
a1a76ac0bc49478d5bce1b1b598dc6c290c28003

If you pay attention to the output above when you added the submodule into your superproject as a submodule, you should see the 160000 mode.

And you find this clear explanation of 160000 in here.

160000: A gitlink, SHA-1 of the object refers to a commit in another repository. Git links can only be specified by SHA or through a commit mark. They are used to implement submodules.

hustnzj
  • 525
  • 6
  • 13