git commit error message: cannot open (a previously deleted source file)

Every time I commit anything in that git repository, I am getting an (apparently harmless) error message mentioning a few files that no longer exist:

$ git commit -a
error: Could not open cssrc/csgrpc/Main.cs
error: Could not open cssrc/csgrpc/Main.cs
Recorded preimage for 'cssrc/csgrpc/Main.cs'
... more 3-line groups like one above ...
[x017-upgrade a86861b] Point Audio to new location of....
 1 file changed, 1 insertion(+), 1 deletion(-)

The files were initially part of a subtree, maintained with git subtree -P cssrc ..., and I deleted them during a git subtree pull conflict, since they are not needed in this project any more (but were modified previously and committed, hence a conflict).

The files are indeed found neither in the index nor in the worktree:

$ git ls-files -cs | grep Main.cs
$ find -name 'Main.cs'
$

The rerere.enabled option is set to true. Is it a culprit? Where is the stuck pointer to these file names stored? How to clean it?

  • Setting up staging environment for heroku app
  • How could git status porcelain show DM?
  • Git/Github allow collaborators but keep control
  • Git- archive old commits
  • Files changed between commits but with limiting file list to older commit
  • Which files on .idea directory should be committed to git repository?
  • Split Up Folders in a git repository into separate branches
  • GIT Branch Specific Files?
  • One Solution collect form web for “git commit error message: cannot open (a previously deleted source file)”

    The source of the error is git’s rerere or “reuse recorded resolution” feature. Since you “deleted them(your files) during a git subtree pull conflict“, you inadvertently put git into an “unresolved” state. git rerere tries its very best to keep a clean conflict resolution record for reuse later on down the line. Because you deleted your files in the middle of a conflict resolution, you had a reference to those files in rerere, causing git to look for files that no longer existed. Understand that in order for git to reuse a recorded resolution, it has to record the steps involved. However, this does not mean that git is tracking the commands that you use; which explains why it doesn’t know why the file that is in its conflict state, is missing from it’s resolved state. It expected you to choose one version of that file or the other, not remove the file/’s entirely.

    If you are interested in learning more about git rerere I recommend reading the git manual pages.

    If you are interested in a working example of the problem described in this question, and a solution(I’m sure there are many more) to the problem please follow the steps listed below. I know it is quite lengthy but I don’t know how else I can clarify the issue.

    In a directory suitable for testing code…

    1. $ mkdir test_rerere
    2. $ cd test_rerere
    3. $ git init
    4. $ cd .git
    5. $ mkdir rr-cache
    6. $ cd ..
    7. create a file named hello.rb with the following code

      #! /usr/bin/env ruby
      
      def hello
        puts 'hello world'
      end
      
    8. $ git commit -a -m"added hello.rb"
    9. create a file named goodbye.rb with the following code

      #! /usr/bin/env ruby
      
      def bye
        puts "goodbye world"
      end
      
    10. $ git commit -m"added goodbye.rb"
    11. $ git branch i18-world
    12. Change hello to hola in hello.rb
    13. $ git commit -a -m"changed hello to hola in hello.rb"
    14. $ git checkout i18-world
    15. Change world to mundo in hello.rb
    16. $ git commit -a -m"changed world to mundo in hello.rb"
    17. Change goodbye to adios in goodbye.rb
    18. $ git commit -a -m"changed goodbye to adios in goodbye.rb"
    19. $ git checkout master
    20. Change world to mundo in goodbye.rb
    21. $ git commit -a -m"changed world to mundo in goodbye.rb"
      Now we have two branches, with two files that are similar, but not identical. Take a minute to look at each file as it exists in both branches.
    22. $ git status should say

      On branch master
      nothing to commit, working tree clean
      
    23. $ git merge i18-world
    24. You should get something that looks like this…

      Auto-merging hello.rb
      CONFLICT (content): Merge conflict in hello.rb
      Auto-merging goodbye.rb
      CONFLICT (content): Merge conflict in goodbye.rb
      Recorded preimage for 'goodbye.rb'
      Recorded preimage for 'hello.rb'
      Automatic merge failed; fix conflicts and then commit the result.
      
    25. You are not in a conflict state, and rerere is doing its job… notice the Recorded preimage logs above.
    26. $ git rerere status returns goodbye.rb and hello.rb, since both files are being recorded for this conflict. Not is a good time to try out git rerere diff and git ls-files -u Now, lets create an error state.
    27. First, lets resolve hello.rb to print hola mundo, and without committing, lets $ git rm goodbye.rb. This will cause your error. Have a look with $ git status to see that indeed goodbye.rb has been deleted(although git complains) and hello.rb has been modified and is ready to merge.
    28. $ git commit -a -m"HUH?"
    29. Notice that the error you get at this point is exactly the same as the error described in the question, and that we also have a HUGE clue as to what happened when that Recorded preimage bit shows up. Now let’s make sure it’s really broken.
    30. $ git log --oneline --decorate --graph --all to see a pretty picture of our commit history.
    31. Change hello.rb from ‘hola mundo’ to ‘hola chica bonita!’
    32. $ git commit -a -m"changed 'hola mundo' to 'hola chica bonita!' in hello.rb"
    33. Notice that the error still shows up, and we are still getting Recorded preimage.
    34. $ git rerere status should still return goodbye.rb because it is still recorded in the preimage.
    35. $ git rerere diff returns a fatal error because goodbye.rb does not exist.
    36. For a clear picture, $ git log --oneline --decorate --graph --all
    37. Again, notice that git status and git rerere status will not return the same thing in this unresolved state. Verify for your own sanity that goodbye.rb does not exist in your working directory.
    38. Now, lets fix that pesky error message by checking out the commit that we made just before our merge. If you have been following along with your commit messages, it’s the one that says “changed goodbye to adios in goodbye.rb”. We will use a file specific checkout (since we don’t want to mess up our work in hello.rb) with $ git checkout **yoursha1** goodbye.rb.
    39. Verify that hello.rb has not been altered. Should say ‘hola chica bonita!’.
    40. The BIG FIX! git rerere … Ta Da! Notice that git says Recorded resolution for ‘goodbye.rb’.
    41. Okay, if you’re not confused, Bravo! This was very confusing to me at first, but then I remembered… rerere was just itching to reuse the resolution that I had already applied. It’s only complaint was that I had deleted a file out from underneath it and not given it an opportunity to catch up. Now that goodbye.rb existed again, it was more than happy to remove the reference that it had been carrying around, and live in a world where goodbye.rb did not exist. Magically, no more errors.
    42. Okay, I’ll prove it to you since you’re still sceptical.
    43. $ git checkout i18-world
    44. $ git rebase master
    45. $ git status returns nothing to commit, working tree clean
    46. $ ls returns “hello.rb” so we know that we are rid of that pesky goodbye.rb file.
    47. $ git log --oneline --decorate --graph --all shows us all of our hard work.
    48. $ git rerere status returns nothing because there is nothing being tracked (no preimages).
    49. $ cat hello.rb shows us

      #! /usr/bin/env ruby
      
      def hello
        puts 'hola chica bonita!'
      end
      
    50. Change hello.rb from ‘hola chica bonita!’ to ‘hola chica bonita! te amo’.
    51. $ git commit -a -m"updated hello in hello.rb to say 'hola chica bonita! te amo"
    52. git log --oneline --decorate --graph --all to see that i18-world is ahead of master.
    53. $ git checkout master
    54. $ git merge i18-world
    55. $ git branch should return i18-world *master
    56. $ git branch -d i18-world

    You can now be confident that your working directory is clean and error free. Plus if you ever need to go back to a state where ‘goodbye.rb’ exists, you can!

    I apologize for the length of this answer, but hopefully now you understand where things went wrong, and how easy(at least in this tiny example case) it can be to fix them.

    Git Baby is a git and github fan, let's start git clone.