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).
- Pull only one file from collaborators repository on GitHub
- Prevent 'git checkout' if uncommitted changes
- Github failing to add arbitrary .svg file?
- How to revert a merge which used strategy=ours?
- TortoiseGit… switch to local or remote branch
- Key with fingerprint not authorized in Heroku
The files are indeed found neither in the index nor in the worktree:
$ git ls-files -cs | grep Main.cs $ find -name 'Main.cs' $
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?
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…
$ mkdir test_rerere
$ cd test_rerere
$ git init
$ cd .git
$ mkdir rr-cache
$ cd ..
create a file named hello.rb with the following code
#! /usr/bin/env ruby def hello puts 'hello world' end
$ git commit -a -m"added hello.rb"
create a file named goodbye.rb with the following code
#! /usr/bin/env ruby def bye puts "goodbye world" end
$ git commit -m"added goodbye.rb"
$ git branch i18-world
- Change hello to hola in hello.rb
$ git commit -a -m"changed hello to hola in hello.rb"
$ git checkout i18-world
- Change world to mundo in hello.rb
$ git commit -a -m"changed world to mundo in hello.rb"
- Change goodbye to adios in goodbye.rb
$ git commit -a -m"changed goodbye to adios in goodbye.rb"
$ git checkout master
- Change world to mundo in goodbye.rb
$ 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.
$ git statusshould say
On branch master nothing to commit, working tree clean
$ git merge i18-world
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.
- You are not in a conflict state, and rerere is doing its job… notice the Recorded preimage logs above.
$ git rerere statusreturns goodbye.rb and hello.rb, since both files are being recorded for this conflict. Not is a good time to try out
git rerere diffand
git ls-files -uNow, lets create an error state.
- 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 statusto see that indeed goodbye.rb has been deleted(although git complains) and hello.rb has been modified and is ready to merge.
$ git commit -a -m"HUH?"
- 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.
$ git log --oneline --decorate --graph --allto see a pretty picture of our commit history.
- Change hello.rb from ‘hola mundo’ to ‘hola chica bonita!’
$ git commit -a -m"changed 'hola mundo' to 'hola chica bonita!' in hello.rb"
- Notice that the error still shows up, and we are still getting Recorded preimage.
$ git rerere statusshould still return goodbye.rb because it is still recorded in the preimage.
$ git rerere diffreturns a fatal error because goodbye.rb does not exist.
- For a clear picture,
$ git log --oneline --decorate --graph --all
- Again, notice that
git rerere statuswill not return the same thing in this unresolved state. Verify for your own sanity that goodbye.rb does not exist in your working directory.
- 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.
- Verify that hello.rb has not been altered. Should say ‘hola chica bonita!’.
- The BIG FIX!
git rerere… Ta Da! Notice that git says Recorded resolution for ‘goodbye.rb’.
- 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.
- Okay, I’ll prove it to you since you’re still sceptical.
$ git checkout i18-world
$ git rebase master
$ git statusreturns
nothing to commit, working tree clean
$ lsreturns “hello.rb” so we know that we are rid of that pesky goodbye.rb file.
$ git log --oneline --decorate --graph --allshows us all of our hard work.
$ git rerere statusreturns nothing because there is nothing being tracked (no preimages).
$ cat hello.rbshows us
#! /usr/bin/env ruby def hello puts 'hola chica bonita!' end
- Change hello.rb from ‘hola chica bonita!’ to ‘hola chica bonita! te amo’.
$ git commit -a -m"updated hello in hello.rb to say 'hola chica bonita! te amo"
git log --oneline --decorate --graph --allto see that i18-world is ahead of master.
$ git checkout master
$ git merge i18-world
$ git branchshould return
$ 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.