Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Git says 'commit your changes or stash them before you switch branches', but also 'nothing to commit'

Tags:

git

I'm trying to switch branches from test1 to test2 by running git checkout test2, but am getting this error:

error: Your local changes to the following files would be overwritten by checkout:
    path/to/file.xml
Please commit your changes or stash them before you switch branches.
Aborting

Even though, when I run git status or git commit on test1, I get this:

On branch test1
nothing to commit, working tree clean

Interestingly, I can switch between master and test1 no problem.

What's going on here? What do I need to do to switch to test2?

like image 639
holastello Avatar asked Feb 20 '19 18:02

holastello


1 Answers

TL;DR

You need to clear the skip-worktree bit and re-run git status to see what's going on. From that point forward, things will be (somewhat) clearer.

Long(ish)

The problem here was that the skip-worktree bit was set on:

path/to/file.xml

There's a related bit spelled assume-unchanged. Both bits have the same actual effect. Neither is meant for the way people tend to use them, though documentation and stackoverflow answers recommend the skip-worktree bit,1 and so do I here; but either one does the same thing in practice. You do have to remember (or re-discover) which bit you set, in order to clear it:

git update-index --no-skip-worktree path/to/file.xml

When either bit is set on a file whose name and contents are recorded in the index, Git assumes that the contents stored via the index should be used, and the work-tree copy should be ignored during git status and git add operations.

Fortunately, Git is smart enough to check the actual work-tree copy on other operations. If Git is about to overwrite the work-tree copy for some reason—such as git checkout or git merge of a commit whose committed copy of that file differs from the current index copy—Git will double-check that the work-tree copy of path/to/file.xml matches the index copy. If not, Git will complain that the operation will overwrite the work-tree copy.

Unfortunately, git status, by design, doesn't announce that the work-tree copy is out of sync with the index copy. It just assumes that both versions of the file match. So you run git status and there's no changes to commit and hence nothing to save, but meanwhile git checkout or git merge keeps complaining that you must commit your changes.

Clearing the bit, whichever bit it is, makes git status notice the problem. It seems to me that git status should be more informative here: it needs to say, perhaps when using an extra option or perhaps just always, that there is some difference here but it's being deliberately ignored due to one or both of these bits. (To make this work well with sparse checkout, it probably should say nothing about a marked---skip-worktree-file that's in the index, not in the work-tree, and excluded by the sparseness rules.)


1Assume-unchanged is meant for use on file systems where the lstat call is particularly slow, and Git is allowed to ignore it. Skip-worktree is meant for use with sparse checkout, and Git is not allowed to ignore this. Git has no user-oriented sparse checkout commands either, so setting the skip-worktree bit is better.

like image 93
torek Avatar answered Oct 03 '22 14:10

torek