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?
In order to remove some files from a Git commit, use the “git reset” command with the “–soft” option and specify the commit before HEAD. When running this command, you will be presented with the files from the most recent commit (HEAD) and you will be able to commit them.
As you can see, by executing the “git rm” command, a “deleted” action was added to the changes to be committed. It means that the file was removed from the filesystem but it was not deleted from the index just yet.
The git commit --amend command is a convenient way to modify the most recent commit. It lets you combine staged changes with the previous commit instead of creating an entirely new commit. It can also be used to simply edit the previous commit message without changing its snapshot.
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
$ git commit -a -m"changed hello to hola in hello.rb"
$ git checkout i18-world
$ git commit -a -m"changed world to mundo in hello.rb"
$ git commit -a -m"changed goodbye to adios in goodbye.rb"
$ git checkout master
$ 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 status
should 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.
$ 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.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.$ git commit -a -m"HUH?"
$ git log --oneline --decorate --graph --all
to see a pretty picture of our commit history.$ git commit -a -m"changed 'hola mundo' to 'hola chica bonita!' in hello.rb"
$ git rerere status
should still return goodbye.rb because it is still recorded in the preimage.$ git rerere diff
returns a fatal error because goodbye.rb does not exist.$ git log --oneline --decorate --graph --all
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.$ git checkout **yoursha1** goodbye.rb
.git rerere
... Ta Da! Notice that git says Recorded resolution for 'goodbye.rb'.
$ git checkout i18-world
$ git rebase master
$ git status
returns nothing to commit, working tree clean
$ ls
returns "hello.rb" so we know that we are rid of that pesky goodbye.rb file.$ git log --oneline --decorate --graph --all
shows us all of our hard work.$ git rerere status
returns nothing because there is nothing being tracked (no preimages).$ cat hello.rb
shows us
#! /usr/bin/env ruby
def hello
puts 'hola chica bonita!'
end
$ git commit -a -m"updated hello in hello.rb to say 'hola chica bonita! te amo"
git log --oneline --decorate --graph --all
to see that i18-world is ahead of master.$ git checkout master
$ git merge i18-world
$ git branch
should return i18-world *master
$ 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With