* On the behavior of checkout <branch> with uncommitted local changes @ 2013-09-19 9:23 r.ductor 2013-09-19 17:43 ` Junio C Hamano 0 siblings, 1 reply; 5+ messages in thread From: r.ductor @ 2013-09-19 9:23 UTC (permalink / raw) To: git Dear all I'm not a power git user but I profit of git every day and I like to fully understand what I do. The man section for git checkout is too vague for my taste. In particular it is not clearly (unambiguously) stated what happens to index and worktree whenever local uncommitted changes are around. I've already rised a similar problem in this mail list [1], but I understand that a man page must be concise. On the other hand, I couldn't find any complete information on this behavior: tutorials and books seem to avoid the problem, user posts seems confused ... To grasp some more information, I've spent some hours in trials (sorry I'm unable to grasp information browsing the code repository). That resulted in the algorithm below presented. Could anybody authoritative on that subject confirm/correct/discharge my statement? That could be of help for me and may others. Nonetheless to say having this kind of pseudocodes available somewhere (e.g. for stash [2] and other tools modifing index and working tree) would make my git experience (and that of many more people) happier. Thanks to all developers for their efforts. Regards ric Notations: let us fix a file and denote C0 = its version in the initial commit I0 = its version in the initial index W0 = its version in the working tree C1 = its version in the target commit W1= its version in working tree after checkout completed I1 = its version in index after checkout completed git checkout Branch if C0=W0=I0, then: W1=I1=C1; if C1=I0, then: W1=W0 and I1=C1=I0; if C1=C0, then: W1=W0 and I1=I0; otherwise: abort Note: in particular, if W0=I0 !=C0 then (in general) abort Note: in particular, if C0=I0 and C1=W0 then abort (...actually why that? no information is lost) REFS [1]http://thread.gmane.org/gmane.linux.debian.devel.bugs.general/782914/focus=164647 [2]http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=717088 ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: On the behavior of checkout <branch> with uncommitted local changes 2013-09-19 9:23 On the behavior of checkout <branch> with uncommitted local changes r.ductor @ 2013-09-19 17:43 ` Junio C Hamano 2013-09-20 13:33 ` r.ductor 0 siblings, 1 reply; 5+ messages in thread From: Junio C Hamano @ 2013-09-19 17:43 UTC (permalink / raw) To: r.ductor; +Cc: git r.ductor@gmail.com writes: > The man section for git checkout ... In > particular it is not clearly (unambiguously) stated what happens > to index and worktree whenever local uncommitted changes are > around. In the current text, the key information is in two places: 'git checkout' <branch>:: To prepare for working on <branch>, 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>. -m:: --merge:: When switching branches, if you have local modifications to one or more files that are different between the current branch and the branch to which you are switching, the command refuses to switch branches in order to preserve your modifications in context. Let's see how we can improve the text. Points to notice are: * "by updating the index and the files" does not say "how" they are updated and can be clarified: - The index is made to match the state the commit at the tip of <branch> records. - The working tree files without local modifications are updated the same way. - The working tree files with local modifications are not touched. * Because "the command refuses to checkout another branch under this and that condition" does not have its own section, the description of "-m" needs to say it as a background information to explain in what situation the option may be useful. It can be moved to the main "'git checkout' <branch>" part and it may make the result read easier. * "in order to preserve your modifications in context" is correct and sufficient description, but it requires some thinking in readers' part to understand why it is a good thing. It can be clarified. The thinking goes like this. Suppose your current branch has file X whose contents is X0 (that is, the commit at the tip of this branch records file X with content X0). You have local changes to this file and its contents is X1. The index at path X is unchanged and still records X0. The branch you are checking out has contents X2 at the path. If we allowed "git checkout <the other branch>" and simply kept the local changes, you will end up in a funny state in which: - The tip commit, that will become the parent commit when you make the next commit, has X2 at path X. - The index has X2 at path X to match the tip commit. You could change this to keep X0 but it does not matter in the larger picture, because you will be editing the working tree version and updating the index from there to prepare for the next commit. - The working tree has contents X1 at path X. But realize that the change "you" made is the difference between X0 and X1, not X2 and X1. If we allowed such a checkout and then you did "git commit -a", you will end up reverting the state between X0 (contents in your original branch) and X2 (contents in the new branch), even though the change you wanted to make was only the difference between X0 and X1. Also, if you did "git add X" and then "checkout <branch>", unless the version in the index at path X match either your original branch or the branch you are checking out, the command will stop you, and the "-m" option does not resolve this with a 4-way merge (it will be too complex for users to understand if we did so). ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: On the behavior of checkout <branch> with uncommitted local changes 2013-09-19 17:43 ` Junio C Hamano @ 2013-09-20 13:33 ` r.ductor 2013-09-20 22:58 ` Junio C Hamano 0 siblings, 1 reply; 5+ messages in thread From: r.ductor @ 2013-09-20 13:33 UTC (permalink / raw) To: Junio C Hamano; +Cc: git Dear Junio, thanks for your answer and you availability to revise the man text. Below my (irreverent) comments On Thursday 19 September 2013 10:43:16 Junio C Hamano wrote: > Let's see how we can improve the text. Points to notice are: > > * "by updating the index and the files" does not say "how" they are > updated and can be clarified: > > - The index is made to match the state the commit at the tip of > <branch> records. > > - The working tree files without local modifications are updated > the same way. > > - The working tree files with local modifications are not > touched. mmm maybe I'm wrong, but it seems to me that the first statement on the index (above) is oversimplifing and not correct in presence of local changes. In the example below, when in the branch 'dev' the index content was '2 in index' and the workspace content was '3 in work' and the commited contents dev:a=master:a='1'. In this case checkout completed and the index (and workspace) contents after checkout where preserved, hence the index was different from the head commit in both branches master and dev. $ echo '1'>a; git init; git add a; git commit -a -m '1';git checkout -b dev;echo '2 in index'>a;git add a; echo '3 in work'>a; git checkout master; cat a; git diff; git diff HEAD Initialized empty Git repository in /home/xxxx/git-test12/.git/ [master (root-commit) d0064f1] 1 1 file changed, 1 insertion(+) create mode 100644 a Switched to a new branch 'dev' M a Switched to branch 'master' 3 in work diff --git a/a b/a index d35137c..ee9231a 100644 --- a/a +++ b/a @@ -1 +1 @@ -2 in index +3 in work diff --git a/a b/a index d00491f..ee9231a 100644 --- a/a +++ b/a @@ -1 +1 @@ -1 +3 in work $ This is what I ment by the line "if C1=C0, then: W1=W0 and I1=I0;" ... am I missing something? > * Because "the command refuses to checkout another branch under > this and that condition" does not have its own section, the > description of "-m" needs to say it as a background information > to explain in what situation the option may be useful. It can be > moved to the main "'git checkout' <branch>" part and it may make > the result read easier. I 100% agree that the git checkout' <branch> should mention that the command might not complete in some cases, and hopefully describe when. A normal user (me) learning the command tries to first understand the simpler usage before going below and learning the action of the options. > "in order to preserve your modifications in context" is correct > and sufficient description :((( this is one of the points I considered "vague"... what is "context"? "parent commit" or "parent commit AND index" or "index"? the reader starts to asks theirself too much questions, whose aswers requires an educated guess that should ideally not be necessary when reading a man page.... Maybe I'm to much mathematically minded, but few clean lines of pseudocode explain everything without any doubt. > If we allowed such a checkout and then you did "git commit -a", > you will end up reverting the state between X0 (contents in your > original branch) and X2 (contents in the new branch), even though > the change you wanted to make was only the difference between X0 > and X1. > ... OK I understand your motivations, in your example the contents would have been preserved by checkout, but a shallow user could be then "overchange" by mistake. > > Also, if you did "git add X" and then "checkout <branch>", unless > the version in the index at path X match either your original branch > or the branch you are checking out, the command will stop you, ... disagree (or misunderstand), if X0=X2 and index = X1 (work) then checkout does not fail, an example would be the example above with echo '2 in index'>a; replaced by echo '3 in work'>a. $ echo '1'>a; git init; git add a; git commit -a -m '1';git checkout -b dev;echo '3 in work'>a;git add a; echo '3 in work'>a; git checkout master; cat a; git diff; git diff HEAD Initialized empty Git repository in /home/xxx/git-test13/.git/ [master (root-commit) f8d39d9] 1 1 file changed, 1 insertion(+) create mode 100644 a Switched to a new branch 'dev' M a Switched to branch 'master' 3 in work diff --git a/a b/a index d00491f..ee9231a 100644 --- a/a +++ b/a @@ -1 +1 @@ -1 +3 in work $ ... again, sorry if I'm stupidly missing a point or I'm too much irreverent. Any suggestion of references on that would be very welcome. ric PS, BTW, updated in your glossary my statement would be For each path, denote by C0 = its content in the head commit before checkout I0 = its content in the index before checkout W0 = its content in the working tree before checkout C1 = its content in the head commit of the target branch <branch> W1= its content in working tree after checkout <branch> successfully completed I1 = its content in index after checkout <branch> successfully completed then: if C0=W0=I0, then: W1=I1=C1; if C1=I0, then: W1=W0 and I1=C1=I0; if C1=C0, then: W1=W0 and I1=I0; otherwise: abort ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: On the behavior of checkout <branch> with uncommitted local changes 2013-09-20 13:33 ` r.ductor @ 2013-09-20 22:58 ` Junio C Hamano 2013-09-24 9:25 ` r.ductor 0 siblings, 1 reply; 5+ messages in thread From: Junio C Hamano @ 2013-09-20 22:58 UTC (permalink / raw) To: r.ductor; +Cc: git r.ductor@gmail.com writes: > mmm maybe I'm wrong, but it seems to me that the first statement > on the index (above) is oversimplifing. Yes, it was simplified to illustrate the principle, not even trying to be exhaustive. The principle is that we allow you to check out a different branch when you have local changes to the working tree and/or to the index, as long as we can make the index and the working tree pretend as if you reached that locally modified state, starting from a clean state of the branch you are checking out. That is what "your modifications in context" in the description of the "-m" option refers to. It directly follows that a local change to the index at a path is carried forward when you check out a different branch, if HEAD and the branch you are checking out have the same contents registered at the path. The message you are responding to illustrated that principle by talking about changes to the working tree but the same principle applies to changes to the index, as changes to the working tree is much easier to picture in your mind. ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: On the behavior of checkout <branch> with uncommitted local changes 2013-09-20 22:58 ` Junio C Hamano @ 2013-09-24 9:25 ` r.ductor 0 siblings, 0 replies; 5+ messages in thread From: r.ductor @ 2013-09-24 9:25 UTC (permalink / raw) To: Junio C Hamano; +Cc: git Dear Juno Thanks for your answer. My fair criticism in my previous emails (and below) is just to try to convince you that with a few short sentences you risk to transmit only vague ideas, while a serious user is interested to understand the behavior of git in any occurrence, with no ambiguity. Once more, in my view a short pseudo code -- or its equivalent in words -- would be a useful compromise among simplicity and accuracy. I'm attacking git checkout but I guess that what I say is a general problem of the git official documentation (i.e git stash in my experience has problems). Each undocumented feature (simulated by my dumb questions) enforces the loss of a significant percentage of the users. Lacking details, a hurried user will not use the feature, or if they are brave enough, they will use it without understanding (i.e. risking data loss one day or the other)... Lacking details, a serious user will have to waste their time in trials or in studing the sources. Do not fear that giving details in a man page would scare newbyes: as a git newbye I can say that what scares me is the lack of information, not the complexity(=power) of a program (*) Do not waste your precious time in explaining me/us general ideas, we can find them in the tens of pedagogic tutorials/books out there, please give us those details that nobody out there seems to know and that man (un)intentionally hides! I would be happy to submit a patch for the man git-checkout but I'm not sure that my understanding of git checkout (as encoded in the pseudocode I submitted) is correct. My friendly regards, ric (*) of course you're allowed to discard my suggestions pretending that I'm not a representative user ;) On Friday 20 September 2013 15:58:27 Junio C Hamano wrote: > The principle is that we allow you to check out a different branch > when you have local changes to the working tree and/or to the index, > as long as we can make the index and the working tree pretend as if > you reached that locally modified state, starting from a clean state > of the branch you are checking out. Of course I understand the idea, but if I try to grasp the details I'm in trouble: the problem in this statement is the ambiguity of "change" and "pretend as". In plain english I can start from any content and change it to any other content, so in this semantics your statement is empty, or worse. If I assume that change means "differences with N lines of unchanged context" I must still guess differences with respect to what? head-index, index-work, head-work ???? ... and how much is N? 3, 4, 1028? Then, in order to understand I (a user) make the trials below, and concludes that also the nice principle stated above is somewhat incomplete.... git-test15$ echo -e 'a\n1\n2\n3\n4\n5\nb\n6\n7\n8\n9\n10\n'>f; cat f;git init; git add f; git commit -a -m 'ab'; git checkout -b dev; echo -e 'A\n1\n2\n3\n4\n5\nb\n6\n7\n8\n9\n10\n'>f;cat f;git commit -a -m 'Ab'; echo -e 'A\n1\n2\n3\n4\n5\nB\n6\n7\n8\n9\n10\n'>f;cat f;git add f; git checkout master a 1 2 3 4 5 b 6 7 8 9 10 Initialized empty Git repository in /home/git-test15/.git/ [master (root-commit) 46d19ab] ab 1 file changed, 13 insertions(+) create mode 100644 f Switched to a new branch 'dev' A 1 2 3 4 5 b 6 7 8 9 10 [dev bb852db] Ab 1 file changed, 1 insertion(+), 1 deletion(-) A 1 2 3 4 5 B 6 7 8 9 10 error: Your local changes to the following files would be overwritten by checkout: f Please, commit your changes or stash them before you can switch branches. Aborting ##################################################################################### #### why abort the change w.r.t. dev was just b -> B and that patch was admissible in master ... I start questioning the principle #### ##################################################################################### git-test15$ mkdir ../gittest16 git-test15$ cd ../gittest16 gittest16$ echo -e 'a\n1\n2\n3\n4\n5\nb\n6\n7\n8\n9\n10\n'>f; cat f;git init; git add f; git commit -a -m 'ab'; git checkout -b dev; echo -e 'A\n1\n2\n3\n4\n5\nb\n6\n7\n8\n9\n10\n'>f;cat f;git commit -a -m 'Ab'; echo -e 'a\n1\n2\n3\n4\n5\nB\n6\n7\n8\n9\n10\n'>f;cat f;git add f; git checkout master a 1 2 3 4 5 b 6 7 8 9 10 Initialized empty Git repository in /home/gittest16/.git/ [master (root-commit) 7d7febe] ab 1 file changed, 13 insertions(+) create mode 100644 f Switched to a new branch 'dev' A 1 2 3 4 5 b 6 7 8 9 10 [dev 143db1d] Ab 1 file changed, 1 insertion(+), 1 deletion(-) a 1 2 3 4 5 B 6 7 8 9 10 error: Your local changes to the following files would be overwritten by checkout: f Please, commit your changes or stash them before you can switch branches. Aborting gittest16$ ##################################################################################### #### why abort? the change w.r.t. master was just b -> B and that patch was admissible in master ... I start questioning the principle #### ##################################################################################### ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2013-09-24 9:22 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2013-09-19 9:23 On the behavior of checkout <branch> with uncommitted local changes r.ductor 2013-09-19 17:43 ` Junio C Hamano 2013-09-20 13:33 ` r.ductor 2013-09-20 22:58 ` Junio C Hamano 2013-09-24 9:25 ` r.ductor
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).