Git blame Windows reports "fatal: no such path <path> in HEAD"
When I run git blame in the file in the e, g folder:
git blame Foo/FileA.txt
he returns
fatal: no such path 'Foo/FileA.txt' in HEAD
I clearly see that this file exists in the file system, and other files in the same folder can be successfully blamed - so what happens?
I post this question and answer, because today I was at an impasse and I could not find a single answer that would hit the whole solution.
This is due to the renaming of the parent folder in the file system with a new name, which changes only depending on the case - and some files were added to the commit that occurred before renaming the folder. Here is an example from the Powershell tooltip:
mkdir C:\RenameProblem cd C:\RenameProblem git init mkdir foo "FileA" > foo/FileA.txt git add foo/FileA.txt git commit -m "Add FileA"
Then, in Windows Explorer, rename the directory "foo" to "Foo", and then continue in Powershell with:
"FileB" > Foo/FileB.txt git add Foo/FileB.txt git commit -m "Add FileB"
At this point, git blame /Foo/FileA.txt
(that the tab git blame /Foo/FileA.txt
after renaming the folder) will fail with a path error, while git blame /Foo/FileB.txt
or even git blame /Foo/FileA.txt
will succeed.
Moreover, a call to git ls-files Foo
will only display FileB.txt
, and git ls-files Foo
will only display FileA.txt
. Not a great place for Windows.
In my case, I had a large number of files shared between two versions of the folder name.
You can solve this problem by renaming the file with git mv
:
git mv foo/FileA.txt Foo/FileA.txt git commit -am "Rename foo to Foo"
If you need to rename many files, use the Powershell bit (also note that git mv
has a -n
switch to perform a dry what-if run, so you can verify that your renaming is correct):
git ls-files foo | % { (& git mv $_ $('F' + $_.Substring(1))) }
The above example uses git ls-files
to get the list of files in the "foo" folder of the problem, this means that it is "ForEach" ( %
is a shortcut for this), and then runs git mv
for each file supplying the original name ( $_
) and the new name "F" and the rest of the file name ( 'F' + $_.Substring(1))
)