0

How do I show only untracked subdirectories that are git repos? Do I use git diff, git status, or git ls? What options do I use?

The closest thing I could find is:
git diff --name-only --diff-filter=M
but that shows modified, not untracked. And it shows files.

I'm looking for something like:

$ git init .
Initialized empty Git repository in /tmp/my-dir
$ touch my-file
$ git add my-file
$ git commit -m 'init'
[master (root-commit) 3f18576] init
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 my-file
$ echo changed >> my-file
$ mkdir sub-repo
$ cd sub-repo
$ git init .
Initialized empty Git repository in /tmp/my-dir/sub-repo/.git/
$ touch my-file-sub-repo
$ cd ..
$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
    modified:   my-file

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

$ git # diff? What options?
my-dir

(Related: I don't know how git is treating these "sub-repos" but would like to understand. Maybe git is considering them as git submodules, even though I never explicitly ran any git submodule commands?)

Rob Bednark
  • 25,981
  • 23
  • 80
  • 125
  • 1
    Git knows nothing about "directories" so there is no such thing as a tracked or untracked directory. Git doesn't track directories. Git doesn't store directories. A commit doesn't contain directories. Git deals in commits. Commits contain files. So Git tracks _files_. So can you express the question in terms that make sense for Git? What do you really want to know? – matt Sep 11 '22 at 15:24
  • if a 'untracked' directory has 'untracked' files, git will show them with status. it can also show a list of all 'tracked' files, so you can script around it to look for 'untracked' directories. – Serge Sep 11 '22 at 17:25
  • Thanks @matt . Aha. I realized that the directories I'm referring to contain repos themselves. I've updated my question to reflect that. They are not submodules. I'm not sure how git treats "sub-repositories". I did some searching but came up empty. – Rob Bednark Sep 11 '22 at 18:42
  • "They are not submodules". I don't believe that. You cannot put a folder containing a _.git_ folder inside _another_ folder containing a _.git_ folder except as a submodule. It would be incoherent otherwise. – matt Sep 11 '22 at 19:18
  • @matt I never explicitly ran any `git submodule` commands to add a submodule, and running `git submodule` alone shows no existing submodules. As indicated in my example, all I did was `git init` in a subdirectory. I'm not really familiar with submodules, so I may be missing something. If you run my commands above, do you get any submodules? – Rob Bednark Sep 13 '22 at 14:26
  • The point is that if you put a git folder inside a git folder and you _don't_ make submodules, you've got an incoherent situation. Basically I'm saying do _not_ do what you're doing in the first place. – matt Sep 13 '22 at 14:36
  • Ah, that helps @matt. What do you mean by "incoherent situation"? – Rob Bednark Sep 16 '22 at 14:08
  • Try reading https://stackoverflow.com/a/73725600/341994 – matt Sep 16 '22 at 14:14
  • Wow, that answer is exactly what I'm looking for -- thanks @matt ! ⭐️ – Rob Bednark Sep 18 '22 at 14:03

1 Answers1

1

hmm. Okay, from the rewrite it seems what you want is the nested work trees or repositories that aren't tracked?

(
echo .git
git ls-files -s | sed -n '/^16/s,[^\t]*.,,p'
find -mindepth 1 -type d \( \
    \( -exec test -d {}/objects -a -d {}/refs -a -f {}/HEAD \; -prune -printf %P\\n \) \
 -o \( -exec test -e {}/.git \; -prune -printf %P\\n \) \)
) | sort | uniq -u

====

but the original question, showing all directories containing no tracked files, is also interesting, so here's what I had for that:

Git's flexible, arguably (though I'd disagree strongly) flexible to a fault, about where repositories and their work trees can reside, to the point where it's possible for a trolling guru to make it impossible to tell, but if we rule out such hopefully-playful malice it's down in fiveliner range.

All directories that contain files tracked in the current checkout anywhere underneath:

git ls-files \*/* \
| awk '{while(sub(/\/[^/]*$/,""))if(!seen[$0]++)print;else break}'

All directories that could contain tracked files:

find -mindepth 1 -type d \( \
      \( -exec test -d {}/objects -a -d {}/refs -a -f {}/HEAD \; -prune \) \
   -o \( -exec test -e {}/.git \; -prune -printf %P\\n \) \
   -o -printf %P\\n \)

And then just look for un-duplicated entries:

( git ls-files \*/* \
  | awk '{while(sub(/\/[^/]*$/,""))if(!seen[$0]++)print;else break}'

  find -mindepth 1 -type d \( \
      \( -exec test -d {}/objects -a -d {}/refs -a -f {}/HEAD \; -prune \) \
   -o \( -exec test -e {}/.git \; -prune -printf %P\\n \) \
   -o -printf %P\\n \)
) | sort | uniq -u

====

jthill
  • 55,082
  • 5
  • 77
  • 137