On Sat, Oct 27, 2012 at 03:51:00PM -0700, Matt Schoen wrote: > This is my first post so I'm not sure if there's a more appropriate way to > post a "bug" like this one but I've been using git for a few years now and > having learned most of the idiosyncrasies, there's one that still bugs me. > So I'm sure we're all familiar with the behavior or switching branches. > Sometimes, when I switch to a branch at an earlier state, some newly added > files will stick around from the previous (newer) branch which count as > "new" files to the current (older) branch. When I do this I'm often just > switching to the branch to test things out, poke around, and switch right > back. At that point, when I try to switch back to the newer branch, I > can't because "some files will be overwritten" even though those files came > from the branch I'm trying to switch to! > > I'm not exactly sure what should be the preferred behavior. Maybe git > could compare these files the ones that would overwrite them, or maybe it > could delete the files when switching out of that branch. It would be > great if this issue could be addressed, though.
You seem to maintain wrong mental model of how Git handles local modifications in your work tree (and this appears to be quite common). The thing is, while the work tree is always *based* on some recorded repository state referenced to by a commit, neither the work tree nor any local modifications you do there nor the index do belong to any branch. This is crucial to understand. Basically when you do `git checkout <whatever>`, Git ensures your work tree and the index match the repository state pointed to by <whatever>, and then sets the special reference named "HEAD" to contain that <whatever>. Then you start to modify files, record your changes to the index etc, and then you do a commit. Then you run `git commit` -- Git takes the index, builds a new commit out of it, *and only then* it does consult HEAD to see which commit will be the parent of that new commit. Git also checks if HEAD points to a branch, and if it is, that branch reference is updated to point to the newly created commit. You might now see that contrary to how it might feel, the work tree, the index and your local modifications to work tree do not really belong to any branch -- they are just used to build a new commit, and only then that commit might start to "belong" to somewhere. Consequently, when you're switching branches, you're changing the base versions of files your local modifications were made against. When populating the work tree and the index, Git sees which files in the work tree have local modifications; for each file found, Git checks if its "old" base version differs from its "new" base version, and if they're differ, Git refuses to proceed. Possibly you can now see that within the Git's model just described, this behaviour is logical. To combat this problem, there are two approaches: trying to merge the local modifications with the new base versions of modified files and saving/restoring local modifications. The first approach is about passing the "--merge" command-line option to `git checkout`. Read more in its man page. The second approach has two options: the stash and temporary ("work in progress") commits. With stashing, you just run `git stash` before switching the work tree to another commit -- Git saves away all your local changes and then resets the index and the work tree to HEAD so that they are "clean" and checking out another commit is guaranteed to succeed. When you're done with another branch and switch back, run `git stash pop` to recreate your local modifications. WIP commits do mostly the same thing: just commit all your local changes, stating your intent clearly in the commit message and switch to another branch. When you're done with that branch and switched back, run `git reset HEAD^` or `git reset --soft HEAD^` (the first form implies the "--mixed" command-line option) -- you'll get your local modifications back, but the WIP commit itself will go away. There are pros and cons of both approaches (stashing is simpler and quickier, more fine grained -- is able to restore the index to exact state it was when stashing, when you had both staged and unstaged local modifications; WIP commits can be pushed or pulled and possibly more "visible" to the user). One more thing: bug reporting should be done on the main (for developers) Git list which is git at vger.kernel.org; this list is for helping users dealing with their Git-related problems. -- You received this message because you are subscribed to the Google Groups "Git for human beings" group. To post to this group, send email to git-users@googlegroups.com. To unsubscribe from this group, send email to git-users+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/git-users?hl=en.