Home > Mobile >  Git refuses to track some files (git add -f not working)
Git refuses to track some files (git add -f not working)

Time:09-16

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 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).

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.)

  •  Tags:  
  • git
  • Related