Why error switching branches after squashing? Nothing to commit
I just squashed my remote commits, then forced-pushed them to the remote. A git status shows no changes. Why then would I get this error when trying to checkout the develop branch?
error: Your local changes to the following files would be overwritten
by checkout:
[file here]
Please commit your changes or stash them before you switch branches.
Aborting
Here is what was done:
git rebase -i origin/feature/EX-1576~14 feature/EX-1576
git push --force origin feature/EX-1576
And git status shows nothing:
$ git status
On branch feature/EX-1576
Your branch is up to date with 'origin/feature/EX-1576'.
nothing to commit, working tree clean
It's my understanding that the error occurs when you have local changes, but I don't have local changes. I simply want to do this:
git checkout develop
git git-rebase git-squash
add a comment |
I just squashed my remote commits, then forced-pushed them to the remote. A git status shows no changes. Why then would I get this error when trying to checkout the develop branch?
error: Your local changes to the following files would be overwritten
by checkout:
[file here]
Please commit your changes or stash them before you switch branches.
Aborting
Here is what was done:
git rebase -i origin/feature/EX-1576~14 feature/EX-1576
git push --force origin feature/EX-1576
And git status shows nothing:
$ git status
On branch feature/EX-1576
Your branch is up to date with 'origin/feature/EX-1576'.
nothing to commit, working tree clean
It's my understanding that the error occurs when you have local changes, but I don't have local changes. I simply want to do this:
git checkout develop
git git-rebase git-squash
Are you on Linux, macOS or Windows?
– iBug
Jan 3 at 18:32
I'm on Windows 10.
– Bob Horn
Jan 3 at 18:32
Iscore.autocrlfset? i.e. What doesgit config --get core.autocrlfsay?
– iBug
Jan 3 at 18:34
It returns true.
– Bob Horn
Jan 3 at 18:36
add a comment |
I just squashed my remote commits, then forced-pushed them to the remote. A git status shows no changes. Why then would I get this error when trying to checkout the develop branch?
error: Your local changes to the following files would be overwritten
by checkout:
[file here]
Please commit your changes or stash them before you switch branches.
Aborting
Here is what was done:
git rebase -i origin/feature/EX-1576~14 feature/EX-1576
git push --force origin feature/EX-1576
And git status shows nothing:
$ git status
On branch feature/EX-1576
Your branch is up to date with 'origin/feature/EX-1576'.
nothing to commit, working tree clean
It's my understanding that the error occurs when you have local changes, but I don't have local changes. I simply want to do this:
git checkout develop
git git-rebase git-squash
I just squashed my remote commits, then forced-pushed them to the remote. A git status shows no changes. Why then would I get this error when trying to checkout the develop branch?
error: Your local changes to the following files would be overwritten
by checkout:
[file here]
Please commit your changes or stash them before you switch branches.
Aborting
Here is what was done:
git rebase -i origin/feature/EX-1576~14 feature/EX-1576
git push --force origin feature/EX-1576
And git status shows nothing:
$ git status
On branch feature/EX-1576
Your branch is up to date with 'origin/feature/EX-1576'.
nothing to commit, working tree clean
It's my understanding that the error occurs when you have local changes, but I don't have local changes. I simply want to do this:
git checkout develop
git git-rebase git-squash
git git-rebase git-squash
edited Jan 3 at 18:02
Bob Horn
asked Jan 3 at 17:57
Bob HornBob Horn
19.6k2283175
19.6k2283175
Are you on Linux, macOS or Windows?
– iBug
Jan 3 at 18:32
I'm on Windows 10.
– Bob Horn
Jan 3 at 18:32
Iscore.autocrlfset? i.e. What doesgit config --get core.autocrlfsay?
– iBug
Jan 3 at 18:34
It returns true.
– Bob Horn
Jan 3 at 18:36
add a comment |
Are you on Linux, macOS or Windows?
– iBug
Jan 3 at 18:32
I'm on Windows 10.
– Bob Horn
Jan 3 at 18:32
Iscore.autocrlfset? i.e. What doesgit config --get core.autocrlfsay?
– iBug
Jan 3 at 18:34
It returns true.
– Bob Horn
Jan 3 at 18:36
Are you on Linux, macOS or Windows?
– iBug
Jan 3 at 18:32
Are you on Linux, macOS or Windows?
– iBug
Jan 3 at 18:32
I'm on Windows 10.
– Bob Horn
Jan 3 at 18:32
I'm on Windows 10.
– Bob Horn
Jan 3 at 18:32
Is
core.autocrlf set? i.e. What does git config --get core.autocrlf say?– iBug
Jan 3 at 18:34
Is
core.autocrlf set? i.e. What does git config --get core.autocrlf say?– iBug
Jan 3 at 18:34
It returns true.
– Bob Horn
Jan 3 at 18:36
It returns true.
– Bob Horn
Jan 3 at 18:36
add a comment |
1 Answer
1
active
oldest
votes
TL;DR
Follow Git's advice: for each file that it names, move that file somewhere else (out of the way, perhaps out of the project entirely), or commit it. Then do the checkout, and see what file(s) you got that replaced those files, and decide whether to keep the replacements, or to use the saved copies you made before the checkout.
Be careful with git update-index --assume-unchanged or git update-index --skip-worktree: these work well for some cases, but set you up for this particular trap.
Since you are on Windows, which defaults to conflating files named (e.g.) readme with other different files named README—Windows can't store both; it just clobbers one of them—be careful with case-sensitive file names, usually made by some Linux programmer. :-)
Long
It's my understanding that the error occurs when you have local changes ...
That's not really right. You get that error when the operation—in this case, git checkout—would overwrite some state.
Git isn't about changes at all. Git is mostly about commits, and commits save state—a snapshot of all of your files, along with your metadata: your name and email address, the time you made the commit, and your log message as to why you made the commit, for instance. (Included in this metadata is another critical item, the parent commit hash ID, but we can ignore that for this particular problem.)
The difference between state and changes is like talking about the weather: saying it's warmer today than yesterday tells you one thing, but not everything, about the temperature. Saying that it was 15˚C (59˚F) yesterday, and is 20 / 68 today, tells you everything about the temperature. (Well, about this one temperature, anyway.) Note that it took two states to come up with the change: we have to subtract yesterday's temperature from today's to see how much warmer or colder it might be.
Anyway, commits store state: a full, complete copy of every file that was committed, as of the time it was committed. This copy actually comes out of Git's index, but we get to ignore that fine distinction for the moment. It's about to crop up in a moment, though. So each commit is very much independent of every other commit.
Your work-tree, on the other hand, is not something Git saves (at all, really, because of the index). You use it to work on your files, because the committed copies are in a special, frozen, compressed (sometimes very compressed), Git-only format. To make these useful, Git needs to expand them out into ordinary-format files, that you can use and change if you like. Those expanded copies go in your work-tree.
Now, a thing about the work-tree is that it's allowed to contain files that you won't commit. These are what Git calls untracked files. Normally, if there is a file in your work-tree that's is untracked—that won't be committed—Git will complain about that file. You can make Git shut up about it by listing the untracked file in .gitignore, but this is trickier than it looks. This is where Git smacks you in the face with the existence of the index, again.
The index is a weird and wonderful, but also obnoxious, thing that is pretty much unique to Git. In between the commits, which store files in a frozen Git-only compressed form, and the work-tree, which lets you work on your files, Git puts a third copy of every file. The index copy of each file is in the special Git-only format, but instead of being frozen, it's merely ready to freeze: kind of slushy, if you will. The point is that you can change this copy, and that's what git add does: it copies a file from the work-tree, into the index.
It's actually the presence of the index copy that determines whether or not a file is tracked. If the file is in the index, it's tracked; if not, it's untracked. Listing a file in .gitignore means: if it's not in the index, and is in the work-tree, don't complain. But it has a second side effect, which is: it gives Git permission to destroy the file, in some cases.
Filename case issues
Linux programmers happily write and commit two different files, one named README and other named readme or Readme. Or they do the same with header files: ip.h and IP.h (in older Linux kernel trees). When someone using a Mac or a Windows box tries to work with these commits, they get bitten by the fact that the work-tree on these systems can't put both files into place. (Git's index handles it just fine, because the index is actually a file, .git/index.)
If you are switching from a commit that has a file named README to one that has Readme, or that has both, Git will sometimes get a little discombobulated by this, and not know what to do. (Git needs to be smarter about this, someday.)
assume-unchanged and skip-worktree
In any case, suppose a file is in the index. If you change the work-tree copy, Git will tell you that you have a modified tracked file. If you don't want Git to keep reminding you about this, you can use git update-index --assume-unchanged or git update-index --skip-worktree to mark that file specially.
When you do this—and I think you probably did—Git stops comparing the index copy of the file to the work-tree copy, for git status commands, and does not copy the work-tree copy of the file over top of the index copy, for git add commands. This means that you can take a configuration file, modify it for some reason, and yet have new commits—which use the index copy of the file—store the original version of the file, the one that came out of the commit and went into your work-tree before you set the assume-unchanged or skip-worktree bit.
But git checkout must, when it goes to switch to some other commit, replace the index copy of that file with the (different) committed copy in the commit you're going to switch to. When this happens, Git will not only update the index copy, it will also overwrite the work-tree copy. So if you have a file marked with either of these two bits, you can get that error when you use git checkout.
Is this a problem? Maybe so, maybe not. If you force git checkout to check out that other commit, Git will overwrite the index entry with the file from the other commit, and replace the work-tree copy of that file with the one from the other commit. It's up to you to decide whether this is OK, and if not, whether you need to move the file out of the way first, or clear those bits and go ahead and add-and-commit the file.
There are also corner cases with half-ignored files
Suppose, on the other hand, you didn't set those index bits with git update-index. You could still have an ordinary, untracked file, perhaps even one listed in a .gitignore to keep Git quiet about it. But some other commit might have (a different version of) that same file, and if you have Git switch to that commit, Git will have to replace your untracked work-tree file with the version out of the commit where it's a tracked file.
In this case, git checkout will sometimes—but not always—also complain. Usually it will say that the checkout would overwrite an untracked file. If the file is listed in .gitignore, this will give some parts of Git permission to clobber it. Fortunately git checkout is usually pretty careful about these things.
In my case, there is one file that Git is complaining about. So you're suggesting to copy that file somewhere else, then do a force checkout of develop? Then, if something is wrong with that file, I can reference the backup I made? BTW, that file isn't something I set in.gitignoreor the--skip-worktreething.
– Bob Horn
Jan 3 at 18:46
I ask about making a backup copy, becausegit statusshows there is nothing to commit, so I don't have that option.
– Bob Horn
Jan 3 at 18:56
Yes, if you save the file (or move it out of the way entirely) the checkout can proceed (without-fif you move it out of the way). Then you can see what's different and decide what to do. If it's not an assume-unchanged/skip-worktree thing (and I had the idea it was not ignored already), that's pretty much the only option.
– torek
Jan 3 at 18:56
That file is tracked. If I move it out of the way, won't that cause a local change?
– Bob Horn
Jan 3 at 19:00
1
No, what's going on is that the file in the commit you checked out is different. Exactly what the difference is, is not clear—there are some encoding tricks (end of line stuff for instance) that makes for puzzlements. I avoid Windows myself and don't normally run into any of these problems, though a few of them show up on MacOS too.
– torek
Jan 3 at 19:21
|
show 4 more comments
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54027437%2fwhy-error-switching-branches-after-squashing-nothing-to-commit%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
TL;DR
Follow Git's advice: for each file that it names, move that file somewhere else (out of the way, perhaps out of the project entirely), or commit it. Then do the checkout, and see what file(s) you got that replaced those files, and decide whether to keep the replacements, or to use the saved copies you made before the checkout.
Be careful with git update-index --assume-unchanged or git update-index --skip-worktree: these work well for some cases, but set you up for this particular trap.
Since you are on Windows, which defaults to conflating files named (e.g.) readme with other different files named README—Windows can't store both; it just clobbers one of them—be careful with case-sensitive file names, usually made by some Linux programmer. :-)
Long
It's my understanding that the error occurs when you have local changes ...
That's not really right. You get that error when the operation—in this case, git checkout—would overwrite some state.
Git isn't about changes at all. Git is mostly about commits, and commits save state—a snapshot of all of your files, along with your metadata: your name and email address, the time you made the commit, and your log message as to why you made the commit, for instance. (Included in this metadata is another critical item, the parent commit hash ID, but we can ignore that for this particular problem.)
The difference between state and changes is like talking about the weather: saying it's warmer today than yesterday tells you one thing, but not everything, about the temperature. Saying that it was 15˚C (59˚F) yesterday, and is 20 / 68 today, tells you everything about the temperature. (Well, about this one temperature, anyway.) Note that it took two states to come up with the change: we have to subtract yesterday's temperature from today's to see how much warmer or colder it might be.
Anyway, commits store state: a full, complete copy of every file that was committed, as of the time it was committed. This copy actually comes out of Git's index, but we get to ignore that fine distinction for the moment. It's about to crop up in a moment, though. So each commit is very much independent of every other commit.
Your work-tree, on the other hand, is not something Git saves (at all, really, because of the index). You use it to work on your files, because the committed copies are in a special, frozen, compressed (sometimes very compressed), Git-only format. To make these useful, Git needs to expand them out into ordinary-format files, that you can use and change if you like. Those expanded copies go in your work-tree.
Now, a thing about the work-tree is that it's allowed to contain files that you won't commit. These are what Git calls untracked files. Normally, if there is a file in your work-tree that's is untracked—that won't be committed—Git will complain about that file. You can make Git shut up about it by listing the untracked file in .gitignore, but this is trickier than it looks. This is where Git smacks you in the face with the existence of the index, again.
The index is a weird and wonderful, but also obnoxious, thing that is pretty much unique to Git. In between the commits, which store files in a frozen Git-only compressed form, and the work-tree, which lets you work on your files, Git puts a third copy of every file. The index copy of each file is in the special Git-only format, but instead of being frozen, it's merely ready to freeze: kind of slushy, if you will. The point is that you can change this copy, and that's what git add does: it copies a file from the work-tree, into the index.
It's actually the presence of the index copy that determines whether or not a file is tracked. If the file is in the index, it's tracked; if not, it's untracked. Listing a file in .gitignore means: if it's not in the index, and is in the work-tree, don't complain. But it has a second side effect, which is: it gives Git permission to destroy the file, in some cases.
Filename case issues
Linux programmers happily write and commit two different files, one named README and other named readme or Readme. Or they do the same with header files: ip.h and IP.h (in older Linux kernel trees). When someone using a Mac or a Windows box tries to work with these commits, they get bitten by the fact that the work-tree on these systems can't put both files into place. (Git's index handles it just fine, because the index is actually a file, .git/index.)
If you are switching from a commit that has a file named README to one that has Readme, or that has both, Git will sometimes get a little discombobulated by this, and not know what to do. (Git needs to be smarter about this, someday.)
assume-unchanged and skip-worktree
In any case, suppose a file is in the index. If you change the work-tree copy, Git will tell you that you have a modified tracked file. If you don't want Git to keep reminding you about this, you can use git update-index --assume-unchanged or git update-index --skip-worktree to mark that file specially.
When you do this—and I think you probably did—Git stops comparing the index copy of the file to the work-tree copy, for git status commands, and does not copy the work-tree copy of the file over top of the index copy, for git add commands. This means that you can take a configuration file, modify it for some reason, and yet have new commits—which use the index copy of the file—store the original version of the file, the one that came out of the commit and went into your work-tree before you set the assume-unchanged or skip-worktree bit.
But git checkout must, when it goes to switch to some other commit, replace the index copy of that file with the (different) committed copy in the commit you're going to switch to. When this happens, Git will not only update the index copy, it will also overwrite the work-tree copy. So if you have a file marked with either of these two bits, you can get that error when you use git checkout.
Is this a problem? Maybe so, maybe not. If you force git checkout to check out that other commit, Git will overwrite the index entry with the file from the other commit, and replace the work-tree copy of that file with the one from the other commit. It's up to you to decide whether this is OK, and if not, whether you need to move the file out of the way first, or clear those bits and go ahead and add-and-commit the file.
There are also corner cases with half-ignored files
Suppose, on the other hand, you didn't set those index bits with git update-index. You could still have an ordinary, untracked file, perhaps even one listed in a .gitignore to keep Git quiet about it. But some other commit might have (a different version of) that same file, and if you have Git switch to that commit, Git will have to replace your untracked work-tree file with the version out of the commit where it's a tracked file.
In this case, git checkout will sometimes—but not always—also complain. Usually it will say that the checkout would overwrite an untracked file. If the file is listed in .gitignore, this will give some parts of Git permission to clobber it. Fortunately git checkout is usually pretty careful about these things.
In my case, there is one file that Git is complaining about. So you're suggesting to copy that file somewhere else, then do a force checkout of develop? Then, if something is wrong with that file, I can reference the backup I made? BTW, that file isn't something I set in.gitignoreor the--skip-worktreething.
– Bob Horn
Jan 3 at 18:46
I ask about making a backup copy, becausegit statusshows there is nothing to commit, so I don't have that option.
– Bob Horn
Jan 3 at 18:56
Yes, if you save the file (or move it out of the way entirely) the checkout can proceed (without-fif you move it out of the way). Then you can see what's different and decide what to do. If it's not an assume-unchanged/skip-worktree thing (and I had the idea it was not ignored already), that's pretty much the only option.
– torek
Jan 3 at 18:56
That file is tracked. If I move it out of the way, won't that cause a local change?
– Bob Horn
Jan 3 at 19:00
1
No, what's going on is that the file in the commit you checked out is different. Exactly what the difference is, is not clear—there are some encoding tricks (end of line stuff for instance) that makes for puzzlements. I avoid Windows myself and don't normally run into any of these problems, though a few of them show up on MacOS too.
– torek
Jan 3 at 19:21
|
show 4 more comments
TL;DR
Follow Git's advice: for each file that it names, move that file somewhere else (out of the way, perhaps out of the project entirely), or commit it. Then do the checkout, and see what file(s) you got that replaced those files, and decide whether to keep the replacements, or to use the saved copies you made before the checkout.
Be careful with git update-index --assume-unchanged or git update-index --skip-worktree: these work well for some cases, but set you up for this particular trap.
Since you are on Windows, which defaults to conflating files named (e.g.) readme with other different files named README—Windows can't store both; it just clobbers one of them—be careful with case-sensitive file names, usually made by some Linux programmer. :-)
Long
It's my understanding that the error occurs when you have local changes ...
That's not really right. You get that error when the operation—in this case, git checkout—would overwrite some state.
Git isn't about changes at all. Git is mostly about commits, and commits save state—a snapshot of all of your files, along with your metadata: your name and email address, the time you made the commit, and your log message as to why you made the commit, for instance. (Included in this metadata is another critical item, the parent commit hash ID, but we can ignore that for this particular problem.)
The difference between state and changes is like talking about the weather: saying it's warmer today than yesterday tells you one thing, but not everything, about the temperature. Saying that it was 15˚C (59˚F) yesterday, and is 20 / 68 today, tells you everything about the temperature. (Well, about this one temperature, anyway.) Note that it took two states to come up with the change: we have to subtract yesterday's temperature from today's to see how much warmer or colder it might be.
Anyway, commits store state: a full, complete copy of every file that was committed, as of the time it was committed. This copy actually comes out of Git's index, but we get to ignore that fine distinction for the moment. It's about to crop up in a moment, though. So each commit is very much independent of every other commit.
Your work-tree, on the other hand, is not something Git saves (at all, really, because of the index). You use it to work on your files, because the committed copies are in a special, frozen, compressed (sometimes very compressed), Git-only format. To make these useful, Git needs to expand them out into ordinary-format files, that you can use and change if you like. Those expanded copies go in your work-tree.
Now, a thing about the work-tree is that it's allowed to contain files that you won't commit. These are what Git calls untracked files. Normally, if there is a file in your work-tree that's is untracked—that won't be committed—Git will complain about that file. You can make Git shut up about it by listing the untracked file in .gitignore, but this is trickier than it looks. This is where Git smacks you in the face with the existence of the index, again.
The index is a weird and wonderful, but also obnoxious, thing that is pretty much unique to Git. In between the commits, which store files in a frozen Git-only compressed form, and the work-tree, which lets you work on your files, Git puts a third copy of every file. The index copy of each file is in the special Git-only format, but instead of being frozen, it's merely ready to freeze: kind of slushy, if you will. The point is that you can change this copy, and that's what git add does: it copies a file from the work-tree, into the index.
It's actually the presence of the index copy that determines whether or not a file is tracked. If the file is in the index, it's tracked; if not, it's untracked. Listing a file in .gitignore means: if it's not in the index, and is in the work-tree, don't complain. But it has a second side effect, which is: it gives Git permission to destroy the file, in some cases.
Filename case issues
Linux programmers happily write and commit two different files, one named README and other named readme or Readme. Or they do the same with header files: ip.h and IP.h (in older Linux kernel trees). When someone using a Mac or a Windows box tries to work with these commits, they get bitten by the fact that the work-tree on these systems can't put both files into place. (Git's index handles it just fine, because the index is actually a file, .git/index.)
If you are switching from a commit that has a file named README to one that has Readme, or that has both, Git will sometimes get a little discombobulated by this, and not know what to do. (Git needs to be smarter about this, someday.)
assume-unchanged and skip-worktree
In any case, suppose a file is in the index. If you change the work-tree copy, Git will tell you that you have a modified tracked file. If you don't want Git to keep reminding you about this, you can use git update-index --assume-unchanged or git update-index --skip-worktree to mark that file specially.
When you do this—and I think you probably did—Git stops comparing the index copy of the file to the work-tree copy, for git status commands, and does not copy the work-tree copy of the file over top of the index copy, for git add commands. This means that you can take a configuration file, modify it for some reason, and yet have new commits—which use the index copy of the file—store the original version of the file, the one that came out of the commit and went into your work-tree before you set the assume-unchanged or skip-worktree bit.
But git checkout must, when it goes to switch to some other commit, replace the index copy of that file with the (different) committed copy in the commit you're going to switch to. When this happens, Git will not only update the index copy, it will also overwrite the work-tree copy. So if you have a file marked with either of these two bits, you can get that error when you use git checkout.
Is this a problem? Maybe so, maybe not. If you force git checkout to check out that other commit, Git will overwrite the index entry with the file from the other commit, and replace the work-tree copy of that file with the one from the other commit. It's up to you to decide whether this is OK, and if not, whether you need to move the file out of the way first, or clear those bits and go ahead and add-and-commit the file.
There are also corner cases with half-ignored files
Suppose, on the other hand, you didn't set those index bits with git update-index. You could still have an ordinary, untracked file, perhaps even one listed in a .gitignore to keep Git quiet about it. But some other commit might have (a different version of) that same file, and if you have Git switch to that commit, Git will have to replace your untracked work-tree file with the version out of the commit where it's a tracked file.
In this case, git checkout will sometimes—but not always—also complain. Usually it will say that the checkout would overwrite an untracked file. If the file is listed in .gitignore, this will give some parts of Git permission to clobber it. Fortunately git checkout is usually pretty careful about these things.
In my case, there is one file that Git is complaining about. So you're suggesting to copy that file somewhere else, then do a force checkout of develop? Then, if something is wrong with that file, I can reference the backup I made? BTW, that file isn't something I set in.gitignoreor the--skip-worktreething.
– Bob Horn
Jan 3 at 18:46
I ask about making a backup copy, becausegit statusshows there is nothing to commit, so I don't have that option.
– Bob Horn
Jan 3 at 18:56
Yes, if you save the file (or move it out of the way entirely) the checkout can proceed (without-fif you move it out of the way). Then you can see what's different and decide what to do. If it's not an assume-unchanged/skip-worktree thing (and I had the idea it was not ignored already), that's pretty much the only option.
– torek
Jan 3 at 18:56
That file is tracked. If I move it out of the way, won't that cause a local change?
– Bob Horn
Jan 3 at 19:00
1
No, what's going on is that the file in the commit you checked out is different. Exactly what the difference is, is not clear—there are some encoding tricks (end of line stuff for instance) that makes for puzzlements. I avoid Windows myself and don't normally run into any of these problems, though a few of them show up on MacOS too.
– torek
Jan 3 at 19:21
|
show 4 more comments
TL;DR
Follow Git's advice: for each file that it names, move that file somewhere else (out of the way, perhaps out of the project entirely), or commit it. Then do the checkout, and see what file(s) you got that replaced those files, and decide whether to keep the replacements, or to use the saved copies you made before the checkout.
Be careful with git update-index --assume-unchanged or git update-index --skip-worktree: these work well for some cases, but set you up for this particular trap.
Since you are on Windows, which defaults to conflating files named (e.g.) readme with other different files named README—Windows can't store both; it just clobbers one of them—be careful with case-sensitive file names, usually made by some Linux programmer. :-)
Long
It's my understanding that the error occurs when you have local changes ...
That's not really right. You get that error when the operation—in this case, git checkout—would overwrite some state.
Git isn't about changes at all. Git is mostly about commits, and commits save state—a snapshot of all of your files, along with your metadata: your name and email address, the time you made the commit, and your log message as to why you made the commit, for instance. (Included in this metadata is another critical item, the parent commit hash ID, but we can ignore that for this particular problem.)
The difference between state and changes is like talking about the weather: saying it's warmer today than yesterday tells you one thing, but not everything, about the temperature. Saying that it was 15˚C (59˚F) yesterday, and is 20 / 68 today, tells you everything about the temperature. (Well, about this one temperature, anyway.) Note that it took two states to come up with the change: we have to subtract yesterday's temperature from today's to see how much warmer or colder it might be.
Anyway, commits store state: a full, complete copy of every file that was committed, as of the time it was committed. This copy actually comes out of Git's index, but we get to ignore that fine distinction for the moment. It's about to crop up in a moment, though. So each commit is very much independent of every other commit.
Your work-tree, on the other hand, is not something Git saves (at all, really, because of the index). You use it to work on your files, because the committed copies are in a special, frozen, compressed (sometimes very compressed), Git-only format. To make these useful, Git needs to expand them out into ordinary-format files, that you can use and change if you like. Those expanded copies go in your work-tree.
Now, a thing about the work-tree is that it's allowed to contain files that you won't commit. These are what Git calls untracked files. Normally, if there is a file in your work-tree that's is untracked—that won't be committed—Git will complain about that file. You can make Git shut up about it by listing the untracked file in .gitignore, but this is trickier than it looks. This is where Git smacks you in the face with the existence of the index, again.
The index is a weird and wonderful, but also obnoxious, thing that is pretty much unique to Git. In between the commits, which store files in a frozen Git-only compressed form, and the work-tree, which lets you work on your files, Git puts a third copy of every file. The index copy of each file is in the special Git-only format, but instead of being frozen, it's merely ready to freeze: kind of slushy, if you will. The point is that you can change this copy, and that's what git add does: it copies a file from the work-tree, into the index.
It's actually the presence of the index copy that determines whether or not a file is tracked. If the file is in the index, it's tracked; if not, it's untracked. Listing a file in .gitignore means: if it's not in the index, and is in the work-tree, don't complain. But it has a second side effect, which is: it gives Git permission to destroy the file, in some cases.
Filename case issues
Linux programmers happily write and commit two different files, one named README and other named readme or Readme. Or they do the same with header files: ip.h and IP.h (in older Linux kernel trees). When someone using a Mac or a Windows box tries to work with these commits, they get bitten by the fact that the work-tree on these systems can't put both files into place. (Git's index handles it just fine, because the index is actually a file, .git/index.)
If you are switching from a commit that has a file named README to one that has Readme, or that has both, Git will sometimes get a little discombobulated by this, and not know what to do. (Git needs to be smarter about this, someday.)
assume-unchanged and skip-worktree
In any case, suppose a file is in the index. If you change the work-tree copy, Git will tell you that you have a modified tracked file. If you don't want Git to keep reminding you about this, you can use git update-index --assume-unchanged or git update-index --skip-worktree to mark that file specially.
When you do this—and I think you probably did—Git stops comparing the index copy of the file to the work-tree copy, for git status commands, and does not copy the work-tree copy of the file over top of the index copy, for git add commands. This means that you can take a configuration file, modify it for some reason, and yet have new commits—which use the index copy of the file—store the original version of the file, the one that came out of the commit and went into your work-tree before you set the assume-unchanged or skip-worktree bit.
But git checkout must, when it goes to switch to some other commit, replace the index copy of that file with the (different) committed copy in the commit you're going to switch to. When this happens, Git will not only update the index copy, it will also overwrite the work-tree copy. So if you have a file marked with either of these two bits, you can get that error when you use git checkout.
Is this a problem? Maybe so, maybe not. If you force git checkout to check out that other commit, Git will overwrite the index entry with the file from the other commit, and replace the work-tree copy of that file with the one from the other commit. It's up to you to decide whether this is OK, and if not, whether you need to move the file out of the way first, or clear those bits and go ahead and add-and-commit the file.
There are also corner cases with half-ignored files
Suppose, on the other hand, you didn't set those index bits with git update-index. You could still have an ordinary, untracked file, perhaps even one listed in a .gitignore to keep Git quiet about it. But some other commit might have (a different version of) that same file, and if you have Git switch to that commit, Git will have to replace your untracked work-tree file with the version out of the commit where it's a tracked file.
In this case, git checkout will sometimes—but not always—also complain. Usually it will say that the checkout would overwrite an untracked file. If the file is listed in .gitignore, this will give some parts of Git permission to clobber it. Fortunately git checkout is usually pretty careful about these things.
TL;DR
Follow Git's advice: for each file that it names, move that file somewhere else (out of the way, perhaps out of the project entirely), or commit it. Then do the checkout, and see what file(s) you got that replaced those files, and decide whether to keep the replacements, or to use the saved copies you made before the checkout.
Be careful with git update-index --assume-unchanged or git update-index --skip-worktree: these work well for some cases, but set you up for this particular trap.
Since you are on Windows, which defaults to conflating files named (e.g.) readme with other different files named README—Windows can't store both; it just clobbers one of them—be careful with case-sensitive file names, usually made by some Linux programmer. :-)
Long
It's my understanding that the error occurs when you have local changes ...
That's not really right. You get that error when the operation—in this case, git checkout—would overwrite some state.
Git isn't about changes at all. Git is mostly about commits, and commits save state—a snapshot of all of your files, along with your metadata: your name and email address, the time you made the commit, and your log message as to why you made the commit, for instance. (Included in this metadata is another critical item, the parent commit hash ID, but we can ignore that for this particular problem.)
The difference between state and changes is like talking about the weather: saying it's warmer today than yesterday tells you one thing, but not everything, about the temperature. Saying that it was 15˚C (59˚F) yesterday, and is 20 / 68 today, tells you everything about the temperature. (Well, about this one temperature, anyway.) Note that it took two states to come up with the change: we have to subtract yesterday's temperature from today's to see how much warmer or colder it might be.
Anyway, commits store state: a full, complete copy of every file that was committed, as of the time it was committed. This copy actually comes out of Git's index, but we get to ignore that fine distinction for the moment. It's about to crop up in a moment, though. So each commit is very much independent of every other commit.
Your work-tree, on the other hand, is not something Git saves (at all, really, because of the index). You use it to work on your files, because the committed copies are in a special, frozen, compressed (sometimes very compressed), Git-only format. To make these useful, Git needs to expand them out into ordinary-format files, that you can use and change if you like. Those expanded copies go in your work-tree.
Now, a thing about the work-tree is that it's allowed to contain files that you won't commit. These are what Git calls untracked files. Normally, if there is a file in your work-tree that's is untracked—that won't be committed—Git will complain about that file. You can make Git shut up about it by listing the untracked file in .gitignore, but this is trickier than it looks. This is where Git smacks you in the face with the existence of the index, again.
The index is a weird and wonderful, but also obnoxious, thing that is pretty much unique to Git. In between the commits, which store files in a frozen Git-only compressed form, and the work-tree, which lets you work on your files, Git puts a third copy of every file. The index copy of each file is in the special Git-only format, but instead of being frozen, it's merely ready to freeze: kind of slushy, if you will. The point is that you can change this copy, and that's what git add does: it copies a file from the work-tree, into the index.
It's actually the presence of the index copy that determines whether or not a file is tracked. If the file is in the index, it's tracked; if not, it's untracked. Listing a file in .gitignore means: if it's not in the index, and is in the work-tree, don't complain. But it has a second side effect, which is: it gives Git permission to destroy the file, in some cases.
Filename case issues
Linux programmers happily write and commit two different files, one named README and other named readme or Readme. Or they do the same with header files: ip.h and IP.h (in older Linux kernel trees). When someone using a Mac or a Windows box tries to work with these commits, they get bitten by the fact that the work-tree on these systems can't put both files into place. (Git's index handles it just fine, because the index is actually a file, .git/index.)
If you are switching from a commit that has a file named README to one that has Readme, or that has both, Git will sometimes get a little discombobulated by this, and not know what to do. (Git needs to be smarter about this, someday.)
assume-unchanged and skip-worktree
In any case, suppose a file is in the index. If you change the work-tree copy, Git will tell you that you have a modified tracked file. If you don't want Git to keep reminding you about this, you can use git update-index --assume-unchanged or git update-index --skip-worktree to mark that file specially.
When you do this—and I think you probably did—Git stops comparing the index copy of the file to the work-tree copy, for git status commands, and does not copy the work-tree copy of the file over top of the index copy, for git add commands. This means that you can take a configuration file, modify it for some reason, and yet have new commits—which use the index copy of the file—store the original version of the file, the one that came out of the commit and went into your work-tree before you set the assume-unchanged or skip-worktree bit.
But git checkout must, when it goes to switch to some other commit, replace the index copy of that file with the (different) committed copy in the commit you're going to switch to. When this happens, Git will not only update the index copy, it will also overwrite the work-tree copy. So if you have a file marked with either of these two bits, you can get that error when you use git checkout.
Is this a problem? Maybe so, maybe not. If you force git checkout to check out that other commit, Git will overwrite the index entry with the file from the other commit, and replace the work-tree copy of that file with the one from the other commit. It's up to you to decide whether this is OK, and if not, whether you need to move the file out of the way first, or clear those bits and go ahead and add-and-commit the file.
There are also corner cases with half-ignored files
Suppose, on the other hand, you didn't set those index bits with git update-index. You could still have an ordinary, untracked file, perhaps even one listed in a .gitignore to keep Git quiet about it. But some other commit might have (a different version of) that same file, and if you have Git switch to that commit, Git will have to replace your untracked work-tree file with the version out of the commit where it's a tracked file.
In this case, git checkout will sometimes—but not always—also complain. Usually it will say that the checkout would overwrite an untracked file. If the file is listed in .gitignore, this will give some parts of Git permission to clobber it. Fortunately git checkout is usually pretty careful about these things.
edited Jan 3 at 18:45
answered Jan 3 at 18:40
torektorek
198k18246328
198k18246328
In my case, there is one file that Git is complaining about. So you're suggesting to copy that file somewhere else, then do a force checkout of develop? Then, if something is wrong with that file, I can reference the backup I made? BTW, that file isn't something I set in.gitignoreor the--skip-worktreething.
– Bob Horn
Jan 3 at 18:46
I ask about making a backup copy, becausegit statusshows there is nothing to commit, so I don't have that option.
– Bob Horn
Jan 3 at 18:56
Yes, if you save the file (or move it out of the way entirely) the checkout can proceed (without-fif you move it out of the way). Then you can see what's different and decide what to do. If it's not an assume-unchanged/skip-worktree thing (and I had the idea it was not ignored already), that's pretty much the only option.
– torek
Jan 3 at 18:56
That file is tracked. If I move it out of the way, won't that cause a local change?
– Bob Horn
Jan 3 at 19:00
1
No, what's going on is that the file in the commit you checked out is different. Exactly what the difference is, is not clear—there are some encoding tricks (end of line stuff for instance) that makes for puzzlements. I avoid Windows myself and don't normally run into any of these problems, though a few of them show up on MacOS too.
– torek
Jan 3 at 19:21
|
show 4 more comments
In my case, there is one file that Git is complaining about. So you're suggesting to copy that file somewhere else, then do a force checkout of develop? Then, if something is wrong with that file, I can reference the backup I made? BTW, that file isn't something I set in.gitignoreor the--skip-worktreething.
– Bob Horn
Jan 3 at 18:46
I ask about making a backup copy, becausegit statusshows there is nothing to commit, so I don't have that option.
– Bob Horn
Jan 3 at 18:56
Yes, if you save the file (or move it out of the way entirely) the checkout can proceed (without-fif you move it out of the way). Then you can see what's different and decide what to do. If it's not an assume-unchanged/skip-worktree thing (and I had the idea it was not ignored already), that's pretty much the only option.
– torek
Jan 3 at 18:56
That file is tracked. If I move it out of the way, won't that cause a local change?
– Bob Horn
Jan 3 at 19:00
1
No, what's going on is that the file in the commit you checked out is different. Exactly what the difference is, is not clear—there are some encoding tricks (end of line stuff for instance) that makes for puzzlements. I avoid Windows myself and don't normally run into any of these problems, though a few of them show up on MacOS too.
– torek
Jan 3 at 19:21
In my case, there is one file that Git is complaining about. So you're suggesting to copy that file somewhere else, then do a force checkout of develop? Then, if something is wrong with that file, I can reference the backup I made? BTW, that file isn't something I set in
.gitignore or the --skip-worktree thing.– Bob Horn
Jan 3 at 18:46
In my case, there is one file that Git is complaining about. So you're suggesting to copy that file somewhere else, then do a force checkout of develop? Then, if something is wrong with that file, I can reference the backup I made? BTW, that file isn't something I set in
.gitignore or the --skip-worktree thing.– Bob Horn
Jan 3 at 18:46
I ask about making a backup copy, because
git status shows there is nothing to commit, so I don't have that option.– Bob Horn
Jan 3 at 18:56
I ask about making a backup copy, because
git status shows there is nothing to commit, so I don't have that option.– Bob Horn
Jan 3 at 18:56
Yes, if you save the file (or move it out of the way entirely) the checkout can proceed (without
-f if you move it out of the way). Then you can see what's different and decide what to do. If it's not an assume-unchanged/skip-worktree thing (and I had the idea it was not ignored already), that's pretty much the only option.– torek
Jan 3 at 18:56
Yes, if you save the file (or move it out of the way entirely) the checkout can proceed (without
-f if you move it out of the way). Then you can see what's different and decide what to do. If it's not an assume-unchanged/skip-worktree thing (and I had the idea it was not ignored already), that's pretty much the only option.– torek
Jan 3 at 18:56
That file is tracked. If I move it out of the way, won't that cause a local change?
– Bob Horn
Jan 3 at 19:00
That file is tracked. If I move it out of the way, won't that cause a local change?
– Bob Horn
Jan 3 at 19:00
1
1
No, what's going on is that the file in the commit you checked out is different. Exactly what the difference is, is not clear—there are some encoding tricks (end of line stuff for instance) that makes for puzzlements. I avoid Windows myself and don't normally run into any of these problems, though a few of them show up on MacOS too.
– torek
Jan 3 at 19:21
No, what's going on is that the file in the commit you checked out is different. Exactly what the difference is, is not clear—there are some encoding tricks (end of line stuff for instance) that makes for puzzlements. I avoid Windows myself and don't normally run into any of these problems, though a few of them show up on MacOS too.
– torek
Jan 3 at 19:21
|
show 4 more comments
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54027437%2fwhy-error-switching-branches-after-squashing-nothing-to-commit%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Are you on Linux, macOS or Windows?
– iBug
Jan 3 at 18:32
I'm on Windows 10.
– Bob Horn
Jan 3 at 18:32
Is
core.autocrlfset? i.e. What doesgit config --get core.autocrlfsay?– iBug
Jan 3 at 18:34
It returns true.
– Bob Horn
Jan 3 at 18:36