Let's create a small local repository:
git init
echo foo > foo
git add foo
git commit -m foo
git branch bar
echo foo >> foo
git commit -a -m 'another foo'
If we do this now, we replace our file foo
in our index as well as in our working copy with the one from the branch bar
:
git restore --source bar --staged --worktree foo
and now we switch to bar
:
git switch bar
Expectation
git should refuse the switch
due to a dirty repository
Actual behavior
git does the switch and acts like nothing ever happened:
git status
On branch bar nothing to commit, working tree clean
Even weirder, if we instead just restore to the index:
git restore --source bar --staged foo
and switch then:
git switch bar
It will again just do it, but this time with uncommitted changes to foo
?
git status
On branch bar Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: foo
Questions
- Why does git perform the switch?
- Why doesn't it refuse to switch because of a dirty repository?
- What is happening behind the scenes?
- Where is this behavior documented?
FYI, the same happens with git checkout
.
All I could find in the documentation is this sentence:
The operation is aborted however if the operation leads to loss of local changes, [...]
But that doesn't really explain it, since if I do this instead of the restore
above:
echo foo >> foo
git add foo
git switch bar
error: Your local changes to the following files would be overwritten by checkout: foo Please commit your changes or stash them before you switch branches. Aborting
git won't do the switch because of a dirty repository (as expected), even though it theoretically could without losing local changes by only updating the index and not the working directory, as it seemingly does when the index already has the desired content for the switch.
Why is there an exception when the index has the same content as the target branch?