{"thread":{"id":"12766","subject":"Two bugs with renaming","startedAt":"2008-03-19T23:21:27Z","lastAt":"2008-03-20T04:45:53Z","messageCount":9,"participants":["John Goerzen","Junio C Hamano","Jeff King","Björn Steinbrink","Linus Torvalds"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"72443","messageId":"slrnfu37vn.d2i.jgoerzen@katherina.lan.complete.org","threadId":"12766","inReplyTo":null,"subject":"Two bugs with renaming","fromName":"John Goerzen","fromEmail":"jgoerzen@complete.org","sentAt":"2008-03-19T23:21:27Z","receivedAt":"2008-03-19T23:21:27Z","isPatch":false,"sender":{"key":"jgoerzen@complete.org","avatar":null},"body":"Hi folks,\n\nI have a transcript of a Git session that illustrates two odd bugs\nwith Git renaming.  Command output is truncated except where\ninteresting.\n\nBug #1 causes git to refuse to change to a different branch, claiming\nthat uncommitted changes exist, even when git status says there are none.\nBug #2 causes git to refuse to merge unrelated changes.\n\nTested with Git 1.5.4.4.\n\njgoerzen@katherina:/tmp$ mkdir testrepo\njgoerzen@katherina:/tmp$ cd testrepo\njgoerzen@katherina:/tmp/testrepo$ git init\njgoerzen@katherina:/tmp/testrepo$ mkdir files\njgoerzen@katherina:/tmp/testrepo$ echo hi > files/delete.me\njgoerzen@katherina:/tmp/testrepo$ git add .\njgoerzen@katherina:/tmp/testrepo$ git commit -m 'Added files/delete.me'\njgoerzen@katherina:/tmp/testrepo$ git checkout -b testbranch\nSwitched to a new branch \"testbranch\"\njgoerzen@katherina:/tmp/testrepo$ git mv files files.upstream\njgoerzen@katherina:/tmp/testrepo$ git commit -m 'Renamed files to files.upstream'\nCreated commit 7b6e9c5: Renamed files to files.upstream\n 1 files changed, 0 insertions(+), 0 deletions(-)\n rename {files => files.upstream}/delete.me (100%)\njgoerzen@katherina:/tmp/testrepo$ git status\n# On branch testbranch\nnothing to commit (working directory clean)\n\n#######\n# We can still change branches here...\n\njgoerzen@katherina:/tmp/testrepo$ git co master\nSwitched to branch \"master\"\njgoerzen@katherina:/tmp/testrepo$ git co testbranch\nSwitched to branch \"testbranch\"\n\n#######\n# Now here comes bug #1...\n\njgoerzen@katherina:/tmp/testrepo$ ln -s /tmp/nonexistant files\njgoerzen@katherina:/tmp/testrepo$ git add files\njgoerzen@katherina:/tmp/testrepo$ git commit -m 'Added files as symlink'\njgoerzen@katherina:/tmp/testrepo$ git status\n# On branch testbranch\nnothing to commit (working directory clean)\njgoerzen@katherina:/tmp/testrepo$ git checkout master\nfatal: Untracked working tree file 'files.upstream/delete.me' would be removed by merge.\n\n#######\n# Hrm, but that file really is tracked, AND it didn't show up in git status!\n\n$ git log files.upstream/delete.me | cat\ncommit 7b6e9c5d0fb268b5bca4985b407fe35aa2a7bd6d\nAuthor: John Goerzen <jgoerzen@complete.org>\nDate:   Wed Mar 19 18:12:12 2008 -0500\n\n    Renamed files to files.upstream\n\n#######\n# Well, let's work around this and check out master anyhow.\n\njgoerzen@katherina:/tmp/testrepo$ git checkout -f master\nSwitched to branch \"master\"\njgoerzen@katherina:/tmp/testrepo$ ls -l\ntotal 0\ndrwxr-xr-x 2 jgoerzen jgoerzen 22 Mar 19 18:13 files\ndrwxr-xr-x 2 jgoerzen jgoerzen 22 Mar 19 18:12 files.upstream\n\n#######\n# Yeow!  What's files.upstream doing here?  It wasn't on this branch, and\n# we had no uncommitted changes on the other branch.\n\njgoerzen@katherina:/tmp/testrepo$ rm -r files.upstream\njgoerzen@katherina:/tmp/testrepo$ git rm files.upstream/delete.me\nrm 'files.upstream/delete.me'\njgoerzen@katherina:/tmp/testrepo$ git status\n# On branch master\nnothing to commit (working directory clean)\n\n#######\n# Set up bug #2\n\njgoerzen@katherina:/tmp/testrepo$ echo foo > foo\njgoerzen@katherina:/tmp/testrepo$ git add foo\njgoerzen@katherina:/tmp/testrepo$ git commit -m 'Added foo'\njgoerzen@katherina:/tmp/testrepo$ git checkout testbranch\nSwitched to branch \"testbranch\"\njgoerzen@katherina:/tmp/testrepo$ ls -l\ntotal 0\nlrwxrwxrwx 1 jgoerzen jgoerzen 16 Mar 19 18:14 files -> /tmp/nonexistant\ndrwxr-xr-x 2 jgoerzen jgoerzen 22 Mar 19 18:14 files.upstream\njgoerzen@katherina:/tmp/testrepo$ git merge master\nfatal: Entry 'files/delete.me' would be overwritten by merge. Cannot merge.\nMerge with strategy recursive failed.\n\n########\n# And there's bug #2\n#\n# Note that it doesn't matter what strategy is attempted.\n\nThanks for any insight.\n\n-- John\n"},{"id":"72460","messageId":"7vwsnyz07y.fsf@gitster.siamese.dyndns.org","threadId":"12766","inReplyTo":"slrnfu37vn.d2i.jgoerzen@katherina.lan.complete.org","subject":"Re: Two bugs with renaming","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-03-20T00:51:45Z","receivedAt":"2008-03-20T00:51:45Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"John Goerzen <jgoerzen@complete.org> writes:\n\n> # Now here comes bug #1...\n\nPlease try 1.5.5-rc0 or newer.  I think Linus's unpack_trees() updates,\neven though it was sort of a rocky road to get there, addresses this.\n\nNamely, v1.5.5-rc0~25 was the commit that fixed this issue.\n\n> # Set up bug #2\n\nThis hasn't been addressed, I think.\n"},{"id":"72463","messageId":"20080320005633.GA22736@coredump.intra.peff.net","threadId":"12766","inReplyTo":"slrnfu37vn.d2i.jgoerzen@katherina.lan.complete.org","subject":"Re: Two bugs with renaming","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2008-03-20T00:56:33Z","receivedAt":"2008-03-20T00:56:33Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Mar 19, 2008 at 06:21:27PM -0500, John Goerzen wrote:\n\n> Bug #1 causes git to refuse to change to a different branch, claiming\n> that uncommitted changes exist, even when git status says there are none.\n> [...]\n> Tested with Git 1.5.4.4.\n\nI tried to reproduce this with current 'master', and it seems to be\nmagically fixed. There has been some work on unpack-trees lately, so it\nmight be a fallout from that.\n\n> Bug #2 causes git to refuse to merge unrelated changes.\n> [...]\n> lrwxrwxrwx 1 jgoerzen jgoerzen 16 Mar 19 18:14 files -> /tmp/nonexistant\n> drwxr-xr-x 2 jgoerzen jgoerzen 22 Mar 19 18:14 files.upstream\n> jgoerzen@katherina:/tmp/testrepo$ git merge master\n> fatal: Entry 'files/delete.me' would be overwritten by merge. Cannot merge.\n> Merge with strategy recursive failed.\n\nHrm, that should work, I think. I haven't kept up with the recent\nchanges, so I'll have to take some time to investigate.\n\n-Peff\n"},{"id":"72466","messageId":"20080320012454.GA16843@atjola.homenet","threadId":"12766","inReplyTo":"slrnfu37vn.d2i.jgoerzen@katherina.lan.complete.org","subject":"Re: Two bugs with renaming","fromName":"Björn Steinbrink","fromEmail":"b.steinbrink@gmx.de","sentAt":"2008-03-20T01:24:54Z","receivedAt":"2008-03-20T01:24:54Z","isPatch":false,"sender":{"key":"b.steinbrink@gmx.de","avatar":"https://avatars.githubusercontent.com/u/230962?v=4"},"body":"On 2008.03.19 18:21:27 -0500, John Goerzen wrote:\n> Hi folks,\n> \n> I have a transcript of a Git session that illustrates two odd bugs\n> with Git renaming.  Command output is truncated except where\n> interesting.\n\nI have another one. Well, not necessarily a bug, but at least something\nthat looks like it could be improved. I found that while trying to\nreproduce bug #1 (which doesn't show up here, as I'm using\n1.5.5-something).\n\nIt seems to boil down to the fact that even when git detected a rename\nduring a merge, it still uses the original file name to check for\nconflicts, causing somewhat bogus conflicts.\n\nTest script is attached, when I run that, git correctly applies the\nchanges from foo/file in master to foo2/file in \"other\", but\nnevertheless it complains that \"foo\" conflicts, although the directory\nis effectively empty and should therefore not be of any interest to git.\n\nBjörn\n"},{"id":"72467","messageId":"20080320020621.GA24678@coredump.intra.peff.net","threadId":"12766","inReplyTo":"7vwsnyz07y.fsf@gitster.siamese.dyndns.org","subject":"Re: Two bugs with renaming","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2008-03-20T02:06:21Z","receivedAt":"2008-03-20T02:06:21Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Mar 19, 2008 at 05:51:45PM -0700, Junio C Hamano wrote:\n\n> > # Set up bug #2\n> \n> This hasn't been addressed, I think.\n\nHmm. It looks like threeway_merge is getting bogus input. In a regular\nmerge (e.g., branch changes file \"file\", master adds new file \"other\",\nbranch merges master), threeway merge sees:\n\n  - call 1: index=file, head=file, remote=file\n  - call 2: index=NULL, head=NULL, remote=other\n\nBut if the change to file is a D/F conflict (as in the scenario John\ndescribed), we get:\n\n  - call 1: index=files, head=files, remote=\"\"\n  - call 2: index=files.upstream/delete.me, head=NULL, remote=NULL\n\nand it barfs because index != head in the second call. But the \"\" entry\nin the first call makes me wonder if this is the same \"lists getting out\nof sync\" problem as before.\n\nThis is as far as I got.  I don't have any more time to look at it\ntonight, unfortunately.\n\n-Peff\n"},{"id":"72470","messageId":"200803192130.17649.jgoerzen@complete.org","threadId":"12766","inReplyTo":"7vwsnyz07y.fsf@gitster.siamese.dyndns.org","subject":"Re: Two bugs with renaming","fromName":"John Goerzen","fromEmail":"jgoerzen@complete.org","sentAt":"2008-03-20T02:30:17Z","receivedAt":"2008-03-20T02:30:17Z","isPatch":false,"sender":{"key":"jgoerzen@complete.org","avatar":null},"body":"On Wednesday 19 March 2008 7:51:45 pm Junio C Hamano wrote:\n> John Goerzen <jgoerzen@complete.org> writes:\n> > # Now here comes bug #1...\n>\n> Please try 1.5.5-rc0 or newer.  I think Linus's unpack_trees() updates,\n> even though it was sort of a rocky road to get there, addresses this.\n>\n> Namely, v1.5.5-rc0~25 was the commit that fixed this issue.\n\nCorrect, bug #1 is gone with current git master.\n\n>\n> > # Set up bug #2\n>\n> This hasn't been addressed, I think.\n\nAlso correct.  Bug #2 is still present with current git master.  It shows:\n\njgoerzen@katherina:/tmp/testrepo$ git merge master\nerror: Entry 'files.upstream/delete.me' would be overwritten by merge. Cannot \nmerge.\nfatal: merging of trees 5cec043802758b3a4cd617905c395a9f12bf89a2 and \n9671b5181cb0649f39cfae372af1aed56a24010d failed\nMerge with strategy recursive failed.\n\nIs there any other information I can provide to assist with tracking that one \ndown?\n\n-- John\n"},{"id":"72476","messageId":"alpine.LFD.1.00.0803192059120.3020@woody.linux-foundation.org","threadId":"12766","inReplyTo":"slrnfu37vn.d2i.jgoerzen@katherina.lan.complete.org","subject":"Re: Two bugs with renaming","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2008-03-20T04:12:02Z","receivedAt":"2008-03-20T04:12:02Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Wed, 19 Mar 2008, John Goerzen wrote:\n>\n> #######\n> # Set up bug #2\n> \n> jgoerzen@katherina:/tmp/testrepo$ echo foo > foo\n> jgoerzen@katherina:/tmp/testrepo$ git add foo\n> jgoerzen@katherina:/tmp/testrepo$ git commit -m 'Added foo'\n> jgoerzen@katherina:/tmp/testrepo$ git checkout testbranch\n> Switched to branch \"testbranch\"\n> jgoerzen@katherina:/tmp/testrepo$ ls -l\n> total 0\n> lrwxrwxrwx 1 jgoerzen jgoerzen 16 Mar 19 18:14 files -> /tmp/nonexistant\n> drwxr-xr-x 2 jgoerzen jgoerzen 22 Mar 19 18:14 files.upstream\n> jgoerzen@katherina:/tmp/testrepo$ git merge master\n> fatal: Entry 'files/delete.me' would be overwritten by merge. Cannot merge.\n> Merge with strategy recursive failed.\n\nOk, so if I read this right, you have a D/F conflict, with the current \nbranch having a file (or rather, a symlink) called \"files\", and the branch \nyou are trying to merge has a *directory* called \"files\" in it, and the \nmerge gets really unhappy about that conflict.\n\nNow, arguably, it should just see them as two independent issues, and then \nthe rename detection will notice that the \"files/delete.me\" file got \nrenamed as \"files.upstream/delete.me\", so *after* rename detection there \nwill be no D/F conflict in the end result, but we see the conflict before \nthat all even happens.\n\nHo humm. \n\nWith the new unpack-trees logic it's pretty easy to *not* unpack with DF \nconflicts (add a flag that tells us to use \"base_name_compare()\" instead \nof \"df_name_compare()\" in do_compare_entry()), and maybe we can then make \nbuiltin-merge-recursive.c set that flag. But then builtin-merge-recursive\nwould also have to understand about D/F conflicts itself (since now \nunpack_trees() wouldn't give them as conflicts any more).\n\n\t\t\tLinus\n"},{"id":"72477","messageId":"alpine.LFD.1.00.0803192120410.3020@woody.linux-foundation.org","threadId":"12766","inReplyTo":"alpine.LFD.1.00.0803192059120.3020@woody.linux-foundation.org","subject":"Re: Two bugs with renaming","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2008-03-20T04:22:57Z","receivedAt":"2008-03-20T04:22:57Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Wed, 19 Mar 2008, Linus Torvalds wrote:\n> \n> With the new unpack-trees logic it's pretty easy to *not* unpack with DF \n> conflicts (add a flag that tells us to use \"base_name_compare()\" instead \n> of \"df_name_compare()\" in do_compare_entry()), and maybe we can then make \n> builtin-merge-recursive.c set that flag. [...]\n\nLooking at that, the first thing we should probably do is to make those \nexisting flags be bitfields rather than \"int\" before we add even more \nflags there.\n\nHmm?\n\n\t\t\tLinus\n\n---\n unpack-trees.h |   20 ++++++++++----------\n 1 files changed, 10 insertions(+), 10 deletions(-)\n\ndiff --git a/unpack-trees.h b/unpack-trees.h\nindex 50453ed..ad8cc65 100644\n--- a/unpack-trees.h\n+++ b/unpack-trees.h\n@@ -9,16 +9,16 @@ typedef int (*merge_fn_t)(struct cache_entry **src,\n \t\tstruct unpack_trees_options *options);\n \n struct unpack_trees_options {\n-\tint reset;\n-\tint merge;\n-\tint update;\n-\tint index_only;\n-\tint nontrivial_merge;\n-\tint trivial_merges_only;\n-\tint verbose_update;\n-\tint aggressive;\n-\tint skip_unmerged;\n-\tint gently;\n+\tunsigned int reset:1,\n+\t\t     merge:1,\n+\t\t     update:1,\n+\t\t     index_only:1,\n+\t\t     nontrivial_merge:1,\n+\t\t     trivial_merges_only:1,\n+\t\t     verbose_update:1,\n+\t\t     aggressive:1,\n+\t\t     skip_unmerged:1,\n+\t\t     gently:1;\n \tconst char *prefix;\n \tint pos;\n \tstruct dir_struct *dir;\n"},{"id":"72481","messageId":"7vbq5aypdq.fsf@gitster.siamese.dyndns.org","threadId":"12766","inReplyTo":"alpine.LFD.1.00.0803192059120.3020@woody.linux-foundation.org","subject":"Re: Two bugs with renaming","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-03-20T04:45:53Z","receivedAt":"2008-03-20T04:45:53Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@linux-foundation.org> writes:\n\n> Now, arguably, it should just see them as two independent issues, and then \n> the rename detection will notice that the \"files/delete.me\" file got \n> renamed as \"files.upstream/delete.me\", so *after* rename detection there \n> will be no D/F conflict in the end result, but we see the conflict before \n> that all even happens.\n\nThe common ancestor had files/delete.me.\n\nOur side (test_branch) deleted files/delete.me, created\nfiles.upstream/delete.me and created files.\n\nTheir side (master)kept files/delete.me without changing, created foo.\n\nSo I would think we should not even trigger D/F conflict at all.\n\n - files/delete.me is deleted by only one side (our side) and it should go.\n\n - files and files.upstream/delete.me are created by only one side (ours)\n   and it should stay.\n\n - foo is created by only one side (theirs) and it should come.\n\nHowever, we wanted to allow policy decision to happen after read-tree, and\nwe traditionally kept \"one side removes\" case as an internal conflict in\nthe index, later to be resolved by merge-one-file (and merge-recursive).\n\nSo I think the resulting index should look like this:\n\n        100644 xxxxxxx 0\tfiles.upstream/delete.me\n        100644 xxxxxxx 1\tfiles/delete.me\n        100644 xxxxxxx 3\tfiles/delete.me\n        120000 xxxxxxx 0\tfiles\n        100644 xxxxxxx 0\tfoo\n\nor (if we also want to leave policy decision for \"one side adds\" case to\nmerge-one-file and merge-recursive) even:\n\n        100644 xxxxxxx 1\tfiles/delete.me\n        100644 xxxxxxx 3\tfiles/delete.me\n        120000 xxxxxxx 2\tfiles\n        100644 xxxxxxx 2\tfiles.upstream/delete.me\n        100644 xxxxxxx 2\tfoo\n\nBut that is not what is happening here.  In fact, if you did not have\n\"files\" in the test branch, here is what you will see:\n\n        100644 xxxxxxx 0\tfiles.upstream/delete.me\n        100644 xxxxxxx 1\tfiles/delete.me\n        100644 xxxxxxx 3\tfiles/delete.me\n        100644 xxxxxxx 0\tfoo\n\nand merge-recursive knows how to match up the first three entries and if\nthere are changes between stages #1 and #3 of files/delete.me, that is\ncarried forward to files.upstream/delete.me\n\nYour unpack_trees() is bug-to-bug compatibile with Daniel's that is in\n1.5.4.  Both \"read-tree -m -u\" bails out with the same error, without\neven leaving higher stage entries in the index.\n"}]}