{"thread":{"id":"26217","subject":"Re: git checkout branch behaves differently from what specified in man page","startedAt":"2011-01-06T17:35:22Z","lastAt":"2011-01-07T14:27:42Z","messageCount":4,"participants":["Jonathan Nieder","Junio C Hamano","r.ductor@gmail.com"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"159043","messageId":"20110106173522.GB11346@burratino","threadId":"26217","inReplyTo":"20110106154418.3348.29438.reportbug@localhost","subject":"Re: git checkout branch behaves differently from what specified in man page","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-01-06T17:35:22Z","receivedAt":"2011-01-06T17:35:22Z","isPatch":false,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi,\n\nr. ductor wrote[1]:\n\n>  git checkout [<branch>], git checkout -b <new branch> [<start point>] \n>\tThis form switches branches by updating the index, working tree,\n>\tand HEAD to reflect the specified branch. \"\n>\n> The key is the meaning of \"to reflect\": a normal (?) human being\n> like me understands that git  checkout branch will reset the\n> contents of working directory, and index exactly equal to that of\n> the head of the branch.  As you might know this is not true (see\n> example below).\n[example with both unregistered and staged local modifications]\n\nYes, I agree that this could be a lot clearer.  For reference, here's\nthe current description section:\n\n Updates files in the working tree to match the version in the index\n or the specified tree. If no paths are given, git checkout will also\n update HEAD to set the specified branch as the current branch.\n\n git checkout [<branch>], git checkout -b|-B <new_branch> [<start point>]\n\tThis form switches branches by updating the index, working tree,\n\tand HEAD to reflect the specified branch.\n\n\tIf -b is given,\n[... description of -b and -B ...]\n\n git checkout [--patch] [<tree-ish>] [--] <pathspec>...\n\tWhen <paths> or --patch are given, git checkout does not switch\n\tbranches. It updates the named paths in the working tree from\n\tthe index file or from a named <tree-ish> (most often a commit).\n\tIn this case, the -b and --track options are meaningless and\n\tgiving either of them results in an error. The <tree-ish>\n\targument can be used to specify a specific tree-ish (i.e.\n\tcommit, tag or tree) to update the index for the given paths\n\tbefore updating the working tree.\n\n\tThe index may contain unmerged entries because of a previous\n\tfailed merge.\n[... more details about the unmerged entries case ...]\n\nProposed clearer text would be welcome, especially if in the form of\na patch to Documentation/git-checkout.txt (see Documentation/SubmittingPatches).\n\nCurrently I think the examples section explains it better.  The\ndetails are something like this:\n\n - git checkout <branch> --\n\n\ttries to change the current branch to <branch>, dragging other\n\tstate kicking and screaming along with it.\n\n\t- if a file does _not_ differ between the current commit and\n\t  <branch>, it does not need to be touched.  Any local changes\n\t  in that file will be preserved.\n\n\t- if a file that _does_ differ between the current commit and\n\t  <branch> has local changes, git gives up --- the operation is\n\t  cancelled and all state is preserved.\n\t  This behavior can be tweaked with the --merge option.\n\n - git checkout <tree> -- <path specifiers>\n\n\tkeeping the current branch the same, grabs some files from <tree>\n\tto replace the current versions in the index and work tree\n\n\t- no matter what, the local state of the specified paths is\n\t  forgotten and both the index and worktree made to match <tree>\n\n\t- paths not specified are left alone.\n\nIf you just want to reset the worktree and index to match some\nbranch, then you can use\n\n\tgit reset --hard <branch>\n\nor\n\n\tgit checkout <tree> -- .\n\n.  The former even forgets what branch you were on (well, it is\nremembered in the reflog).  The latter adopts the content of <tree>\nas content registered for the next commit on the current branch.\n\nHope that helps,\nJonathan\n\n[1] http://bugs.debian.org/609128\n"},{"id":"159080","messageId":"20110106225222.GA15900@burratino","threadId":"26217","inReplyTo":"20110106173522.GB11346@burratino","subject":"[PATCH/RFC] Documentation/checkout: explain behavior wrt local changes","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-01-06T22:52:22Z","receivedAt":"2011-01-06T22:52:22Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Jonathan Nieder wrote:\n\n> Proposed clearer text would be welcome, especially if in the form of\n> a patch to Documentation/git-checkout.txt (see Documentation/SubmittingPatches).\n\nLike this, maybe?\n\n-- 8< --\nSubject: Documentation/checkout: explain behavior wrt local changes\n\nThe current start of the description to \"git checkout\" tries to\ncombine an explanation of \"git checkout <branch> --\" with \"git\ncheckout -- <paths>\" and ends up with a muddle (as Jeff noticed).\n\nIn particular, the text does not make it obvious that the \"git\ncheckout <branch> --\" form does not clobber local changes relative\nto the HEAD commit in the worktree and index.\n\nReported-by: r.ductor <r.ductor@gmail.com>\nHelped-by: Jeff King <peff@peff.net>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\nI somehow suspect that a mention of --merge would make this clearer\nbut good words for it aren't coming at the moment.  Improvements\nwelcome.\n\n Documentation/git-checkout.txt |   14 ++++++++------\n 1 files changed, 8 insertions(+), 6 deletions(-)\n\ndiff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt\nindex 22d3611..cfb71a8 100644\n--- a/Documentation/git-checkout.txt\n+++ b/Documentation/git-checkout.txt\n@@ -15,16 +15,18 @@ SYNOPSIS\n \n DESCRIPTION\n -----------\n-Updates files in the working tree to match the version in the index\n-or the specified tree.  If no paths are given, 'git checkout' will\n-also update `HEAD` to set the specified branch as the current\n-branch.\n+There are two different modes -- one to switch branches and one to\n+make some paths in the work tree match the index or specified tree.\n \n 'git checkout' [<branch>]::\n 'git checkout' -b|-B <new_branch> [<start point>]::\n \n-\tThis form switches branches by updating the index, working\n-\ttree, and HEAD to reflect the specified branch.\n+\tThis form switches branches by changing `HEAD` and updating the\n+\ttracked files to the specified branch.  'git checkout' will\n+\tstop without doing anything if local changes overlap with\n+\tchanges to the tracked files.  (Any local changes that do not\n+\toverlap with changes from `HEAD` to the specified branch will\n+\tbe preserved.)\n +\n If `-b` is given, a new branch is created as if linkgit:git-branch[1]\n were called and then checked out; in this case you can\n-- \n1.7.4.rc1\n"},{"id":"159083","messageId":"7vtyhl8t5y.fsf@alter.siamese.dyndns.org","threadId":"26217","inReplyTo":"20110106225222.GA15900@burratino","subject":"Re: [PATCH/RFC] Documentation/checkout: explain behavior wrt local changes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-01-07T00:16:25Z","receivedAt":"2011-01-07T00:16:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jonathan Nieder <jrnieder@gmail.com> writes:\n\n>  'git checkout' [<branch>]::\n>  'git checkout' -b|-B <new_branch> [<start point>]::\n>  \n> -\tThis form switches branches by updating the index, working\n> -\ttree, and HEAD to reflect the specified branch.\n> +\tThis form switches branches by changing `HEAD` and updating the\n> +\ttracked files to the specified branch.  'git checkout' will\n> +\tstop without doing anything if local changes overlap with\n> +\tchanges to the tracked files.  (Any local changes that do not\n> +\toverlap with changes from `HEAD` to the specified branch will\n> +\tbe preserved.)\n\nEven though I am fully aware that \"switch\" was an attempt to match the\nterminology from another SCM (e.g. svn), it may help readers in the longer\nterm if we stop using \"switch\" and instead explain this as \"checking out a\nbranch\" and what this action is _for_.  I suspect that an explanation of\nthe purpose would clarify the reason why the command does what it does.\n\nYou check out a branch to work on that branch, namely, eventually to\ncommit changes to that branch (as opposed to committing them to the\ncurrent branch).  For that purpose, the local changes obviously need to be\npreserved.  And that is why it refuses to act if paths with local changes\nneed to be updated.\n\nSide note.  When you check out a path (or a set of paths), you don't work\non these files (git does not track individual files), hence there is no\npossible interpretation other than \"get a fresh unmodified copy out of\nsomething\" when the command is used with paths, i.e. \"checking out paths\n(either out of the index or out of a named commit)\".\n\nIn any case, your rewrite is certainly an improvement compared to an\nunexplained \"reflect\", so I think this is a step in the right direction.\n\nThanks.\n"},{"id":"159113","messageId":"201101071527.42544.r.ductor@gmail.com","threadId":"26217","inReplyTo":"7vtyhl8t5y.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH/RFC] Documentation/checkout: explain behavior wrt local changes","fromName":"r.ductor@gmail.com","fromEmail":"r.ductor@gmail.com","sentAt":"2011-01-07T14:27:42Z","receivedAt":"2011-01-07T14:27:42Z","isPatch":true,"sender":{"key":"r.ductor@gmail.com","avatar":null},"body":"Dear all\n\nI'm a beginner git user trying to defend the beginners' party. Using Jonathan's explanations (and some educated guess on git behavior) I tried to concoct the man git-checkout documentation I would have liked to read, which is somewhat more explicit than Jonathan's patch. If you want to implement/improve it please double check it (and maybe warn me about my own errors). If you are happy about that I will try to send more suggestions. Thanks for your time and your work.\n\nriccardo   \n\ngit checkout [<branch>]\ngit checkout -b|-B <new_branch> [<start point>]\n\n     Tries to change the current HEAD to <branch> (or <start point>) and to safely update the working tree and the index.\n     If there exist files having three distinct contents in the current commit, in the new branch and in the working tree, then the operation is canceled and all state is preserved.\n     (This behavior may be changed with the option --merge.) If this is not the case, for all other files it acts as follows.  \n       - Files not differing between the current commit and the new branch: their contents in the working tree (and eventually in the index) are left unchanged. \n       - Files in the current commit, unchanged or absent in the working tree, but not present in the new branch are removed from the working tree and from the index.\n       - Files in the new branch but not in the current commit are added to the working tree and to the index (if they were already there they must have had the same contents by hypothesis).\n       - Files in the working tree or in the index that are absent in the current commit and in the new branch are left unchanged.\n    \n    If -b is given, ...\n\n\n\nOn Friday 07 January 2011 01:16:25 Junio C Hamano wrote:\n> Jonathan Nieder <jrnieder@gmail.com> writes:\n> \n> >  'git checkout' [<branch>]::\n> >  'git checkout' -b|-B <new_branch> [<start point>]::\n> >  \n> > -\tThis form switches branches by updating the index, working\n> > -\ttree, and HEAD to reflect the specified branch.\n> > +\tThis form switches branches by changing `HEAD` and updating the\n> > +\ttracked files to the specified branch.  'git checkout' will\n> > +\tstop without doing anything if local changes overlap with\n> > +\tchanges to the tracked files.  (Any local changes that do not\n> > +\toverlap with changes from `HEAD` to the specified branch will\n> > +\tbe preserved.)\n> \n"}]}