{"thread":{"id":"30767","subject":"Help understanding git checkout behavior","startedAt":"2012-06-11T16:52:26Z","lastAt":"2012-06-11T22:45:45Z","messageCount":13,"participants":["Cláudio Lourenço","Konstantin Khomoutov","konglu@minatec.inpg.fr","Leila","Vincent van Ravesteijn","Jeff King","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"193327","messageId":"CAMUXYmUFbixgA1bVMA46Zzjed1Dwmjv54kWWXyjsuyu904GpTA@mail.gmail.com","threadId":"30767","inReplyTo":null,"subject":"Help understanding git checkout behavior","fromName":"Cláudio Lourenço","fromEmail":"pt.smooke@gmail.com","sentAt":"2012-06-11T16:52:26Z","receivedAt":"2012-06-11T16:52:26Z","isPatch":false,"sender":{"key":"pt.smooke@gmail.com","avatar":null},"body":"Hello,\n\nWe are master students at University of Minho in Portugal and we are\ncurrently working on a project suggested by CSAIL (MIT), called\n\"Understanding Git with Alloy\". The project consists in modeling git\nusing alloy and then check for some properties that git does (not)\nguarantee.\n\nThe project was going pretty fine, till we start modeling the checkout\noperation. We are with some problems finding useful information about\nthe properties that have to be satisfied when the \"git checkout\" is\nperformed. We have concluded that if everything that is on index is\ncommited then we have no problems making checkout.\nThe problem is when we have something on index that is not updated\nwith the last commit. We cannot find a general property that says when\ncheckout can be performed. We have even found some files that are\nlost, like in this case:\n\nsmooke  teste $ git init\nInitialized empty Git repository in /home/smooke/Dropbox/teste/.git/\nsmooke  teste $ touch f\nsmooke  teste $ echo a > f\nsmooke  teste $ git add f\nsmooke  teste $ git commit -m 'first commit'\n[master (root-commit) dab04b9] first commit\n 1 files changed, 1 insertions(+), 0 deletions(-)\n create mode 100644 f\nsmooke  teste $ git branch b\nsmooke  teste $ touch something\nsmooke  teste $ echo b > something\nsmooke  teste $ git add something\nsmooke  teste $ git commit -m 'something added'\n[master 9f2b8ad] something added\n 1 files changed, 1 insertions(+), 0 deletions(-)\n create mode 100644 something\nsmooke  teste $ git rm something\nrm 'something'\nsmooke  teste $ mkdir something\nsmooke  teste $ cd something/\nsmooke  something $ touch f1\nsmooke  something $ echo c > f1\nsmooke  something $ cd ..\nsmooke  teste $ git add something/f1\nsmooke  teste $ git checkout b\nSwitched to branch 'b'\nsmooke  teste $ ls\nf\nsmooke  teste $ git checkout master\nSwitched to branch 'master'\nsmooke  teste $ ls\nf  something\nsmooke  teste $ cat something\nb\n\nWe are not sure if this behavior has an explanation of if it is just a bug.\n\nWe are hoping that you could clarify us about this operation or\nrecommend us some place where we can find some useful information\nabout this...\n\nThank you in advance,\nBest regards,\n\nCláudio and Renato\n"},{"id":"193332","messageId":"20120611210742.7983d92d.kostix+git@domain007.com","threadId":"30767","inReplyTo":"CAMUXYmUFbixgA1bVMA46Zzjed1Dwmjv54kWWXyjsuyu904GpTA@mail.gmail.com","subject":"Re: Help understanding git checkout behavior","fromName":"Konstantin Khomoutov","fromEmail":"kostix+git@007spb.ru","sentAt":"2012-06-11T17:07:42Z","receivedAt":"2012-06-11T17:07:42Z","isPatch":false,"sender":{"key":"kostix+git@007spb.ru","avatar":null},"body":"On Mon, 11 Jun 2012 17:52:26 +0100\nCláudio Lourenço <pt.smooke@gmail.com> wrote:\n\n> We are master students at University of Minho in Portugal and we are\n> currently working on a project suggested by CSAIL (MIT), called\n> \"Understanding Git with Alloy\". The project consists in modeling git\n> using alloy and then check for some properties that git does (not)\n> guarantee.\nI think providing a link to that \"alloy\" thing could be helpful.\n\n[...]\n"},{"id":"193342","messageId":"20120611202132.Horde.dPo1XHwdC4BP1jcsTvSBaFA@webmail.minatec.grenoble-inp.fr","threadId":"30767","inReplyTo":"CAMUXYmUFbixgA1bVMA46Zzjed1Dwmjv54kWWXyjsuyu904GpTA@mail.gmail.com","subject":"Re: Help understanding git checkout behavior","fromName":"","fromEmail":"konglu@minatec.inpg.fr","sentAt":"2012-06-11T18:21:32Z","receivedAt":"2012-06-11T18:21:32Z","isPatch":false,"sender":{"key":"konglu@minatec.inpg.fr","avatar":null},"body":"\nCláudio Lourenço <pt.smooke@gmail.com> a écrit :\n\n> The project was going pretty fine, till we start modeling the checkout\n> operation. We are with some problems finding useful information about\n> the properties that have to be satisfied when the \"git checkout\" is\n> performed. We have concluded that if everything that is on index is\n> commited then we have no problems making checkout.\n> The problem is when we have something on index that is not updated\n> with the last commit. We cannot find a general property that says when\n> checkout can be performed. We have even found some files that are\n> lost, like in this case:\n>\n> smooke  teste $ git init\n> Initialized empty Git repository in /home/smooke/Dropbox/teste/.git/\n> smooke  teste $ touch f\n> smooke  teste $ echo a > f\n> smooke  teste $ git add f\n> smooke  teste $ git commit -m 'first commit'\n> [master (root-commit) dab04b9] first commit\n>  1 files changed, 1 insertions(+), 0 deletions(-)\n>  create mode 100644 f\n> smooke  teste $ git branch b\n> smooke  teste $ touch something\n> smooke  teste $ echo b > something\n> smooke  teste $ git add something\n> smooke  teste $ git commit -m 'something added'\n> [master 9f2b8ad] something added\n>  1 files changed, 1 insertions(+), 0 deletions(-)\n>  create mode 100644 something\n> smooke  teste $ git rm something\n> rm 'something'\n> smooke  teste $ mkdir something\n> smooke  teste $ cd something/\n> smooke  something $ touch f1\n> smooke  something $ echo c > f1\n> smooke  something $ cd ..\n> smooke  teste $ git add something/f1\n> smooke  teste $ git checkout b\n> Switched to branch 'b'\n> smooke  teste $ ls\n> f\n> smooke  teste $ git checkout master\n> Switched to branch 'master'\n> smooke  teste $ ls\n> f  something\n> smooke  teste $ cat something\n> b\n\nWhat do you mean by \"lost files\" ? Are you talking about \"something\"\nthat doesn't appear on branch 'b' ?\n"},{"id":"193343","messageId":"CAA3EhH+iD-sS-3Sg4HJDHgs4Deg2=qbCuJD4UwZWtGQsKbV5aA@mail.gmail.com","threadId":"30767","inReplyTo":"20120611202132.Horde.dPo1XHwdC4BP1jcsTvSBaFA@webmail.minatec.grenoble-inp.fr","subject":"Re: Help understanding git checkout behavior","fromName":"Leila","fromEmail":"muhtasib@gmail.com","sentAt":"2012-06-11T18:34:01Z","receivedAt":"2012-06-11T18:34:01Z","isPatch":false,"sender":{"key":"muhtasib@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1618875?v=4"},"body":"When you create a branch, it will contain everything committed on the\nbranch you created it from at that given point. So if you commit more\nthings on the master branch like you have done (after creating b),\nthen switch to branch b, they won't appear. This is the correct\nbehavior. Does that answer your question?\n\n\nOn Mon, Jun 11, 2012 at 2:21 PM,  <konglu@minatec.inpg.fr> wrote:\n>\n> Cláudio Lourenço <pt.smooke@gmail.com> a écrit :\n>\n>\n>> The project was going pretty fine, till we start modeling the checkout\n>> operation. We are with some problems finding useful information about\n>> the properties that have to be satisfied when the \"git checkout\" is\n>> performed. We have concluded that if everything that is on index is\n>> commited then we have no problems making checkout.\n>> The problem is when we have something on index that is not updated\n>> with the last commit. We cannot find a general property that says when\n>> checkout can be performed. We have even found some files that are\n>> lost, like in this case:\n>>\n>> smooke  teste $ git init\n>> Initialized empty Git repository in /home/smooke/Dropbox/teste/.git/\n>> smooke  teste $ touch f\n>> smooke  teste $ echo a > f\n>> smooke  teste $ git add f\n>> smooke  teste $ git commit -m 'first commit'\n>> [master (root-commit) dab04b9] first commit\n>>  1 files changed, 1 insertions(+), 0 deletions(-)\n>>  create mode 100644 f\n>> smooke  teste $ git branch b\n>> smooke  teste $ touch something\n>> smooke  teste $ echo b > something\n>> smooke  teste $ git add something\n>> smooke  teste $ git commit -m 'something added'\n>> [master 9f2b8ad] something added\n>>  1 files changed, 1 insertions(+), 0 deletions(-)\n>>  create mode 100644 something\n>> smooke  teste $ git rm something\n>> rm 'something'\n>> smooke  teste $ mkdir something\n>> smooke  teste $ cd something/\n>> smooke  something $ touch f1\n>> smooke  something $ echo c > f1\n>> smooke  something $ cd ..\n>> smooke  teste $ git add something/f1\n>> smooke  teste $ git checkout b\n>> Switched to branch 'b'\n>> smooke  teste $ ls\n>> f\n>> smooke  teste $ git checkout master\n>> Switched to branch 'master'\n>> smooke  teste $ ls\n>> f  something\n>> smooke  teste $ cat something\n>> b\n>\n>\n> What do you mean by \"lost files\" ? Are you talking about \"something\"\n> that doesn't appear on branch 'b' ?\n>\n>\n>\n> --\n> To unsubscribe from this list: send the line \"unsubscribe git\" in\n> the body of a message to majordomo@vger.kernel.org\n> More majordomo info at  http://vger.kernel.org/majordomo-info.html\n"},{"id":"193348","messageId":"4FD63E70.4000309@lyx.org","threadId":"30767","inReplyTo":"CAMUXYmUFbixgA1bVMA46Zzjed1Dwmjv54kWWXyjsuyu904GpTA@mail.gmail.com","subject":"Re: Help understanding git checkout behavior","fromName":"Vincent van Ravesteijn","fromEmail":"vfr@lyx.org","sentAt":"2012-06-11T18:52:32Z","receivedAt":"2012-06-11T18:52:32Z","isPatch":false,"sender":{"key":"vfr@lyx.org","avatar":"https://avatars.githubusercontent.com/u/687868?v=4"},"body":"Op 11-6-2012 18:52, Cláudio Lourenço schreef:\n> We are not sure if this behavior has an explanation of if it is just a bug.\n>\n> We are hoping that you could clarify us about this operation or\n> recommend us some place where we can find some useful information\n> about this...\n\nI think it is a bug. The file \"something/f1\" should be retained when \nswitching branches. So, checkout should fail because \"something\" would \nget overwritten by checkout, but it doesn't.\n\nVincent\n"},{"id":"193349","messageId":"20120611185507.GF20134@sigill.intra.peff.net","threadId":"30767","inReplyTo":"CAA3EhH+iD-sS-3Sg4HJDHgs4Deg2=qbCuJD4UwZWtGQsKbV5aA@mail.gmail.com","subject":"Re: Help understanding git checkout behavior","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2012-06-11T18:55:07Z","receivedAt":"2012-06-11T18:55:07Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Jun 11, 2012 at 02:34:01PM -0400, Leila wrote:\n\n> When you create a branch, it will contain everything committed on the\n> branch you created it from at that given point. So if you commit more\n> things on the master branch like you have done (after creating b),\n> then switch to branch b, they won't appear. This is the correct\n> behavior. Does that answer your question?\n\nNo, the problem is more subtle:\n\n> >> smooke  teste $ git rm something\n> >> rm 'something'\n> >> smooke  teste $ mkdir something\n> >> smooke  teste $ cd something/\n> >> smooke  something $ touch f1\n> >> smooke  something $ echo c > f1\n> >> smooke  something $ cd ..\n> >> smooke  teste $ git add something/f1\n> >> smooke  teste $ git checkout b\n> >> Switched to branch 'b'\n> >> smooke  teste $ ls\n> >> f\n\nWe have lost \"something/f1\" during the switch, which was not committed\nanywhere. This is presumably an error because we see that \"something\"\nused to be tracked, and now we are tracking something different there.\n\nIf we had put some new content into the file \"something\", git would\nrightfully complain with:\n\n  $ git checkout b\n  error: Your local changes to the following files would be overwritten\n  by checkout:\n          something\n  Please, commit your changes or stash them before you can switch branches.\n  Aborting\n\nBut it misses the case when \"something\" switches from a file into a\ndirectory, which is probably a bug.\n\n-Peff\n"},{"id":"193351","messageId":"7vaa097k3q.fsf@alter.siamese.dyndns.org","threadId":"30767","inReplyTo":"CAA3EhH+iD-sS-3Sg4HJDHgs4Deg2=qbCuJD4UwZWtGQsKbV5aA@mail.gmail.com","subject":"Re: Help understanding git checkout behavior","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-11T18:56:57Z","receivedAt":"2012-06-11T18:56:57Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Leila <muhtasib@gmail.com> writes:\n\n> When you create a branch, it will contain everything committed on the\n> branch you created it from at that given point. So if you commit more\n> things on the master branch like you have done (after creating b),\n> then switch to branch b, they won't appear. This is the correct\n> behavior. Does that answer your question?\n\nIf there were \"git commit\" immediately before the \"git checkout b\"\nto check out the branch \"b\", then something/f1 would be among the\ndata committed to the branch \"master\", and it is perfectly fine to\nremove it in order to check out branch \"b\" that does not have the\ndirectory \"something\" or file in it \"something/f1\".\n\nBut if there is \"something/f1\" that is not yet committed, the\ncommand should have refused to check out the branch \"b\", which I\nthink is what Cláudio is talking about.  It looks like a bug to me.\n\n>\n>\n> On Mon, Jun 11, 2012 at 2:21 PM,  <konglu@minatec.inpg.fr> wrote:\n>>\n>> Cláudio Lourenço <pt.smooke@gmail.com> a écrit :\n>>\n>>\n>>> The project was going pretty fine, till we start modeling the checkout\n>>> operation. We are with some problems finding useful information about\n>>> the properties that have to be satisfied when the \"git checkout\" is\n>>> performed. We have concluded that if everything that is on index is\n>>> commited then we have no problems making checkout.\n>>> The problem is when we have something on index that is not updated\n>>> with the last commit. We cannot find a general property that says when\n>>> checkout can be performed. We have even found some files that are\n>>> lost, like in this case:\n>>>\n>>> smooke  teste $ git init\n>>> Initialized empty Git repository in /home/smooke/Dropbox/teste/.git/\n>>> smooke  teste $ touch f\n>>> smooke  teste $ echo a > f\n>>> smooke  teste $ git add f\n>>> smooke  teste $ git commit -m 'first commit'\n>>> [master (root-commit) dab04b9] first commit\n>>>  1 files changed, 1 insertions(+), 0 deletions(-)\n>>>  create mode 100644 f\n>>> smooke  teste $ git branch b\n>>> smooke  teste $ touch something\n>>> smooke  teste $ echo b > something\n>>> smooke  teste $ git add something\n>>> smooke  teste $ git commit -m 'something added'\n>>> [master 9f2b8ad] something added\n>>>  1 files changed, 1 insertions(+), 0 deletions(-)\n>>>  create mode 100644 something\n>>> smooke  teste $ git rm something\n>>> rm 'something'\n>>> smooke  teste $ mkdir something\n>>> smooke  teste $ cd something/\n>>> smooke  something $ touch f1\n>>> smooke  something $ echo c > f1\n>>> smooke  something $ cd ..\n>>> smooke  teste $ git add something/f1\n>>> smooke  teste $ git checkout b\n>>> Switched to branch 'b'\n>>> smooke  teste $ ls\n>>> f\n>>> smooke  teste $ git checkout master\n>>> Switched to branch 'master'\n>>> smooke  teste $ ls\n>>> f  something\n>>> smooke  teste $ cat something\n>>> b\n>>\n>>\n>> What do you mean by \"lost files\" ? Are you talking about \"something\"\n>> that doesn't appear on branch 'b' ?\n>>\n>>\n>>\n>> --\n>> To unsubscribe from this list: send the line \"unsubscribe git\" in\n>> the body of a message to majordomo@vger.kernel.org\n>> More majordomo info at  http://vger.kernel.org/majordomo-info.html\n"},{"id":"193378","messageId":"CAMUXYmUg12z8LUcFKwjH0Utrvxx0fa5Sne0u9adgoZ=oooBbig@mail.gmail.com","threadId":"30767","inReplyTo":"7vaa097k3q.fsf@alter.siamese.dyndns.org","subject":"Re: Help understanding git checkout behavior","fromName":"Cláudio Lourenço","fromEmail":"pt.smooke@gmail.com","sentAt":"2012-06-11T20:48:06Z","receivedAt":"2012-06-11T20:48:06Z","isPatch":false,"sender":{"key":"pt.smooke@gmail.com","avatar":null},"body":"First of all, thank you all for your attention.\nThe link for alloy is http://alloy.mit.edu/alloy/  Feel free to take a\nlook, but this is not the point. We just want to understand what are\nthe pre-conditions that have to be satisfied to perform checkout.\n\nWe have done some tests and we concluded that it is possible to checkout if:\n\nfor each file that is on index, but not on the last commit, we have\ntwo cases when it is possible to checkout (from master) to branch b\n\n   first: the file is not on the commit pointed by branch b\n\n   second: the file is on the commit pointed by branch b, and it has\nthe same content as the file on index, or, the file of both commits\n(master and b) have the same content\n\nThe deleted files from index, are just ignored (we think the bug comes\nfrom here).\n\nAre our assumptions corrects? Is there any place were we can see such\nspecifications?\n\n\n\nOn Mon, Jun 11, 2012 at 7:56 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Leila <muhtasib@gmail.com> writes:\n>\n>> When you create a branch, it will contain everything committed on the\n>> branch you created it from at that given point. So if you commit more\n>> things on the master branch like you have done (after creating b),\n>> then switch to branch b, they won't appear. This is the correct\n>> behavior. Does that answer your question?\n>\n> If there were \"git commit\" immediately before the \"git checkout b\"\n> to check out the branch \"b\", then something/f1 would be among the\n> data committed to the branch \"master\", and it is perfectly fine to\n> remove it in order to check out branch \"b\" that does not have the\n> directory \"something\" or file in it \"something/f1\".\n>\n> But if there is \"something/f1\" that is not yet committed, the\n> command should have refused to check out the branch \"b\", which I\n> think is what Cláudio is talking about.  It looks like a bug to me.\n>\n>>\n>>\n>> On Mon, Jun 11, 2012 at 2:21 PM,  <konglu@minatec.inpg.fr> wrote:\n>>>\n>>> Cláudio Lourenço <pt.smooke@gmail.com> a écrit :\n>>>\n>>>\n>>>> The project was going pretty fine, till we start modeling the checkout\n>>>> operation. We are with some problems finding useful information about\n>>>> the properties that have to be satisfied when the \"git checkout\" is\n>>>> performed. We have concluded that if everything that is on index is\n>>>> commited then we have no problems making checkout.\n>>>> The problem is when we have something on index that is not updated\n>>>> with the last commit. We cannot find a general property that says when\n>>>> checkout can be performed. We have even found some files that are\n>>>> lost, like in this case:\n>>>>\n>>>> smooke  teste $ git init\n>>>> Initialized empty Git repository in /home/smooke/Dropbox/teste/.git/\n>>>> smooke  teste $ touch f\n>>>> smooke  teste $ echo a > f\n>>>> smooke  teste $ git add f\n>>>> smooke  teste $ git commit -m 'first commit'\n>>>> [master (root-commit) dab04b9] first commit\n>>>>  1 files changed, 1 insertions(+), 0 deletions(-)\n>>>>  create mode 100644 f\n>>>> smooke  teste $ git branch b\n>>>> smooke  teste $ touch something\n>>>> smooke  teste $ echo b > something\n>>>> smooke  teste $ git add something\n>>>> smooke  teste $ git commit -m 'something added'\n>>>> [master 9f2b8ad] something added\n>>>>  1 files changed, 1 insertions(+), 0 deletions(-)\n>>>>  create mode 100644 something\n>>>> smooke  teste $ git rm something\n>>>> rm 'something'\n>>>> smooke  teste $ mkdir something\n>>>> smooke  teste $ cd something/\n>>>> smooke  something $ touch f1\n>>>> smooke  something $ echo c > f1\n>>>> smooke  something $ cd ..\n>>>> smooke  teste $ git add something/f1\n>>>> smooke  teste $ git checkout b\n>>>> Switched to branch 'b'\n>>>> smooke  teste $ ls\n>>>> f\n>>>> smooke  teste $ git checkout master\n>>>> Switched to branch 'master'\n>>>> smooke  teste $ ls\n>>>> f  something\n>>>> smooke  teste $ cat something\n>>>> b\n>>>\n>>>\n>>> What do you mean by \"lost files\" ? Are you talking about \"something\"\n>>> that doesn't appear on branch 'b' ?\n>>>\n>>>\n>>>\n>>> --\n>>> To unsubscribe from this list: send the line \"unsubscribe git\" in\n>>> the body of a message to majordomo@vger.kernel.org\n>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html\n"},{"id":"193381","messageId":"7vobop5zmp.fsf@alter.siamese.dyndns.org","threadId":"30767","inReplyTo":"CAMUXYmUg12z8LUcFKwjH0Utrvxx0fa5Sne0u9adgoZ=oooBbig@mail.gmail.com","subject":"Re: Help understanding git checkout behavior","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-11T21:04:30Z","receivedAt":"2012-06-11T21:04:30Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Cláudio Lourenço <pt.smooke@gmail.com> writes:\n\n> The deleted files from index, are just ignored (we think the bug comes\n> from here).\n\nNot really.  In general, \"git checkout b\" (no path arguments,\nchecking out the branch \"b\") will try to keep the local changes you\nmade to the index and to the working tree for a path that are the\nsame between your current branch and the branch \"b\".  So it is\nperfectly normal to see:\n\n        $ git checkout master\n        $ git ls-files file\n        file\n\t... ok, the master branch has \"file\"\n\t$ git diff master side | grep file\n        ... ok, the side branch also has it and it is the same\n        $ git rm file\n        $ git checkout side\n\tD\tfile\n\tSwitched to branch 'side'\n\nSo it actually _actively_ pays attention to paths deleted or\nmodified in the index.\n\nAnother thing it does is when the local change to the index matches\nthat of the branch you are switching to, checkout is allowed even if\npath is different between two branches.\n\nWhen checking the differences between the two branches (the current\nand the new), unpack-trees notices that the path \"something\" is not\npresent in \"b\" branch, and even though your current branch and the\nindex differs (the index does not have \"something\" as you have\nremoved it), it thinks it is OK for the result to not have it (which\nis correct).  And when it does that, it forgets that a new path\n\"something/f1\" still needs to be kept (which is not correct), which\nis where the problem you are seeing comes from, methinks.\n"},{"id":"193387","messageId":"7vk3zd5y8d.fsf@alter.siamese.dyndns.org","threadId":"30767","inReplyTo":"7vobop5zmp.fsf@alter.siamese.dyndns.org","subject":"Re: Help understanding git checkout behavior","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-11T21:34:42Z","receivedAt":"2012-06-11T21:34:42Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> When checking the differences between the two branches (the current\n> and the new), unpack-trees notices that the path \"something\" is not\n> present in \"b\" branch, and even though your current branch and the\n> index differs (the index does not have \"something\" as you have\n> removed it), it thinks it is OK for the result to not have it (which\n> is correct).  And when it does that, it forgets that a new path\n> \"something/f1\" still needs to be kept (which is not correct), which\n> is where the problem you are seeing comes from, methinks.\n\nSo there are two paths involved in this two-way merge.\n\nThe master branch (HEAD) has \"something\", but not \"something/f1\".\nThe index does not have \"something\", but has \"something/f1\".\nThe \"b\" branch does not have either.\n\nFor path \"something\", the rule 2 in the \"Two Tree Merge\" section of\nDocumentation/git-read-tree.txt applies.  It does not exist in the\nindex, it does exist in HEAD, and it does not exist in the other\nbranch we are checking out.  The result should be to remove it.\n\nFor path \"something/f1\", the rule 4 ought to apply.  The index entry\nfor it is up to date with respect to the working tree file\n(i.e. clean), the HEAD does not have it, and the other branch does\nnot have it either.  We should be keeping it intact across the\ncheckout.  For whatever reason, this is not happening and I suspect\nthat is because we have to remove \"something\" due to rule 2.\n\nI just checked the history of unpack-trees code (which is the\nunderlying machinery of read-tree, which in turn is the machinery\nused to check out another branch by \"git checkout\"), and I suspect\nthat this particular case has never worked.\n"},{"id":"193390","messageId":"20120611214705.GC32061@sigill.intra.peff.net","threadId":"30767","inReplyTo":"7vk3zd5y8d.fsf@alter.siamese.dyndns.org","subject":"Re: Help understanding git checkout behavior","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2012-06-11T21:47:05Z","receivedAt":"2012-06-11T21:47:05Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Jun 11, 2012 at 02:34:42PM -0700, Junio C Hamano wrote:\n\n> So there are two paths involved in this two-way merge.\n> \n> The master branch (HEAD) has \"something\", but not \"something/f1\".\n> The index does not have \"something\", but has \"something/f1\".\n> The \"b\" branch does not have either.\n> \n> For path \"something\", the rule 2 in the \"Two Tree Merge\" section of\n> Documentation/git-read-tree.txt applies.  It does not exist in the\n> index, it does exist in HEAD, and it does not exist in the other\n> branch we are checking out.  The result should be to remove it.\n> \n> For path \"something/f1\", the rule 4 ought to apply.  The index entry\n> for it is up to date with respect to the working tree file\n> (i.e. clean), the HEAD does not have it, and the other branch does\n> not have it either.  We should be keeping it intact across the\n> checkout.  For whatever reason, this is not happening and I suspect\n> that is because we have to remove \"something\" due to rule 2.\n\nI think the problem is in verify_clean_subdirectory, which checks that\nwe do not have untracked files in the subdirectory, nor modifications\nbetween the index and working tree. But I do not see it checking whether\nwe have modifications from the HEAD.\n\n> I just checked the history of unpack-trees code (which is the\n> underlying machinery of read-tree, which in turn is the machinery\n> used to check out another branch by \"git checkout\"), and I suspect\n> that this particular case has never worked.\n\nYeah, I verified it back to v1.6.x, but didn't bother going further\nback.\n\n-Peff\n"},{"id":"193393","messageId":"20120611215808.GA6832@sigill.intra.peff.net","threadId":"30767","inReplyTo":"20120611214705.GC32061@sigill.intra.peff.net","subject":"Re: Help understanding git checkout behavior","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2012-06-11T21:58:09Z","receivedAt":"2012-06-11T21:58:09Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Jun 11, 2012 at 05:47:05PM -0400, Jeff King wrote:\n\n> > I just checked the history of unpack-trees code (which is the\n> > underlying machinery of read-tree, which in turn is the machinery\n> > used to check out another branch by \"git checkout\"), and I suspect\n> > that this particular case has never worked.\n> \n> Yeah, I verified it back to v1.6.x, but didn't bother going further\n> back.\n\nActually, it was broken by c819353 (Fix switching to a branch with D/F\nwhen current branch has file D., 2007-03-15).\n\nHowever, before that the check was too tight, and says:\n\n  fatal: Untracked working tree file 'something' would be removed by merge.\n\nwhich is not really correct, either.\n\n-Peff\n"},{"id":"193400","messageId":"7vfwa15uxy.fsf@alter.siamese.dyndns.org","threadId":"30767","inReplyTo":"20120611214705.GC32061@sigill.intra.peff.net","subject":"Re: Help understanding git checkout behavior","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-11T22:45:45Z","receivedAt":"2012-06-11T22:45:45Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> I think the problem is in verify_clean_subdirectory, which checks that\n> we do not have untracked files in the subdirectory, nor modifications\n> between the index and working tree. But I do not see it checking whether\n> we have modifications from the HEAD.\n\nI actually think \"comparison with HEAD\" is a red herring.  As long\nas the version in the index matches the version in the other branch\nwe are checking out, it does not matter if the version in the index\nis different from the version in HEAD (case 4).  Also if the version\nin the index is new and neither HEAD nor the other branch has it, we\nshould keep it (case 2).  And we should error out if these are not\npossible.\n\nI did a bit more digging on this; even though I am not going to\ncontinue it further today, here is a snapshot of my current\nthinking.\n\nAfter replacing \"something\" with \"something/f1\" in the index,\nattempting to \"read-tree -m -u master b\" (which is what checkout is\nabout) decides that the regular file \"something\" should not exist,\nbecause it is in \"master\" but not in \"b\", so it calls\n\n\tdeleted_entry(ce = master's version, old = NULL)\n\nwhere \"old\" is the version of \"something\" in the index, i.e. \"does\nnot exist\".  This in turn calls verify_absent(ce) to make sure that\nit is OK to remove regular file \"something\".  verify_absent() checks\nthe path \"something\" with lstat(), and it would be happy if there\nweren't \"something\", as there won't be anything necessary to do in\nthat case.\n\nBut it finds a directory.  It calls check_ok_to_remove() on it.\nThis is where things go wrong.  This function is to see if it is ok\nto nuke the entire directory \"something\", for the more common case\nwhere we are about to create a different \"something\" there. It is an\nappropriate check if we were trying to create a version of regular\nfile \"something\" from the branch we are trying to check out, but it\nis a wrong thing to do when we are not interested in touching\n\"something\" in any way.  We do not have regular file \"something\"\nnow, and after checking out the branch, we do not want to have\nregular file \"something\" there, either ---so all we have to do is to\ndo nothing!\n\nInstead, it says \"Ah, something/f1 is clean\", sets o->cache_bottom\nto skip it, and the machinery loses sight of that path.\n\nProbably we need to vet the caller of verify_absent() to see why\neach caller wants to call it.  Some may be about to create a new\nthing there, and really want to make sure there is nothing there\nafter they are done.  But this caller, when it _knows_ the path is\nalready removed (it can tell in check_ok_to_remove() after lstat()\nsays there is a directory \"something\" there---at that point we know\nthe regular file \"something\" cannot be there), should just be happy\nand let the later callers to look at the remaining cache entries\nwithout marking everything under something/* has been processed.\n\nOr something like that.\n"}]}