3

I am new to Git. It seems to be a fantastic non-liner workflow based on the Directed Acyclic Graph.

According to the git checkout doc:

git checkout <branch>

To prepare for working on , switch to it by updating the index and the files in the working tree, and by pointing HEAD at the branch. Local modifications to the files in the working tree are kept, so that they can be committed to the <branch>.

I have 2 branches:

  • master
  • dev

Both branches are clean and up-to-date.

I did this:

git checkout dev <change a tracked file> git checkout master 

Then I got this error:

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

So does this conflict with the bold part of the doc?

ADD

Thanks for all the comments and replies. I can understand Git's good intention to avoid data loss. I just want to point out a potential doc ambiguity/error.

6
  • Did you try committing your changes before switching branches? That error message is pretty clear. Commented May 26, 2016 at 3:23
  • No, I konw that. I deliberatly did this experiment for the doc's sake. Commented May 26, 2016 at 3:33
  • Always make sure your work tree is clean before git checkout. Commented May 26, 2016 at 3:53
  • Git's strategy is to not to allow you to lose data by doing most operations, so its unwillingness to overwrite your file when switching branches can be understood in that context. You can force things (git reset --hard), but you have to direct it to do that. Commented May 26, 2016 at 4:04
  • @ElpieKay Yes, both branches are clean and up-to-date. I just added that. Commented May 26, 2016 at 4:22

5 Answers 5

4

You made a change to readme.txt, which is all well and good.

Then you asked Git to change your current branch from dev to master, which is also OK, except for one problem.

Git compared the tip commit of dev to the tip commit of master and found that readme.txt is different in these two commits. So, in order to switch commits, it "wants" to remove the current readme.txt and replace it with the version out of master.

But you made a change to readme.txt. If Git removes readme.txt and replaces it with the version from master, your changes will be destroyed.

If Git switches to master without getting the different version of readme.txt from master, that might be OK, but it's not programmed to do that. So you must move your changes out of the way first, then you can switch, then you can restore your changes however you like. Using git commit or git stash provide two different ways to do this.

(If you had changed some other file, or if readme.txt were the same in both commits, Git might or definitely would not have run into this problem, and might or definitely would have switched your current branch over.)

Sign up to request clarification or add additional context in comments.

4 Comments

I didn't realize the subtle comparison between the tips of 2 branches.Thanks for the thorough explanation.
More precisely, Git compares the current commit (which in this case is the tip of dev) to the target commit (in this case, the tip of master). If you were on a detached head at commit 1234567 and did git checkout abbccd it would compare those two commits. It's basically a question of updating HEAD-as-resolved-to-a-commit-ID vs target commit ID, and the index, vs what's in the work-tree.
I can understand that when checkout <branchX>, I am essentially re-positioning the HEAD ref/pointer to branchX. But I don't quite understand your saying the index vs. what's in the work-tree. Whose index and whose work-tree here?
There's only one index and one work tree (well, since 2.6 you can create extra work trees, each of which has its own index). The index records what is in the current-and-next commit (what is git add-ed), and the work-tree is where you edit files (what can be git add-ed). So when you check out some other branch or commit, Git must update the index (to match where you're going) and/or the work-tree (likewise). It can leave these (index and work-tree) "dirty" only if it does not see any difference between current and target commit for the dirty paths. (There are many corner cases.)
2

No, not really. Normally local changes are indeed kept if you switch branch, but the problem in this case is that the branch you are checking out (master) has other changes to the same file. These changes would overwrite your local changes. Hence its recommendation to either commit or stash.

1 Comment

So the tips of (master) and (dev) are different. And Git wants to warn me before overwriting the data.
1

Yes, indeed the documentation is a little confusing. Instead of changing a tracked file, if you add a new file to the master branch and then checkout dev branch, you will see the the local change you made in master (new file you added to the working tree) is kept as the documentation suggests.

git checkout dev

touch <some_new_file>

git checkout master

Master checks out without error and ls shows some_new_file in working dir

If you modify a file that is part of the heads of both branches though, git throws the error.

git checkout dev

<change a tracked file>

git checkout master

throws error about committing or stashing local changes before checkout

This is because your local uncommitted changes can be overwritten if git simply checked out the file from the dev branch.

This behavior can be confusing when you have added a new file to master hoping to commit to the master branch but are not ready yet and have to checkout dev branch only to find that your working directory is a mix of dev's files and the file you intended to commit to master.

In order to avoid this confusion, it is recommended to stash, commit or discard all changes before checking out a new branch.

2 Comments

Provide your answer with a terminal commands how to achieve this, for instance. Your answer is hard to read, looks like a bunch of useless text. Use paragraphs, code quotes, etc...
@ghaiklor, I am not super familiar with the stackoverflow formatting, have given it a shot at making it clear. Hope it helps.
0

The readme.text is modified in current branch. This file change at both branches. You should commit and push this file to your current branch.

git add readme.text

git commit -m "Your message"

git push <current branch>

and check git status to see files change. Then, checkout to another branch.

git checkout <another branch>

1 Comment

To make things exact, I think you mean the tips of the 2 branches are different when you say This file change at both branches.
0

The key point here is the process of git checkout:

  • delete the files only in current branch but not in destination branch

  • add files only in destination branch

Thus, in your case, files neither in dev nor master are kept. So

Local modifications to the files in the working tree

really means Local modifications to the files in the working tree but not in the two commits to switch between . Otherwise git can not finish checkout.

Also, it's important bo be aware that git decide whether two files are the same or not by hashes when checkout:

kakakali@cyber:/mnt/d/gitest$ git init Initialized empty Git repository in /mnt/d/contents/test/gitest/test/.git/ kakakali@cyber:/mnt/d/gitest$ touch a.txt kakakali@cyber:/mnt/d/gitest$ echo 'hi'>a.txt kakakali@cyber:/mnt/d/gitest$ git add . kakakali@cyber:/mnt/d/gitest$ git commit -m '.' [master (root-commit) fab2485] . 1 file changed, 1 insertion(+) create mode 100644 a.txt kakakali@cyber:/mnt/d/gitest$ git branch dev kakakali@cyber:/mnt/d/gitest$ git checkout dev Switched to branch 'dev' kakakali@cyber:/mnt/d/gitest$ touch b.txt kakakali@cyber:/mnt/d/gitest$ git add . kakakali@cyber:/mnt/d/gitest$ git commit -m 'dev' [dev d7613e8] dev 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 b.txt kakakali@cyber:/mnt/d/gitest$ git checkout master Switched to branch 'master' kakakali@cyber:/mnt/d/gitest$ mv a.txt c.txt kakakali@cyber:/mnt/d/gitest$ git checkout dev D a.txt Switched to branch 'dev' kakakali@cyber:/mnt/d/gitest$ ls b.txt c.txt 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.