33

I have a project with the following folder structure:

All the project files are in base_fldr folder. Also I have a few folders inside base_fldr called sub_fldr1 and sub_fldr2. These sub folders also contain some files.

If I modify any of the files inside my base_fldr or base_fldr\sub_fldr\ then git status shows them as modified. Also if I add a new file to base_fldr, git status will show it as untracked file.

My problem is if I add a new file inside base_fldr\sub_fldr\ then the git status doesn't show the file as untracked. It won't even give any info about the file.

The file or its extension is NOT in my .gitignore list. Also I did try git add sub_fldr\file_name but neither it gave an error nor it add the file to index.

Any idea what's happening here? Thanks!

kriver
  • 1,316
  • 2
  • 15
  • 32

7 Answers7

25

I figured out what was going wrong. Basically the first line in my .gitignore file is "*/". This causes any file added to sub directory being ignored by git status command. But the funny thing was if I modify any files in sub folder, git status correctly shows them as modified as the file is already in git repository, but was ignoring new files in sub folder.

I fixed my issue by removing the line in .gitignore file to not ignore changes in sub folders, then added the new files to index and then again added back the line in .gitignore so that it will ignore any generated files in subfolders.

Thanks all for the responses.

kriver
  • 1,316
  • 2
  • 15
  • 32
  • 4
    The same thing happened to me and I finally realized I'd actually already added the folder name I created to the .gitignore file months ago for no apparent reason! But +1 for this answer making me check it ;-) ... and -1 for me for searching StackOverflow before even checking that first – PandaWood Nov 26 '11 at 23:39
  • 2
    The command, for a completeness sake: `git status -u --ignored` – Victor Sergienko Apr 17 '19 at 18:55
15

I ran into a similar issue with missing tracked files. While experimenting with ways to manage locally modified versions of tracked files without having to constantly avoid accidental commits, I ran the following:

git update-index --assume-unchanged my-tracked-file-that-is-awol

I ended up scrapping this idea, but forgot to undo the command, so subsequent changes to this and other --assume-unchanged files were completely missing from:

git status -u --ignored

It took me a while to figure out what was going on, but I simply had to reverse the command with:

git update-index --no-assume-unchanged my-tracked-file-that-is-awol
mveerman
  • 33,863
  • 3
  • 19
  • 14
15

This is likely because your base_fldr\sub_fldr\ directory is untracked, if you run:

git add base_fldr\sub_fldr\

From within your working copy root, it will automatically add the directory and other files and directories within that directory as well.

By default, git will not show files within directories that are untracked.

Highway of Life
  • 18,392
  • 14
  • 43
  • 68
  • The OP says that modified files inside `sub_fldr` *are* shown in `git status`. – Greg Hewgill Jan 06 '11 at 00:23
  • My base_fldr\sub_fldr\ is tracked. Actually if I modify an existing file git status correctly shows the file inside sub_fldr as modified. – kriver Jan 06 '11 at 01:09
8

Do you have a .git subdirectory inside your sub_fldr directory? Git may think you're trying to use submodules.

Greg Hewgill
  • 828,234
  • 170
  • 1,097
  • 1,237
6

In order to debug an issue like this, see if your .gitignore file is the culprit by observing the following two outputs

See https://git-scm.com/docs/git-ls-files

  1. git ls-files --other --directory --exclude-standard

This will show all untracked files, while obeying the .gitignore file.

  1. git ls-files --other --directory

This will show all untracked files, without obeying the .gitignore file.

Whichever files are present in output of 2, but are not present in output of 1, are not shown in untracked because of some flag in your .gitignore file

user13107
  • 2,719
  • 4
  • 29
  • 48
2

Here is another cause of the behavior described in this question (git status untracked files list doesn't include an untracked file in a sub-folder). If the file is untracked because of a .gitignore file in the sub-folder then the file won't be included in the git status untracked files list.

user969350
  • 21
  • 1
0

Since 2011, this was fixed for the first time with Git v1.8.3-rc0 (April 2013).
It fixes a handful of issues in the code to traverse working tree to find untracked and/or ignored files, cleans up and optimizes the codepath in general.

See commit 0aaf62b, commit defd7c7, commit 8aaf8d7, commit b07bc8c, commit 95c6f27, commit 6cd5c58, commit 46aa2f9, commit 5bd8e2d, commit be8a84c, commit c94ab01, commit 184d2a8, commit 0104c9e, commit 289ff55, commit 560bb7a (15 Apr 2013) by Karsten Blees (kblees).
(Merged by Junio C Hamano -- gitster -- in commit 7093d2c, 23 Apr 2013)

dir.c: make 'git-status --ignored' work within leading directories

Signed-off-by: Karsten Blees

'git status --ignored path/' doesn't list ignored files and directories within 'path' if some component of 'path' is classified as untracked.

Disable the DIR_SHOW_OTHER_DIRECTORIES flag while traversing leading directories. This prevents treat_leading_path() with DIR_SHOW_IGNORED flag from aborting at the top level untracked directory.

As a side effect, this also eliminates a recursive directory scan per leading directory level, as treat_directory() can no longer call read_directory_recursive() when called from treat_leading_path().


But, 6 years later (late 2019), with Git 2.25 (Q1 2020), an assorted fixes to the directory traversal API... revert that very fix seen above, and re-implement it.

See commit 6836d2f (20 Dec 2019) by Junio C Hamano (gitster).
See commit c847dfa, commit 777b420, commit b9670c1 (19 Dec 2019), and commit c5c4edd, commit 072a231, commit 2f5d384, commit a2b1336, commit 452efd1 (10 Dec 2019) by Elijah Newren (newren).
(Merged by Junio C Hamano -- gitster -- in commit d2189a7, 25 Dec 2019)

Revert "dir.c: make 'git-status --ignored' work within leading directories"

Signed-off-by: Elijah Newren

Commit be8a84c52669 ("[dir.c](https://github.com/git/git/blob/a2b13367fe55bdeb10862f41aff3e2446b63e171/dir.c): make 'git-status --ignored' work within leading directories", 2013-04-15, Git v1.8.3-rc0 -- merge) noted that

git status --ignored <SOMEPATH>

would not list ignored files and directories within <SOMEPATH> if <SOMEPATH> was untracked, and modified the behavior to make it show them.

However, it did so via a hack that broke consistency; it would show paths under <SOMEPATH> differently than a simple

git status --ignored | grep <SOMEPATH>

would show them.

A correct fix is slightly more involved, and complicated slightly by this hack, so we revert this commit (but keep corrected versions of the testcases) and will later fix the original bug with a subsequent patch.

Some history may be helpful:

A very, very similar case to the commit we are reverting was raised in commit 48ffef966c76 ("ls-files: fix overeager pathspec optimization", 2010-01-08, Git v1.7.0-rc0 -- merge); but it actually went in somewhat the opposite direction.

In that commit, it mentioned how

git ls-files -o --exclude-standard t/

used to show untracked files under t/ even when t/ was ignored, and then changed the behavior to stop showing untracked files under an ignored directory.

More importantly, this commit considered keeping this behavior but noted that it would be inconsistent with the behavior when multiple pathspecs were specified and thus rejected it.

The reason for this whole inconsistency when one pathspec is specified versus zero or two is because common prefixes of pathspecs are sent through a different set of checks (in treat_leading_path()) than normal file/directory traversal (those go through read_directory_recursive() and treat_path()).

As such, for consistency, one needs to check that both codepaths produce the same result.

Revert commit be8a84c526691667fc04a8241d93a3de1de298ab, except instead of removing the testcase it added, modify it to check for correct and consistent behavior.

And:

dir: fix checks on common prefix directory

Signed-off-by: Elijah Newren

Many years ago, the directory traversing logic had an optimization that would always recurse into any directory that was a common prefix of all the pathspecs without walking the leading directories to get down to the desired directory.

Thus,

git ls-files -o .git/                        # case A

would notice that .git/ was a common prefix of all pathspecs (since it is the only pathspec listed), and then traverse into it and start showing unknown files under that directory.

Unfortunately, .git/ is not a directory we should be traversing into, which made this optimization problematic.

This also affected cases like:

git ls-files -o --exclude-standard t/        # case B

where t/ was in the .gitignore file and thus isn't interesting and shouldn't be recursed into.

It also affected cases like:

git ls-files -o --directory untracked_dir/   # case C

where untracked_dir/ is indeed untracked and thus interesting, but the --directory flag means we only want to show the directory itself, not recurse into it and start listing untracked files below it.

The case B class of bugs were noted and fixed in commits 16e2cfa90993 ("read_directory(): further split treat_path()", 2010-01-08) and 48ffef966c76 ("ls-files: fix overeager pathspec optimization", 2010-01-08, Git v1.7.0-rc0 -- merge), with the idea being that we first wanted to check whether the common prefix was interesting.

The former patch noted that treat_path() couldn't be used when checking the common prefix because treat_path() requires a dir_entry() and we haven't read any directories at the point we are checking the common prefix.

So, that patch split treat_one_path() out of treat_path().

The latter patch then created a new treat_leading_path() which duplicated by hand the bits of treat_path() that couldn't be broken out and then called treat_one_path() for the remainder.

There were three problems with this approach:

  • The duplicated logic in treat_leading_path() accidentally missed the check for special paths (such as is_dot_or_dotdot and matching ".git"), causing case A types of bugs to continue to be an issue.
  • The treat_leading_path() logic assumed we should traverse intoanything where path_treatment was not path_none, i.e. it perpetuated class C types of bugs.
  • It meant we had split logic that needed to kept in sync, running the risk that people introduced new inconsistencies (such as in commit be8a84c52669, which we reverted earlier in this series, or in commit df5bcdf83ae which we'll fix in a subsequent commit)

Fix most these problems by making treat_leading_path() not only loop over each leading path component, but calling treat_path() directly on each.

To do so, we have to create a synthetic dir_entry, but that only takes a few lines.

Then, pay attention to the path_treatment result we get from treat_path() and don't treat path_excluded, path_untracked, and path_recurse all the same as path_recurse.

VonC
  • 1,042,979
  • 435
  • 3,649
  • 4,283