burgerB
burgerB

Reputation: 772

Git allowing me to switch branches without committing changes

I am just learning Git, going through a tutorial. I am in branch seo_title and I have uncommitted changes to file mission.html. I did git checkout master expecting to get the warning about Changes not staged for commit, no changes added, etc, however instead it went ahead and switched branches with the message:

M       mission.html
Switched to branch 'master'

Then when I did git diff mission.html it showed me that the working directory still contains the changes I made while I had the other branch checked out. What am I missing? For what it's worth, I am using Git Bash on Windows.

EDIT: the changes to mission.html have not been added to staging index either.

EDIT 2: I thought the top voted answer was correct, but upon further investigation it doesn't match the behavior I am seeing. Here is a fuller description of what I am doing:

top_directory(master) > git branch new_branch_1
top_directory(master) > git branch new_branch_2
top_directory(master) > git checkout new_branch_1

(open notepad++ and modify resources.html, save)

top_directory(master) > git status
# On branch new_branch_1
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed
#   (use "git checkout -- <file>..." to discard changes in wo
#
#       modified:   resources.html
#
no changes added to commit (use "git add" and/or "git commit
top_directory(new_branch_1) > git checkout new_branch_2

This is where I expect git to object and tell me to stash or commit since new_branch_1 and new_branch_2 have different versions of resources.html, but it just switches to the new branch without a warning and it brings the uncommitted changes along:

M       resources.html
Switched to branch 'new_branch_2'
top_directory(new_branch_2) > git status
# On branch new_branch_2
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   resources.html
#
no changes added to commit (use "git add" and/or "git commit -a")

Is there a mode or a setting that would make it behave this way instead of warning? Or am I still misunderstanding the scenario?

EDIT 3: I get it now. The top rated answer was right, see my last comment on that answer.

Upvotes: 27

Views: 26971

Answers (5)

Eugene z. Von
Eugene z. Von

Reputation: 41

this is obvious, if you change a file which is not changed in the branch you want to checkout into, because the syntactic of checkout is to bring all the index and working directory to your new branch, you will have them appeared in your new branch. While if there r conflicts, chances r u need to merge those files, which means once after merge, if you checkout back to your old branch then it is already the merged version not your previous one, you lose it. As a result, to make sure you keep the old change it won't let you do that.

Upvotes: 0

Nabeelah Ali
Nabeelah Ali

Reputation: 539

The different behaviour you saw from the last time you tried to switch branches with local changes and now is due to different file changes.

So, let's say we have a branch called 'readme' where you have committed some changes to a file, let's say README.md.

Now, you have switched back to master. You do some work on other files (not README.md). Now you have local changes. If you try to switch back to the 'readme' branch without committing your changes, it will let you. Why? Because switching to the 'readme' branch won't override any of your local changes.

If, however you make a modification to the README.md file on the master branch, then when you try to do a

git checkout readme 

you will encounter

error: Your local changes to the following files would be overwritten by checkout: README.md
Please, commit your changes or stash them before you can switch branches.

because you have changes to README.md that would require a merge.

Upvotes: 36

GoZoner
GoZoner

Reputation: 70145

This is the normal behavior. If you don't want the modified files on your newly checked out branch, then stash them. Like this.

# on branch dev
$ git stash
$ git checkout master

# do stuff on master

# back to dev
$ git checkout dev
$ git stash pop

Upvotes: 16

kan
kan

Reputation: 28951

Git - the stupid content tracker. It just operates with working tree snapshots. The main requirement - you should be able to reconstruct working tree. It does update of course. But if the modified file is the same in both branches - why not to allow switch? If you done it by mistake, you could switch back reconstructing previous state, no big deal. But if the file is differ in the branches, you need merge content, that's why it insists to commit changes, otherwise it will be impossible to go back.

Upvotes: 0

Tuxdude
Tuxdude

Reputation: 49473

Git will let you checkout other branches (or tags or SHA1 hashes) as long as the commit you're changing your work-tree to does NOT clobber your local uncommitted changes.

In your case the branch master's work-tree would have had the same version of missing.html as that currently exists in the tip of your current branch you were switching from. Git does not need to touch the working copy (for missing.html at least) when changing branches here, and hence lets you keep your local modifications.

If you indeed tried to checkout a commit where there was a different version of missing.html in the work-tree (than the one committed in your current branch), git would show an error message similar to this:

$ git checkout some-other-branch
error: Your local changes to the following files would be overwritten by checkout:
        missing.html
Please, commit your changes or stash them before you can switch branches.
Aborting

Upvotes: 2

Related Questions