I must probably have unknowingly mispunched some keys and triggered a strange change in the state of my local git repository, for now git is refusing to track some files. That is :
If I do git add -f myfile.txt
, it executes and returns silently but after that git ls-files -v myfile.txt
still returns nothing when it should return myfile.txt
, and git status
still says nothing to commit
.
Someone suggested that problem might have to do with some filenames being too long, so I tried git config core.longpaths true
followed by git add .
and git add -A
.
And yes, I did check that the file exists and the path is correct : file myfile.txt
tells me it's an ASCII text.
What other git commands may I use to get a better understanding of the situation ?
UPDATE : In the output of git ls-tree -r HEAD
, my file is listed , albeit with a slight modification : what I called myfile.txt
above for short is really a long file path with several directories. The corresponding entry in git ls-tree -r HEAD
is an identical path except that the first directory is uncapitalized (I and the Unix system call it Depth_one
but git calls it depth_one
).
CodePudding user response:
TL;DR summary: the root issue here is case-folding. You may wish to convince Git to rename all the files. (Files in Git's index, AKA staging area, are not in folders, they just have long names that seem to have folder-names embedded within them. The names you need to change are therefore all the ones that start with the lowercase "folder" string.) Alternatively, make your working tree match the Git commits: in Git, file names are case sensitive.
Long, with reproducible example
UPDATE : In the output of
git ls-tree -r HEAD
, my file is listed , albeit with a slight modification : what I calledmyfile.txt
above for short is really a long file path with several directories. The corresponding entry ingit ls-tree -r HEAD
is an identical path except that the first directory is uncapitalized (I and the Unix system call itDepth_one
but git calls itdepth_one
).
This, and the fact that you are on macOS—or at a lower level, using a case-insensitive file system—are the key items. I was able to reproduce your issue on my own Mac, although perhaps with a slightly different reproducer. (This sort of thing is why a Minimal Reproducible Example is so important here. Simplifying a problem to its nub is good, but simplifying it to the point where it's gone is no help at all!)
To reproduce the problem, I ran:
sh-3.2$ cd ~/tmp
sh-3.2$ mkdir gitpath && cd gitpath && git init
Initialized empty Git repository in /Users/torek/tmp/gitpath/.git/
sh-3.2$ mkdir -p depth_one/depth_two
sh-3.2$ touch depth_one/f1.txt depth_one/depth_two/f2.txt
sh-3.2$ git add .
sh-3.2$ git commit -m initial -m "" -m "commit with all lowercase names"
[master (root-commit) 5462107] initial
2 files changed, 0 insertions( ), 0 deletions(-)
create mode 100644 depth_one/depth_two/f2.txt
create mode 100644 depth_one/f1.txt
sh-3.2$
Next, we remove and then re-create the depth_one
directory without telling Git about it, like so:
sh-3.2$ rm -r depth_one
sh-3.2$ mkdir Depth_one
sh-3.2$ git status -s
sh-3.2$ git status -s
D depth_one/depth_two/f2.txt
D depth_one/f1.txt
These D
status-es show that the files have gone missing, which is true. We can get them back with git checkout
, extracting them from Git's index:
sh-3.2$ git checkout -- .
sh-3.2$ git status -s
It's useful to see what Git thinks is in the index / staging-area at this point:
sh-3.2$ git ls-files --stage
100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 depth_one/depth_two/f2.txt
100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 depth_one/f1.txt
The hash IDs here are those of the empty blob. Let's put some data in the working tree copies, under their new names Depth_one/f1.txt
and Depth_one/depth_two/f2.txt
:
sh-3.2$ echo data for file one > Depth_one/f1.txt
sh-3.2$ echo different data for file two > Depth_one/depth_two/f2.txt
sh-3.2$ git status -s
M depth_one/depth_two/f2.txt
M depth_one/f1.txt
Now we put some data in the two files, f1.txt
and f2.txt
, in the renamed directory in the working tree. Git still believes that the names are all lowercase, and because the default file system that I am using here does case-folding, Git's attempts to work with files named depth_one/f1.txt
and depth_one/depth_two/f2.txt
accesses the files whose names now begin with Depth_one
in the actual working tree.
sh-3.2$ echo data for file one > Depth_one/f1.txt
sh-3.2$ echo different data for file two > Depth_one/depth_two/f2.txt
sh-3.2$ git status -s
M depth_one/depth_two/f2.txt
M depth_one/f1.txt
The short status shows that the working tree copies are modified, but an explicit git add
of each file has no effect:
sh-3.2$ git add Depth_one/f1.txt Depth_one/depth_two/f2.txt
sh-3.2$ git status -s
M depth_one/depth_two/f2.txt
M depth_one/f1.txt
Running git add Depth_one/
has the same lack of effect. Interestingly, however, git add .
is different:
sh-3.2$ git add .
sh-3.2$ git status -s
M depth_one/depth_two/f2.txt
M depth_one/f1.txt
sh-3.2$ git ls-files --stage
100644 ee13bb89375a5217f36cb6ee6573fcd05b1719ca 0 depth_one/depth_two/f2.txt
100644 bb5f31937e0c394dabee30155dab5d3f23a4c5c3 0 depth_one/f1.txt
Note that the full file names are still all-lowercase. To convince Git to pick up the changed names, it suffices to remove the index entries and then re-create them from scratch:
sh-3.2$ git rm --cached -r .
rm 'depth_one/depth_two/f2.txt'
rm 'depth_one/f1.txt'
sh-3.2$ git add .
sh-3.2$ git ls-files --stage
100644 ee13bb89375a5217f36cb6ee6573fcd05b1719ca 0 Depth_one/depth_two/f2.txt
100644 bb5f31937e0c394dabee30155dab5d3f23a4c5c3 0 Depth_one/f1.txt
sh-3.2$ git status -s
A Depth_one/depth_two/f2.txt
A Depth_one/f1.txt
D depth_one/depth_two/f2.txt
D depth_one/f1.txt
(there are no renames detected here because the old files are empty and the new ones are much too different from the empty old ones; but if the files had actual contents, Git would show these as renames).
(All testing was with Git 2.20.1; I have not updated the Git on this Mac in quite a while.)