{"thread":{"id":"25378","subject":"[PATCH] fast-import: Allow filemodify to set the root","startedAt":"2010-10-07T10:55:06Z","lastAt":"2011-01-18T22:02:26Z","messageCount":31,"participants":["David Barr","Sverre Rabbelier","Jonathan Nieder","Johannes Sixt","Ramkumar Ramachandra","Gabriel Filion","David Michael Barr","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"152869","messageId":"1286448906-1424-1-git-send-email-david.barr@cordelta.com","threadId":"25378","inReplyTo":null,"subject":"[PATCH] fast-import: Allow filemodify to set the root","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2010-10-07T10:55:06Z","receivedAt":"2010-10-07T10:55:06Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"Most git commands do their writing to the object db via the index and\nloose objects.  When you just have a pile of trees you want to convert\ninto commits, this is wasteful; for performance-critical operations\nlike filter-branch --subdirectory-filter, one might want a sort of\nhash-object --batch-to-pack to write a pack directly.\n\nFortunately we have fast-import (which is one of the only git commands\nthat will write to a pack directly) but there is not an advertised way\nto tell fast-import to use a given tree for its commits.  So in\ncurrent git, one has the unpleasant choice of writing loose objects\nwithout parsing the trees or writing straight to pack but having to\nparse trees to do it.\n\nThis patch changes that, by allowing\n\n\tM 040000 <tree id> \"\"\n\nas a filemodify line in a commit to reset to a particular tree without\nany need to unpack it.  For example,\n\n\tM 040000 4b825dc642cb6eb9a060e54bf8d69288fbee4904 \"\"\n\nis a synonym for the deleteall command.\n\nCommit-message-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n fast-import.c |    9 +++++++++\n 1 files changed, 9 insertions(+), 0 deletions(-)\n\ndiff --git a/fast-import.c b/fast-import.c\nindex 2317b0f..8f68a89 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -1454,6 +1454,15 @@ static int tree_content_set(\n \t\tn = slash1 - p;\n \telse\n \t\tn = strlen(p);\n+\tif (!slash1 && !n) {\n+\t\tif (!S_ISDIR(mode))\n+\t\t\tdie(\"Root cannot be a non-directory\");\n+\t\thashcpy(root->versions[1].sha1, sha1);\n+\t\tif (root->tree)\n+\t\t\trelease_tree_content_recursive(root->tree);\n+\t\troot->tree = subtree;\n+\t\treturn 1;\n+\t}\n \tif (!n)\n \t\tdie(\"Empty path component found in input\");\n \tif (!slash1 && !S_ISDIR(mode) && subtree)\n-- \n1.7.3\n"},{"id":"152875","messageId":"AANLkTikjzQ09XBxYZXXQf6XCme3FiLKtusZ0MLTa--mM@mail.gmail.com","threadId":"25378","inReplyTo":"1286448906-1424-1-git-send-email-david.barr@cordelta.com","subject":"Re: [PATCH] fast-import: Allow filemodify to set the root","fromName":"Sverre Rabbelier","fromEmail":"srabbelier@gmail.com","sentAt":"2010-10-07T13:58:02Z","receivedAt":"2010-10-07T13:58:02Z","isPatch":true,"sender":{"key":"srabbelier@gmail.com","avatar":"https://avatars.githubusercontent.com/u/3098?v=4"},"body":"Heya,\n\nOn Thu, Oct 7, 2010 at 12:55, David Barr <david.barr@cordelta.com> wrote:\n> Most git commands do their writing to the object db via the index and\n> loose objects.  When you just have a pile of trees you want to convert\n> into commits, this is wasteful; for performance-critical operations\n> like filter-branch --subdirectory-filter, one might want a sort of\n> hash-object --batch-to-pack to write a pack directly.\n\nThis means nothing to me, but perhaps I'm not the target audience of\nthis paragraph.\n\n> Fortunately we have fast-import (which is one of the only git commands\n> that will write to a pack directly) but there is not an advertised way\n> to tell fast-import to use a given tree for its commits.\n\nI'm with you up to \"use a given tree for its commits\".\n\n> This patch changes that, by allowing\n>\n>        M 040000 <tree id> \"\"\n>\n> as a filemodify line in a commit to reset to a particular tree without\n> any need to unpack it.  For example,\n>\n>        M 040000 4b825dc642cb6eb9a060e54bf8d69288fbee4904 \"\"\n>\n> is a synonym for the deleteall command.\n\nOk, so maybe I do understand, is it basically 'git read-tree\n4b825dc642cb6eb9a060e54bf8d69288fbee4904' for fast-import?\n\n-- \nCheers,\n\nSverre Rabbelier\n"},{"id":"152928","messageId":"20101007202847.GA13234@burratino","threadId":"25378","inReplyTo":"AANLkTikjzQ09XBxYZXXQf6XCme3FiLKtusZ0MLTa--mM@mail.gmail.com","subject":"Re: [PATCH] fast-import: Allow filemodify to set the root","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-10-07T20:28:47Z","receivedAt":"2010-10-07T20:28:47Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Sverre Rabbelier wrote:\n\n> This means nothing to me\n\nSorry for the lack of clarity.  Probably I should have just said:\n\n| For a command (like filter-branch --subdirectory-filter) that wants\n| to commit a lot of trees that already exist in the object db, writing\n| undeltified objects as loose files only to repack them later can\n| involve a significant amount[*] of overhead.\n|\n| Fortunately we have fast-import (which is one of the only git commands\n| that will write to a pack directly) but there is not an advertised way\n| to tell fast-import to commit a given tree without unpacking it.\n|\n| This patch changes that, by allowing\n|\n|        M 040000 <tree id> \"\"\n|\n| as a filemodify line in a commit to reset to a particular tree without\n| any need to parse it.  For example,\n|\n|\tM 040000 4b825dc642cb6eb9a060e54bf8d69288fbee4904 \"\"\n|\n| is a synonym for the deleteall command.\n\n[*] how significant?  Numbers are always nice. :)\n\n> Ok, so maybe I do understand, is it basically 'git read-tree\n> 4b825dc642cb6eb9a060e54bf8d69288fbee4904' for fast-import?\n\nYep.\n\nThanks.\n"},{"id":"152930","messageId":"AANLkTi=K0NsKB0uBpHs+mB=PubieX7jO7vFiqrs+dnqB@mail.gmail.com","threadId":"25378","inReplyTo":"20101007202847.GA13234@burratino","subject":"Re: [PATCH] fast-import: Allow filemodify to set the root","fromName":"Sverre Rabbelier","fromEmail":"srabbelier@gmail.com","sentAt":"2010-10-07T20:35:20Z","receivedAt":"2010-10-07T20:35:20Z","isPatch":true,"sender":{"key":"srabbelier@gmail.com","avatar":"https://avatars.githubusercontent.com/u/3098?v=4"},"body":"Heya,\n\nOn Thu, Oct 7, 2010 at 22:28, Jonathan Nieder <jrnieder@gmail.com> wrote:\n> | is a synonym for the deleteall command.\n\nThanks, the updated doc is more understandable.\n\n> [*] how significant?  Numbers are always nice. :)\n\nYes, numbers please! :)\n\n>> Ok, so maybe I do understand, is it basically 'git read-tree\n>> 4b825dc642cb6eb9a060e54bf8d69288fbee4904' for fast-import?\n>\n> Yep.\n\nPerhaps mention that in the commit message as well then. Of course,\nthe fast-import doc needs updating, and it needs test.\n\n-- \nCheers,\n\nSverre Rabbelier\n"},{"id":"152936","messageId":"201010081045.46642.david.barr@cordelta.com","threadId":"25378","inReplyTo":"AANLkTi=K0NsKB0uBpHs+mB=PubieX7jO7vFiqrs+dnqB@mail.gmail.com","subject":"Re: [PATCH] fast-import: Allow filemodify to set the root","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2010-10-07T23:45:46Z","receivedAt":"2010-10-07T23:45:46Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"Hi,\n\n> | For a command (like filter-branch --subdirectory-filter) that wants\n> | to commit a lot of trees that already exist in the object db, writing\n> | undeltified objects as loose files only to repack them later can\n> | involve a significant amount[*] of overhead.\n\n> [*] how significant?  Numbers are always nice. :)\n\nUsing git hash-object:\nreal    2m51.748s\nuser    0m25.460s\nsys     0m23.890s\n\nUsing git fast-import:\nreal    2m13.337s\nuser    0m28.010s\nsys     0m18.100s\n\n> \n> > Ok, so maybe I do understand, is it basically 'git read-tree\n> > 4b825dc642cb6eb9a060e54bf8d69288fbee4904' for fast-import?\n\n> Perhaps mention that in the commit message as well then. Of course,\n> the fast-import doc needs updating, and it needs test.\n\n| is a synonym for the deleteall command and the fast-import equivalent of\n| \n|         git read-tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904\n\n--\nDavid Barr\n"},{"id":"152937","messageId":"1286495219-14414-1-git-send-email-david.barr@cordelta.com","threadId":"25378","inReplyTo":"201010081045.46642.david.barr@cordelta.com","subject":"[PATCH] fast-import: Allow filemodify to set the root","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2010-10-07T23:46:59Z","receivedAt":"2010-10-07T23:46:59Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"For a command (like filter-branch --subdirectory-filter) that wants\nto commit a lot of trees that already exist in the object db, writing\nundeltified objects as loose files only to repack them later can\ninvolve a significant amount of overhead.\n(23% slow-down observed on Linux 2.6.35, worse on Mac OS X 10.6)\n\nFortunately we have fast-import (which is one of the only git commands\nthat will write to a pack directly) but there is not an advertised way\nto tell fast-import to commit a given tree without unpacking it.\n\nThis patch changes that, by allowing\n\n\tM 040000 <tree id> \"\"\n\nas a filemodify line in a commit to reset to a particular tree without\nany need to parse it.  For example,\n\n\tM 040000 4b825dc642cb6eb9a060e54bf8d69288fbee4904 \"\"\n\nis a synonym for the deleteall command and the fast-import equivalent of\n\n\tgit read-tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904\n\nCommit-message-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: David Barr <david.barr@cordelta.com>\n---\n fast-import.c |    9 +++++++++\n 1 files changed, 9 insertions(+), 0 deletions(-)\n\ndiff --git a/fast-import.c b/fast-import.c\nindex 2317b0f..8f68a89 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -1454,6 +1454,15 @@ static int tree_content_set(\n \t\tn = slash1 - p;\n \telse\n \t\tn = strlen(p);\n+\tif (!slash1 && !n) {\n+\t\tif (!S_ISDIR(mode))\n+\t\t\tdie(\"Root cannot be a non-directory\");\n+\t\thashcpy(root->versions[1].sha1, sha1);\n+\t\tif (root->tree)\n+\t\t\trelease_tree_content_recursive(root->tree);\n+\t\troot->tree = subtree;\n+\t\treturn 1;\n+\t}\n \tif (!n)\n \t\tdie(\"Empty path component found in input\");\n \tif (!slash1 && !S_ISDIR(mode) && subtree)\n-- \n1.7.3.4.g45608.dirty\n"},{"id":"152938","messageId":"AANLkTi=DYaB9+C6j9cH=eGRPsvm1Re-6+jfQmhCzvhKP@mail.gmail.com","threadId":"25378","inReplyTo":"1286495219-14414-1-git-send-email-david.barr@cordelta.com","subject":"Re: [PATCH] fast-import: Allow filemodify to set the root","fromName":"Sverre Rabbelier","fromEmail":"srabbelier@gmail.com","sentAt":"2010-10-07T23:55:18Z","receivedAt":"2010-10-07T23:55:18Z","isPatch":true,"sender":{"key":"srabbelier@gmail.com","avatar":"https://avatars.githubusercontent.com/u/3098?v=4"},"body":"Heya,\n\nOn Fri, Oct 8, 2010 at 01:46, David Barr <david.barr@cordelta.com> wrote:\n> Commit-message-by: Jonathan Nieder <jrnieder@gmail.com>\n> Signed-off-by: David Barr <david.barr@cordelta.com>\n\nI like it, FWIW:\n\nAcked-by: Sverre Rabbelier <srabbelier@gmail.com>\n\n-- \nCheers,\n\nSverre Rabbelier\n"},{"id":"152950","messageId":"4CAEBF2E.8020206@viscovery.net","threadId":"25378","inReplyTo":"20101007202847.GA13234@burratino","subject":"Re: [PATCH] fast-import: Allow filemodify to set the root","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2010-10-08T06:50:22Z","receivedAt":"2010-10-08T06:50:22Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 10/7/2010 22:28, schrieb Jonathan Nieder:\n> Sverre Rabbelier wrote:\n> \n>> This means nothing to me\n> \n> Sorry for the lack of clarity.  Probably I should have just said:\n> \n> | For a command (like filter-branch --subdirectory-filter) that wants\n> | to commit a lot of trees that already exist in the object db, writing\n> | undeltified objects as loose files only to repack them later can\n> | involve a significant amount[*] of overhead.\n\n1. But when an object already exists in the db, it won't be written again,\nwill it?\n\n2. Even though fast-import puts all (new) objects into a pack file, the\npack is heavily sub-optimal, and you should repack -f anyway. So what's\nthe point? Only to avoid a loose object?\n\n(I'm not saying that the patch is unwanted, but only that the\njustification is still not sufficiently complete.)\n\n-- Hannes\n"},{"id":"152953","messageId":"20101008070511.GA4671@burratino","threadId":"25378","inReplyTo":"4CAEBF2E.8020206@viscovery.net","subject":"Re: [PATCH] fast-import: Allow filemodify to set the root","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-10-08T07:05:11Z","receivedAt":"2010-10-08T07:05:11Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Johannes Sixt wrote:\n> Am 10/7/2010 22:28, schrieb Jonathan Nieder:\n\n>> | For a command (like filter-branch --subdirectory-filter) that wants\n>> | to commit a lot of trees that already exist in the object db, writing\n>> | undeltified objects as loose files only to repack them later can\n>> | involve a significant amount[*] of overhead.\n>\n> 1. But when an object already exists in the db, it won't be written again,\n> will it?\n\nIn David's application, the trees already exist, but the commits are new.\n\n> 2. Even though fast-import puts all (new) objects into a pack file, the\n> pack is heavily sub-optimal, and you should repack -f anyway. So what's\n> the point? Only to avoid a loose object?\n\nTo avoid thousands of loose objects.\n\n> (I'm not saying that the patch is unwanted, but only that the\n> justification is still not sufficiently complete.)\n\nNo problem - these questions are useful.  If the result is learning\nthat something else is responsible for the speedup David observed in\nhis script, that would not be a bad outcome after all.\n\nI suppose supporting M 040000 <tree> \"\" and C <path> \"\" could still\nbe a good idea in that case anyway, for the convenience of front-end\nauthors.\n\nJonathan\nwho still hasn't reviewed the patch (sorry)\n"},{"id":"152954","messageId":"4CAEC6E6.5000305@viscovery.net","threadId":"25378","inReplyTo":"20101008070511.GA4671@burratino","subject":"Re: [PATCH] fast-import: Allow filemodify to set the root","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2010-10-08T07:23:18Z","receivedAt":"2010-10-08T07:23:18Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 10/8/2010 9:05, schrieb Jonathan Nieder:\n> Johannes Sixt wrote:\n>> Am 10/7/2010 22:28, schrieb Jonathan Nieder:\n> \n>>> | For a command (like filter-branch --subdirectory-filter) that wants\n>>> | to commit a lot of trees that already exist in the object db, writing\n>>> | undeltified objects as loose files only to repack them later can\n>>> | involve a significant amount[*] of overhead.\n>>\n>> 1. But when an object already exists in the db, it won't be written again,\n>> will it?\n> \n> In David's application, the trees already exist, but the commits are new.\n\nBut then what has this to do with \"allow filemodify to set the root\"?\n\n> I suppose supporting M 040000 <tree> \"\" and C <path> \"\" could still\n> be a good idea in that case anyway, for the convenience of front-end\n> authors.\n\nWhat is the special new thing here? That \"\" means 'empty string' == 'tree\nat the root'? If so:\n\n1. Then this is the missing piece in the justification. Then I could buy\nthat the observed speed-up is due to the reuse of an existing tree object\n(which avoids parsing it and re-constructing it from its pieces because\nfast-imports syntax didn't allow it otherwise). But it has nothing to do\nwith new loose objects (the re-constructed object would be identical to an\nexisting one).\n\n2. Without this patch, would this syntax create a tree object with a name\nconsisting of two double-quotes in the root? Or would it be a syntax\nerror? How would one construct such an entry with this patch?\n\n-- Hannes\n"},{"id":"152966","messageId":"20101008080027.GC4671@burratino","threadId":"25378","inReplyTo":"4CAEC6E6.5000305@viscovery.net","subject":"Re: [PATCH] fast-import: Allow filemodify to set the root","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-10-08T08:00:27Z","receivedAt":"2010-10-08T08:00:27Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Some quick answers before I go to sleep.\n\nJohannes Sixt wrote:\n\n> What is the special new thing here? That \"\" means 'empty string' == 'tree\n> at the root'? If so:\n\nYes.\n\n> 1. Then this is the missing piece in the justification. Then I could buy\n> that the observed speed-up is due to the reuse of an existing tree object\n> (which avoids parsing it and re-constructing it from its pieces because\n> fast-imports syntax didn't allow it otherwise). But it has nothing to do\n> with new loose objects (the re-constructed object would be identical to an\n> existing one).\n\nIf I remember correctly:\n\nVersion 1 of the script was similar to filter-branch and used\n\"git read-tree\", \"git write-tree\", and \"git commit-tree\" (or something\nequivalent).  Reconstructing the trees seemed to be a significant overhead,\nleading to:\n\nVersion 2, which just called \"git commit-tree\" (or equivalent) repeatedly.\nWhat this patch allows is\n\nVersion 3, which is a bit over 20% faster than version 2 and uses fast-import\nto write the new commits directly to pack.\n\nThat speed-up could be due to avoiding the repeated fork() + exec() +\ngit startup cost, or avoiding loose objects, or any number of other\nthings.  Without this patch, one could write\n\nTheoretical version 1', which uses cat-file --batch to unpack each\ntree and uses fast-import to write commits with the same (recreated)\ntree directly to pack.  But that would be kind of insane.\n\n> 2. Without this patch, would this syntax create a tree object with a name\n> consisting of two double-quotes in the root? Or would it be a syntax\n> error?\n\nSyntax error.\n\n> How would one construct such an entry with this patch?\n\nM 040000 <tree id> \"\\\"\\\"\"\n\nThanks again.\n"},{"id":"152967","messageId":"20101008081509.GA2845@kytes","threadId":"25378","inReplyTo":"1286448906-1424-1-git-send-email-david.barr@cordelta.com","subject":"Re: [PATCH] fast-import: Allow filemodify to set the root","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2010-10-08T08:15:13Z","receivedAt":"2010-10-08T08:15:13Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi David,\n\nI'm sorry I didn't get the time to look at this earlier- just looked\nat it now.\n\nDavid Barr writes:\n> Most git commands do their writing to the object db via the index and\n> loose objects.  When you just have a pile of trees you want to convert\n> into commits, this is wasteful; for performance-critical operations\n> like filter-branch --subdirectory-filter, one might want a sort of\n> hash-object --batch-to-pack to write a pack directly.\n> \n> Fortunately we have fast-import (which is one of the only git commands\n> that will write to a pack directly) but there is not an advertised way\n> to tell fast-import to use a given tree for its commits.  So in\n> current git, one has the unpleasant choice of writing loose objects\n> without parsing the trees or writing straight to pack but having to\n> parse trees to do it.\n> \n> This patch changes that, by allowing\n> \n> \tM 040000 <tree id> \"\"\n\nIt can be a <dataref> in general: either a SHA1 or a tree mark.\n\n> as a filemodify line in a commit to reset to a particular tree without\n> any need to unpack it.  For example,\n> \n> \tM 040000 4b825dc642cb6eb9a060e54bf8d69288fbee4904 \"\"\n> \n> is a synonym for the deleteall command.\n> \n> Commit-message-by: Jonathan Nieder <jrnieder@gmail.com>\n> Signed-off-by: David Barr <david.barr@cordelta.com>\n> ---\n>  fast-import.c |    9 +++++++++\n>  1 files changed, 9 insertions(+), 0 deletions(-)\n\nI applied and tried it out- it works as expected. Here's a patch for\nthe documentation and a test. You might want to put the test in a\nseparate patch (in preparation for Jonathan's t9300 cleanup series).\n\n@Jonathan: What happened to your series cleaning up t9300?\n\nTested-by: Ramkumar Ramachandra <artagnon@gmail.com>\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n\n-- 8< --\ndiff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt\nindex 966ba4f..90a4666 100644\n--- a/Documentation/git-fast-import.txt\n+++ b/Documentation/git-fast-import.txt\n@@ -524,6 +524,9 @@ start with double quote (`\"`).\n If an `LF` or double quote must be encoded into `<path>` shell-style\n quoting should be used, e.g. `\"path/with\\n and \\\" in it\"`.\n \n+Additionally, in `040000` mode, `<path>` may also be an empty string\n+(`\"\"`) to specify the root of the tree.\n+\n The value of `<path>` must be in canonical form. That is it must not:\n \n * contain an empty directory component (e.g. `foo//bar` is invalid),\n\ndiff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh\nindex 7c05920..3c0cf05 100755\n--- a/t/t9300-fast-import.sh\n+++ b/t/t9300-fast-import.sh\n@@ -875,6 +875,27 @@ test_expect_success \\\n \t compare_diff_raw expect actual'\n \n test_expect_success \\\n+\t'N: copy root directory by tree hash' \\\n+\t'cat >expect <<-\\EOF &&\n+\t:100755 000000 f1fb5da718392694d0076d677d6d0e364c79b0bc 0000000000000000000000000000000000000000 D\tfile3/newf\n+\t:100644 000000 7123f7f44e39be127c5eb701e5968176ee9d78b1 0000000000000000000000000000000000000000 D\tfile3/oldf\n+\tEOF\n+\t root=$(git rev-parse refs/heads/branch^0^{tree}) &&\n+\t cat >input <<-INPUT_END &&\n+\tcommit refs/heads/N6\n+\tcommitter $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE\n+\tdata <<COMMIT\n+\tcopy root directory by tree hash\n+\tCOMMIT\n+\n+\tfrom refs/heads/branch^0\n+\tM 040000 $root \"\"\n+\tINPUT_END\n+\t git fast-import <input &&\n+\t git diff-tree -C --find-copies-harder -r N4 N6 >actual &&\n+\t compare_diff_raw expect actual'\n+\n+test_expect_success \\\n \t'N: modify copied tree' \\\n \t'cat >expect <<-\\EOF &&\n \t:100644 100644 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 C100\tnewdir/interesting\tfile3/file5\n\n> diff --git a/fast-import.c b/fast-import.c\n> index 2317b0f..8f68a89 100644\n> --- a/fast-import.c\n> +++ b/fast-import.c\n> @@ -1454,6 +1454,15 @@ static int tree_content_set(\n>  \t\tn = slash1 - p;\n>  \telse\n>  \t\tn = strlen(p);\n> +\tif (!slash1 && !n) {\n> +\t\tif (!S_ISDIR(mode))\n> +\t\t\tdie(\"Root cannot be a non-directory\");\n> +\t\thashcpy(root->versions[1].sha1, sha1);\n> +\t\tif (root->tree)\n> +\t\t\trelease_tree_content_recursive(root->tree);\n> +\t\troot->tree = subtree;\n\nShould there be a hashclr(root->versions[1].sha1) here? I saw it in\nthe other branches.\n\nLooks good otherwise. I'm surprised fast-import didn't already have\nthis functionality.\n\n-- Ram\n"},{"id":"152968","messageId":"4CAED762.7040708@gmail.com","threadId":"25378","inReplyTo":"20101008081509.GA2845@kytes","subject":"Re: [PATCH] fast-import: Allow filemodify to set the root","fromName":"Gabriel Filion","fromEmail":"lelutin@gmail.com","sentAt":"2010-10-08T08:33:38Z","receivedAt":"2010-10-08T08:33:38Z","isPatch":true,"sender":{"key":"lelutin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/108728?v=4"},"body":"Hello,\n\nOn 2010-10-08 04:15, Ramkumar Ramachandra wrote:\n> diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt\n> index 966ba4f..90a4666 100644\n> --- a/Documentation/git-fast-import.txt\n> +++ b/Documentation/git-fast-import.txt\n> @@ -524,6 +524,9 @@ start with double quote (`\"`).\n>  If an `LF` or double quote must be encoded into `<path>` shell-style\n>  quoting should be used, e.g. `\"path/with\\n and \\\" in it\"`.\n>  \n> +Additionally, in `040000` mode, `<path>` may also be an empty string\n> +(`\"\"`) to specify the root of the tree.\n> +\n>  The value of `<path>` must be in canonical form. That is it must not:\n>  \n>  * contain an empty directory component (e.g. `foo//bar` is invalid),\n\nThanks for keeping documentation up to date :)\n\nAlthough, I think the documentation should be a bit more precise about\nwhat \"specifying the root of the tree\" means for a 'filemodify' command\nand its implication on performance (i.e. why there's actually this\nspecial case in the syntax)\n\n-- \nGabriel Filion\n"},{"id":"152969","messageId":"74AF320B-5D82-4622-A7BF-61C847D4059A@cordelta.com","threadId":"25378","inReplyTo":"4CAED762.7040708@gmail.com","subject":"Re: [PATCH] fast-import: Allow filemodify to set the root","fromName":"David Michael Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2010-10-08T08:58:44Z","receivedAt":"2010-10-08T08:58:44Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"Hi,\n\n>> diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt\n>> index 966ba4f..90a4666 100644\n>> --- a/Documentation/git-fast-import.txt\n>> +++ b/Documentation/git-fast-import.txt\n>> @@ -524,6 +524,9 @@ start with double quote (`\"`).\n>> If an `LF` or double quote must be encoded into `<path>` shell-style\n>> quoting should be used, e.g. `\"path/with\\n and \\\" in it\"`.\n>> \n>> +Additionally, in `040000` mode, `<path>` may also be an empty string\n>> +(`\"\"`) to specify the root of the tree.\n>> +\n>> The value of `<path>` must be in canonical form. That is it must not:\n>> \n>> * contain an empty directory component (e.g. `foo//bar` is invalid),\n> \n> Thanks for keeping documentation up to date :)\n> \n> Although, I think the documentation should be a bit more precise about\n> what \"specifying the root of the tree\" means for a 'filemodify' command\n> and its implication on performance (i.e. why there's actually this\n> special case in the syntax)\n\nThe way I perceive it, the patch simply removes the special treatment of\nthe root, allowing it to be modified just as any other path.\nThe only property that distinguishes the root from other paths is that the\nendpoint must be a tree.\n"},{"id":"152975","messageId":"AANLkTi=zS+oj1iHMh-gKVD=2dG5tLwA+bia9E6U3o=zW@mail.gmail.com","threadId":"25378","inReplyTo":"74AF320B-5D82-4622-A7BF-61C847D4059A@cordelta.com","subject":"Re: [PATCH] fast-import: Allow filemodify to set the root","fromName":"Sverre Rabbelier","fromEmail":"srabbelier@gmail.com","sentAt":"2010-10-08T16:34:32Z","receivedAt":"2010-10-08T16:34:32Z","isPatch":true,"sender":{"key":"srabbelier@gmail.com","avatar":"https://avatars.githubusercontent.com/u/3098?v=4"},"body":"Heya,\n\nOn Fri, Oct 8, 2010 at 10:58, David Michael Barr\n<david.barr@cordelta.com> wrote:\n> The way I perceive it, the patch simply removes the special treatment of\n> the root, allowing it to be modified just as any other path.\n> The only property that distinguishes the root from other paths is that the\n> endpoint must be a tree.\n\nSo, are other trees allowed too? Can I set the contents of directory\n\"foo/bar/baz/\" to an existing tree?\n\n-- \nCheers,\n\nSverre Rabbelier\n"},{"id":"152980","messageId":"20101008170939.GG9212@burratino","threadId":"25378","inReplyTo":"AANLkTi=zS+oj1iHMh-gKVD=2dG5tLwA+bia9E6U3o=zW@mail.gmail.com","subject":"Re: [PATCH] fast-import: Allow filemodify to set the root","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-10-08T17:09:39Z","receivedAt":"2010-10-08T17:09:39Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Sverre Rabbelier wrote:\n\n> So, are other trees allowed too? Can I set the contents of directory\n> \"foo/bar/baz/\" to an existing tree?\n\nYep, ever since v1.7.3-rc0~75^2 (Teach fast-import to import\nsubtrees named by tree id, 2010-06-30).\n"},{"id":"153103","messageId":"5A2A5584-FB25-46C2-8891-B667C46011D3@cordelta.com","threadId":"25378","inReplyTo":"20101008170939.GG9212@burratino","subject":"Re: [PATCH] fast-import: Allow filemodify to set the root","fromName":"David Michael Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2010-10-09T22:11:19Z","receivedAt":"2010-10-09T22:11:19Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"Should I resubmit this patch with the complete justification?\n\nAdd an extra paragraph like:\n\nv1.7.3-rc0~75^2 (Teach fast-import to import\nsubtrees named by tree id, 2010-06-30)\nhas a shortcoming, it doesn't allow the root to be set.\nExtend this behaviour by allowing the root to be\nreferenced as the empty path, \"\".\n\n>  v1.7.3-rc0~75^2 (Teach fast-import to import\n> subtrees named by tree id, 2010-06-30)\n"},{"id":"153104","messageId":"AANLkTinsnMRyoeGzCn1Rkk7tc+zwVa5j3AGqVZCdDGDv@mail.gmail.com","threadId":"25378","inReplyTo":"5A2A5584-FB25-46C2-8891-B667C46011D3@cordelta.com","subject":"Re: [PATCH] fast-import: Allow filemodify to set the root","fromName":"Sverre Rabbelier","fromEmail":"srabbelier@gmail.com","sentAt":"2010-10-09T22:12:36Z","receivedAt":"2010-10-09T22:12:36Z","isPatch":true,"sender":{"key":"srabbelier@gmail.com","avatar":"https://avatars.githubusercontent.com/u/3098?v=4"},"body":"Heya,\n\nOn Sun, Oct 10, 2010 at 00:11, David Michael Barr\n<david.barr@cordelta.com> wrote:\n> v1.7.3-rc0~75^2 (Teach fast-import to import\n> subtrees named by tree id, 2010-06-30)\n> has a shortcoming, it doesn't allow the root to be set.\n> Extend this behaviour by allowing the root to be\n> referenced as the empty path, \"\".\n\nYes, that would be a good addition.\n\n-- \nCheers,\n\nSverre Rabbelier\n"},{"id":"153112","messageId":"1286681415-1831-1-git-send-email-david.barr@cordelta.com","threadId":"25378","inReplyTo":"AANLkTinsnMRyoeGzCn1Rkk7tc+zwVa5j3AGqVZCdDGDv@mail.gmail.com","subject":"[PATCH] fast-import: Allow filemodify to set the root","fromName":"David Barr","fromEmail":"david.barr@cordelta.com","sentAt":"2010-10-10T03:30:15Z","receivedAt":"2010-10-10T03:30:15Z","isPatch":true,"sender":{"key":"david.barr@cordelta.com","avatar":"https://avatars.githubusercontent.com/u/220594?v=4"},"body":"v1.7.3-rc0~75^2 (Teach fast-import to import subtrees named by tree id,\n2010-06-30) has a shortcoming - it doesn't allow the root to be set.\nExtend this behaviour by allowing the root to be referenced as the\nempty path, \"\".\n\nFor a command (like filter-branch --subdirectory-filter) that wants\nto commit a lot of trees that already exist in the object db, writing\nundeltified objects as loose files only to repack them later can\ninvolve a significant amount of overhead.\n(23% slow-down observed on Linux 2.6.35, worse on Mac OS X 10.6)\n\nFortunately we have fast-import (which is one of the only git commands\nthat will write to a pack directly) but there is not an advertised way\nto tell fast-import to commit a given tree without unpacking it.\n\nThis patch changes that, by allowing\n\n\tM 040000 <tree id> \"\"\n\nas a filemodify line in a commit to reset to a particular tree without\nany need to parse it.  For example,\n\n\tM 040000 4b825dc642cb6eb9a060e54bf8d69288fbee4904 \"\"\n\nis a synonym for the deleteall command and the fast-import equivalent of\n\n\tgit read-tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904\n\nSigned-off-by: David Barr <david.barr@cordelta.com>\nCommit-message-by: Jonathan Nieder <jrnieder@gmail.com>\nAcked-by: Sverre Rabbelier <srabbelier@gmail.com>\nTested-by: Ramkumar Ramachandra <artagnon@gmail.com>\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n Documentation/git-fast-import.txt |    3 +++\n fast-import.c                     |    9 +++++++++\n t/t9300-fast-import.sh            |   21 +++++++++++++++++++++\n 3 files changed, 33 insertions(+), 0 deletions(-)\n\ndiff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt\nindex 966ba4f..90a4666 100644\n--- a/Documentation/git-fast-import.txt\n+++ b/Documentation/git-fast-import.txt\n@@ -524,6 +524,9 @@ start with double quote (`\"`).\n If an `LF` or double quote must be encoded into `<path>` shell-style\n quoting should be used, e.g. `\"path/with\\n and \\\" in it\"`.\n \n+Additionally, in `040000` mode, `<path>` may also be an empty string\n+(`\"\"`) to specify the root of the tree.\n+\n The value of `<path>` must be in canonical form. That is it must not:\n \n * contain an empty directory component (e.g. `foo//bar` is invalid),\ndiff --git a/fast-import.c b/fast-import.c\nindex 2317b0f..8f68a89 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -1454,6 +1454,15 @@ static int tree_content_set(\n \t\tn = slash1 - p;\n \telse\n \t\tn = strlen(p);\n+\tif (!slash1 && !n) {\n+\t\tif (!S_ISDIR(mode))\n+\t\t\tdie(\"Root cannot be a non-directory\");\n+\t\thashcpy(root->versions[1].sha1, sha1);\n+\t\tif (root->tree)\n+\t\t\trelease_tree_content_recursive(root->tree);\n+\t\troot->tree = subtree;\n+\t\treturn 1;\n+\t}\n \tif (!n)\n \t\tdie(\"Empty path component found in input\");\n \tif (!slash1 && !S_ISDIR(mode) && subtree)\ndiff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh\nindex 7c05920..3c0cf05 100755\n--- a/t/t9300-fast-import.sh\n+++ b/t/t9300-fast-import.sh\n@@ -875,6 +875,27 @@ test_expect_success \\\n \t compare_diff_raw expect actual'\n \n test_expect_success \\\n+\t'N: copy root directory by tree hash' \\\n+\t'cat >expect <<-\\EOF &&\n+\t:100755 000000 f1fb5da718392694d0076d677d6d0e364c79b0bc 0000000000000000000000000000000000000000 D\tfile3/newf\n+\t:100644 000000 7123f7f44e39be127c5eb701e5968176ee9d78b1 0000000000000000000000000000000000000000 D\tfile3/oldf\n+\tEOF\n+\t root=$(git rev-parse refs/heads/branch^0^{tree}) &&\n+\t cat >input <<-INPUT_END &&\n+\tcommit refs/heads/N6\n+\tcommitter $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE\n+\tdata <<COMMIT\n+\tcopy root directory by tree hash\n+\tCOMMIT\n+\n+\tfrom refs/heads/branch^0\n+\tM 040000 $root \"\"\n+\tINPUT_END\n+\t git fast-import <input &&\n+\t git diff-tree -C --find-copies-harder -r N4 N6 >actual &&\n+\t compare_diff_raw expect actual'\n+\n+test_expect_success \\\n \t'N: modify copied tree' \\\n \t'cat >expect <<-\\EOF &&\n \t:100644 100644 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 C100\tnewdir/interesting\tfile3/file5\n-- \n1.7.3\n"},{"id":"153220","messageId":"20101011063429.GA32034@burratino","threadId":"25378","inReplyTo":"1286681415-1831-1-git-send-email-david.barr@cordelta.com","subject":"Re: [PATCH] fast-import: Allow filemodify to set the root","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-10-11T06:34:29Z","receivedAt":"2010-10-11T06:34:29Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"David Barr wrote:\n\n> --- a/Documentation/git-fast-import.txt\n> +++ b/Documentation/git-fast-import.txt\n> @@ -524,6 +524,9 @@ start with double quote (`\"`).\n>  If an `LF` or double quote must be encoded into `<path>` shell-style\n>  quoting should be used, e.g. `\"path/with\\n and \\\" in it\"`.\n>  \n> +Additionally, in `040000` mode, `<path>` may also be an empty string\n> +(`\"\"`) to specify the root of the tree.\n> +\n\nIdeally this would be not so much \"Additionally\" as \"For example\".\nMaybe just:\n\n\tAn empty path (\"\") refers to the toplevel directory of\n\tthe tracked tree.\n\n> --- a/fast-import.c\n> +++ b/fast-import.c\n> @@ -1454,6 +1454,15 @@ static int tree_content_set(\n>  \t\tn = slash1 - p;\n>  \telse\n>  \t\tn = strlen(p);\n> +\tif (!slash1 && !n) {\n> +\t\tif (!S_ISDIR(mode))\n> +\t\t\tdie(\"Root cannot be a non-directory\");\n> +\t\thashcpy(root->versions[1].sha1, sha1);\n> +\t\tif (root->tree)\n> +\t\t\trelease_tree_content_recursive(root->tree);\n> +\t\troot->tree = subtree;\n> +\t\treturn 1;\n> +\t}\n>  \tif (!n)\n>  \t\tdie(\"Empty path component found in input\");\n\nBackground for the curious: tree_content_set() is a recursive function\nto modify a tree-in-the-making by changing the entry at path p to\nrefer to some specified content with a given mode.  The recursion\nworks as one might expect:\n\n\ttree_content_set(root, \"foo/bar/baz\", ...) ->\n\t tree_content_set(root:foo, \"bar/baz\", ...) ->\n\t  et c\n\nThe \"if (!n)\" check introduced in v1.5.1.3~11^2~1 (Don't allow empty\npathnames in fast-import, 2007-04-28) ensures fast-import doesn't\nend up creating a subdirectory corresponding to an empty path\ncomponent in a pathname like \"foo//bar/baz\".\n\nWith this patch, an empty path component is allowed again, but only\nas the last path component.  It is used to modify directories.  So,\nfor example,\n\n\ttree_content_set(root, \"foo/bar/\", sha1, S_IFDIR)\n\nbecomes an almost-synonym for\n\n\ttree_content_set(root, \"foo/bar\", sha1, S_IFDIR)\n\nand\n\n\ttree_content_set(root, \"foo/bar/\", sha1, S_IFREG | 0644)\n\nis rejected.\n\nWhy do I say almost-synonym?  Because as Ram pointed out, you are not\ninvalidating the parent tree hash, because there may not even _be_ a\nparent tree.\n\nIn other words, with this patch, I worry that a\n\n\tM 040000 ...sha1... \"foo/bar/\"\n\nline would be sometimes ignored and sometimes not.  Confusing.\n\nWould it make sense to just handle the empty-path case in the callers\n(file_change_m(), file_change_cr()) to avoid this?\n"},{"id":"153681","messageId":"20101018010005.GA25524@burratino","threadId":"25378","inReplyTo":"20101011063429.GA32034@burratino","subject":"[PATCH 0/2] Re: fast-import: Allow filemodify to set the root","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-10-18T01:00:05Z","receivedAt":"2010-10-18T01:00:05Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Jonathan Nieder wrote:\n\n> In other words, with this patch, I worry that a\n> \n> \tM 040000 ...sha1... \"foo/bar/\"\n> \n> line would be sometimes ignored and sometimes not.  Confusing.\n\nHey, my worries were unfounded!  Nice when that happens.\n\nPatch 1 is an unrelated bugfix.\n\n> Would it make sense to just handle the empty-path case in the callers\n> (file_change_m(), file_change_cr()) to avoid this?\n\nPatch 2 introduces this change anyway, to propose that change, to\navoid unnecessarily introducing a new \"foo/bar/\" syntax that does not\nwork with git 1.7.3.\n\nI hope they are not too dull to read.\nJonathan Nieder (2):\n  fast-import: filemodify after M 040000 <tree> \"\" crashes\n  fast-import: tighten M 040000 syntax\n\n fast-import.c          |   54 +++++++++++++++++++++++++++++---------\n t/t9300-fast-import.sh |   68 ++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 109 insertions(+), 13 deletions(-)\n\n-- \n1.7.2.3\n"},{"id":"153682","messageId":"20101018010338.GB25524@burratino","threadId":"25378","inReplyTo":"20101018010005.GA25524@burratino","subject":"[PATCH 1/2] fast-import: filemodify after M 040000 <tree> \"\" crashes","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-10-18T01:03:38Z","receivedAt":"2010-10-18T01:03:38Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Until M 040000 <tree> \"\" syntax was introduced in commit 2794ad5\n(fast-import: Allow filemodify to set the root, 2010-10-10), it\nwas impossible for the root entry to refer to an unloaded tree.\nUpdate various functions to take that possibility into account.\nOtherwise\n\n\tM 040000 <tree> \"\"\n\tM 100644 :1 \"foo\"\n\nand similar commands (using D, C, or R after resetting the root\ntree) segfault.\n\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\n fast-import.c          |   20 ++++++++++++++++----\n t/t9300-fast-import.sh |   38 ++++++++++++++++++++++++++++++++++++++\n 2 files changed, 54 insertions(+), 4 deletions(-)\n\ndiff --git a/fast-import.c b/fast-import.c\nindex 8f68a89..aaf47c5 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -1444,7 +1444,7 @@ static int tree_content_set(\n \tconst uint16_t mode,\n \tstruct tree_content *subtree)\n {\n-\tstruct tree_content *t = root->tree;\n+\tstruct tree_content *t;\n \tconst char *slash1;\n \tunsigned int i, n;\n \tstruct tree_entry *e;\n@@ -1468,6 +1468,9 @@ static int tree_content_set(\n \tif (!slash1 && !S_ISDIR(mode) && subtree)\n \t\tdie(\"Non-directories cannot have subtrees\");\n \n+\tif (!root->tree)\n+\t\tload_tree(root);\n+\tt = root->tree;\n \tfor (i = 0; i < t->entry_count; i++) {\n \t\te = t->entries[i];\n \t\tif (e->name->str_len == n && !strncmp(p, e->name->str_dat, n)) {\n@@ -1523,7 +1526,7 @@ static int tree_content_remove(\n \tconst char *p,\n \tstruct tree_entry *backup_leaf)\n {\n-\tstruct tree_content *t = root->tree;\n+\tstruct tree_content *t;\n \tconst char *slash1;\n \tunsigned int i, n;\n \tstruct tree_entry *e;\n@@ -1534,6 +1537,9 @@ static int tree_content_remove(\n \telse\n \t\tn = strlen(p);\n \n+\tif (!root->tree)\n+\t\tload_tree(root);\n+\tt = root->tree;\n \tfor (i = 0; i < t->entry_count; i++) {\n \t\te = t->entries[i];\n \t\tif (e->name->str_len == n && !strncmp(p, e->name->str_dat, n)) {\n@@ -1581,7 +1587,7 @@ static int tree_content_get(\n \tconst char *p,\n \tstruct tree_entry *leaf)\n {\n-\tstruct tree_content *t = root->tree;\n+\tstruct tree_content *t;\n \tconst char *slash1;\n \tunsigned int i, n;\n \tstruct tree_entry *e;\n@@ -1592,6 +1598,9 @@ static int tree_content_get(\n \telse\n \t\tn = strlen(p);\n \n+\tif (!root->tree)\n+\t\tload_tree(root);\n+\tt = root->tree;\n \tfor (i = 0; i < t->entry_count; i++) {\n \t\te = t->entries[i];\n \t\tif (e->name->str_len == n && !strncmp(p, e->name->str_dat, n)) {\n@@ -2056,13 +2065,16 @@ static uintmax_t do_change_note_fanout(\n \t\tchar *fullpath, unsigned int fullpath_len,\n \t\tunsigned char fanout)\n {\n-\tstruct tree_content *t = root->tree;\n+\tstruct tree_content *t;\n \tstruct tree_entry *e, leaf;\n \tunsigned int i, tmp_hex_sha1_len, tmp_fullpath_len;\n \tuintmax_t num_notes = 0;\n \tunsigned char sha1[20];\n \tchar realpath[60];\n \n+\tif (!root->tree);\n+\t\tload_tree(root);\n+\tt = root->tree;\n \tfor (i = 0; t && i < t->entry_count; i++) {\n \t\te = t->entries[i];\n \t\ttmp_hex_sha1_len = hex_sha1_len + e->name->str_len;\ndiff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh\nindex 3c0cf05..de95a6e 100755\n--- a/t/t9300-fast-import.sh\n+++ b/t/t9300-fast-import.sh\n@@ -928,6 +928,43 @@ test_expect_success \\\n \t git diff-tree -C --find-copies-harder -r N5^^ N5 >actual &&\n \t compare_diff_raw expect actual'\n \n+test_expect_success \\\n+\t'N: copy to root by id and modify' \\\n+\t'echo \"hello, world\" >expect.foo &&\n+\t echo hello >expect.bar &&\n+\t git fast-import <<-SETUP_END &&\n+\tcommit refs/heads/N7\n+\tcommitter $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE\n+\tdata <<COMMIT\n+\thello, tree\n+\tCOMMIT\n+\n+\tdeleteall\n+\tM 644 inline foo/bar\n+\tdata <<EOF\n+\thello\n+\tEOF\n+\tSETUP_END\n+\n+\t tree=$(git rev-parse --verify N7:) &&\n+\t git fast-import <<-INPUT_END &&\n+\tcommit refs/heads/N8\n+\tcommitter $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE\n+\tdata <<COMMIT\n+\tcopy to root by id and modify\n+\tCOMMIT\n+\n+\tM 040000 $tree \"\"\n+\tM 644 inline foo/foo\n+\tdata <<EOF\n+\thello, world\n+\tEOF\n+\tINPUT_END\n+\t git show N8:foo/foo >actual.foo &&\n+\t git show N8:foo/bar >actual.bar &&\n+\t test_cmp expect.foo actual.foo &&\n+\t test_cmp expect.bar actual.bar'\n+\n ###\n ### series O\n ###\n-- \n1.7.2.3\n"},{"id":"153683","messageId":"20101018010853.GC25524@burratino","threadId":"25378","inReplyTo":"20101018010005.GA25524@burratino","subject":"[PATCH 2/2] fast-import: tighten M 040000 syntax","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-10-18T01:08:53Z","receivedAt":"2010-10-18T01:08:53Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"When tree_content_set() is asked to modify the path \"foo/bar/\",\nit first recurses like so:\n\n\ttree_content_set(root, \"foo/bar/\", sha1, S_IFDIR) ->\n\t tree_content_set(root:foo, \"bar/\", ...) ->\n\t  tree_content_set(root:foo/bar, \"\", ...)\n\nAnd as a side-effect of 2794ad5 (fast-import: Allow filemodify to set\nthe root, 2010-10-10), this last call is accepted and changes\nthe tree entry for root:foo/bar to refer to the specified tree.\n\nThat seems safe enough but let's reject the new syntax (we never meant\nto support it) and make it harder for frontends to introduce pointless\nincompatibilities with git fast-import 1.7.3.\n\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\n fast-import.c          |   34 +++++++++++++++++++++++++---------\n t/t9300-fast-import.sh |   30 ++++++++++++++++++++++++++++++\n 2 files changed, 55 insertions(+), 9 deletions(-)\n\ndiff --git a/fast-import.c b/fast-import.c\nindex aaf47c5..cb947c1 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -1437,6 +1437,20 @@ static void store_tree(struct tree_entry *root)\n \tt->entry_count -= del;\n }\n \n+static void tree_content_replace(\n+\tstruct tree_entry *root,\n+\tconst unsigned char *sha1,\n+\tconst uint16_t mode,\n+\tstruct tree_content *newtree)\n+{\n+\tif (!S_ISDIR(mode))\n+\t\tdie(\"Root cannot be a non-directory\");\n+\thashcpy(root->versions[1].sha1, sha1);\n+\tif (root->tree)\n+\t\trelease_tree_content_recursive(root->tree);\n+\troot->tree = newtree;\n+}\n+\n static int tree_content_set(\n \tstruct tree_entry *root,\n \tconst char *p,\n@@ -1454,15 +1468,6 @@ static int tree_content_set(\n \t\tn = slash1 - p;\n \telse\n \t\tn = strlen(p);\n-\tif (!slash1 && !n) {\n-\t\tif (!S_ISDIR(mode))\n-\t\t\tdie(\"Root cannot be a non-directory\");\n-\t\thashcpy(root->versions[1].sha1, sha1);\n-\t\tif (root->tree)\n-\t\t\trelease_tree_content_recursive(root->tree);\n-\t\troot->tree = subtree;\n-\t\treturn 1;\n-\t}\n \tif (!n)\n \t\tdie(\"Empty path component found in input\");\n \tif (!slash1 && !S_ISDIR(mode) && subtree)\n@@ -2230,6 +2235,10 @@ static void file_change_m(struct branch *b)\n \t\t\t\tcommand_buf.buf);\n \t}\n \n+\tif (!*p) {\n+\t\ttree_content_replace(&b->branch_tree, sha1, mode, NULL);\n+\t\treturn;\n+\t}\n \ttree_content_set(&b->branch_tree, p, sha1, mode, NULL);\n }\n \n@@ -2288,6 +2297,13 @@ static void file_change_cr(struct branch *b, int rename)\n \t\ttree_content_get(&b->branch_tree, s, &leaf);\n \tif (!leaf.versions[1].mode)\n \t\tdie(\"Path %s not in branch\", s);\n+\tif (!*d) {\t/* C \"path/to/subdir\" \"\" */\n+\t\ttree_content_replace(&b->branch_tree,\n+\t\t\tleaf.versions[1].sha1,\n+\t\t\tleaf.versions[1].mode,\n+\t\t\tleaf.tree);\n+\t\treturn;\n+\t}\n \ttree_content_set(&b->branch_tree, d,\n \t\tleaf.versions[1].sha1,\n \t\tleaf.versions[1].mode,\ndiff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh\nindex 1df11ad..ce09457 100755\n--- a/t/t9300-fast-import.sh\n+++ b/t/t9300-fast-import.sh\n@@ -929,6 +929,20 @@ test_expect_success \\\n \t compare_diff_raw expect actual'\n \n test_expect_success \\\n+\t'N: reject foo/ syntax' \\\n+\t'subdir=$(git rev-parse refs/heads/branch^0:file2) &&\n+\t test_must_fail git fast-import <<-INPUT_END\n+\tcommit refs/heads/N5B\n+\tcommitter $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE\n+\tdata <<COMMIT\n+\tcopy with invalid syntax\n+\tCOMMIT\n+\n+\tfrom refs/heads/branch^0\n+\tM 040000 $subdir file3/\n+\tINPUT_END'\n+\n+test_expect_success \\\n \t'N: copy to root by id and modify' \\\n \t'echo \"hello, world\" >expect.foo &&\n \t echo hello >expect.bar &&\n@@ -965,6 +979,22 @@ test_expect_success \\\n \t test_cmp expect.foo actual.foo &&\n \t test_cmp expect.bar actual.bar'\n \n+test_expect_success \\\n+\t'N: extract subtree' \\\n+\t'branch=$(git rev-parse --verify refs/heads/branch^{tree}) &&\n+\t cat >input <<-INPUT_END &&\n+\tcommit refs/heads/N9\n+\tcommitter $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE\n+\tdata <<COMMIT\n+\textract subtree branch:newdir\n+\tCOMMIT\n+\n+\tM 040000 $branch \"\"\n+\tR \"newdir\" \"\"\n+\tINPUT_END\n+\t git fast-import <input &&\n+\t git diff --exit-code branch:newdir N9'\n+\n ###\n ### series O\n ###\n-- \n1.7.2.3\n"},{"id":"153684","messageId":"AANLkTik3iSSzKCxi9aeNw+ATPXvTN6yw-=NDGtqCidce@mail.gmail.com","threadId":"25378","inReplyTo":"20101018010338.GB25524@burratino","subject":"Re: [PATCH 1/2] fast-import: filemodify after M 040000 <tree> \"\" crashes","fromName":"Sverre Rabbelier","fromEmail":"srabbelier@gmail.com","sentAt":"2010-10-18T01:13:09Z","receivedAt":"2010-10-18T01:13:09Z","isPatch":true,"sender":{"key":"srabbelier@gmail.com","avatar":"https://avatars.githubusercontent.com/u/3098?v=4"},"body":"Heya,\n\nOn Sun, Oct 17, 2010 at 20:03, Jonathan Nieder <jrnieder@gmail.com> wrote:\n> Until M 040000 <tree> \"\" syntax was introduced in commit 2794ad5\n> (fast-import: Allow filemodify to set the root, 2010-10-10), it\n> was impossible for the root entry to refer to an unloaded tree.\n> Update various functions to take that possibility into account.\n> Otherwise\n>\n>        M 040000 <tree> \"\"\n>        M 100644 :1 \"foo\"\n>\n> and similar commands (using D, C, or R after resetting the root\n> tree) segfault.\n\nI'm curious, how come this not found earlier? Would seem like a fairly\nregular operation?\n\n-- \nCheers,\n\nSverre Rabbelier\n"},{"id":"153685","messageId":"20101018014404.GD25524@burratino","threadId":"25378","inReplyTo":"AANLkTik3iSSzKCxi9aeNw+ATPXvTN6yw-=NDGtqCidce@mail.gmail.com","subject":"Re: [PATCH 1/2] fast-import: filemodify after M 040000 <tree> \"\" crashes","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-10-18T01:44:04Z","receivedAt":"2010-10-18T01:44:04Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Sverre Rabbelier wrote:\n> On Sun, Oct 17, 2010 at 20:03, Jonathan Nieder <jrnieder@gmail.com> wrote:\n\n>>        M 040000 <tree> \"\"\n>>        M 100644 :1 \"foo\"\n>>\n>> and similar commands (using D, C, or R after resetting the root\n>> tree) segfault.\n>\n> I'm curious, how come this not found earlier? Would seem like a fairly\n> regular operation?\n\nSure, though that isn't what the feature has been used for so far.\n\nHooray for tests. :)\n\n-- 8< --\nSubject: t9300 (fast-import): another test for the \"replace root\" feature\n\nAnother test for the replace root feature.  One can imagine an\nimplementation for which R \"some/subdir\" \"\" would free some state\nassociated to the subdir and leave fast-import confused.\n\nLuckily, git's is not such an implementation.\n\nWhile at it, change the previous test to use C \"some/subdir\" \"\"\ninstead of R (i.e., test both syntaxes).\n\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\n t/t9300-fast-import.sh |   43 ++++++++++++++++++++++++++++++++++++++++++-\n 1 files changed, 42 insertions(+), 1 deletions(-)\n\ndiff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh\nindex ce09457..dd90a09 100755\n--- a/t/t9300-fast-import.sh\n+++ b/t/t9300-fast-import.sh\n@@ -990,11 +990,52 @@ test_expect_success \\\n \tCOMMIT\n \n \tM 040000 $branch \"\"\n-\tR \"newdir\" \"\"\n+\tC \"newdir\" \"\"\n \tINPUT_END\n \t git fast-import <input &&\n \t git diff --exit-code branch:newdir N9'\n \n+test_expect_success \\\n+\t'N: modify subtree, extract it, and modify again' \\\n+\t'echo hello >expect.baz &&\n+\t echo hello, world >expect.qux &&\n+\t git fast-import <<-SETUP_END &&\n+\tcommit refs/heads/N10\n+\tcommitter $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE\n+\tdata <<COMMIT\n+\thello, tree\n+\tCOMMIT\n+\n+\tdeleteall\n+\tM 644 inline foo/bar/baz\n+\tdata <<EOF\n+\thello\n+\tEOF\n+\tSETUP_END\n+\n+\t tree=$(git rev-parse --verify N10:) &&\n+\t git fast-import <<-INPUT_END &&\n+\tcommit refs/heads/N11\n+\tcommitter $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE\n+\tdata <<COMMIT\n+\tcopy to root by id and modify\n+\tCOMMIT\n+\n+\tM 040000 $tree \"\"\n+\tM 100644 inline foo/bar/qux\n+\tdata <<EOF\n+\thello, world\n+\tEOF\n+\tR \"foo\" \"\"\n+\tC \"bar/qux\" \"bar/quux\"\n+\tINPUT_END\n+\t git show N11:bar/baz >actual.baz &&\n+\t git show N11:bar/qux >actual.qux &&\n+\t git show N11:bar/quux >actual.quux &&\n+\t test_cmp expect.baz actual.baz &&\n+\t test_cmp expect.qux actual.qux &&\n+\t test_cmp expect.qux actual.quux'\n+\n ###\n ### series O\n ###\n-- \n1.7.2.3\n"},{"id":"153895","messageId":"20101020202558.GA1151@burratino","threadId":"25378","inReplyTo":"20101018010338.GB25524@burratino","subject":"[PATCH] fast-import: do not clear notes in do_change_note_fanout()","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-10-20T20:25:58Z","receivedAt":"2010-10-20T20:25:58Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Commit 5edde51 (fast-import: filemodify after M 040000 <tree> \"\"\ncrashes, 2010-10-17) taught fast-import to load trees from the\nobject db as needed when it is time to access them.\n\nBut it went too far.  In change_note_fanout(), an empty,\nnot-loaded tree is not meant to destroy notes, so calling\nload_tree() at that point is exactly the wrong thing to do.\n\nKudos to Johan Herland for t9301, which caught this failure.\n\nReported-by: Thomas Rast <trast@student.ethz.ch>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\n[cleared cc list.]\n\nJonathan Nieder wrote:\n\n> +++ b/fast-import.c\n[...]\n> @@ -2056,13 +2065,16 @@ static uintmax_t do_change_note_fanout(\n>  \t\tchar *fullpath, unsigned int fullpath_len,\n>  \t\tunsigned char fanout)\n>  {\n> -\tstruct tree_content *t = root->tree;\n> +\tstruct tree_content *t;\n>  \tstruct tree_entry *e, leaf;\n>  \tunsigned int i, tmp_hex_sha1_len, tmp_fullpath_len;\n>  \tuintmax_t num_notes = 0;\n>  \tunsigned char sha1[20];\n>  \tchar realpath[60];\n>  \n> +\tif (!root->tree);\n> +\t\tload_tree(root);\n> +\tt = root->tree;\n>  \tfor (i = 0; t && i < t->entry_count; i++) {\n\nOops.  The !t case is normal here and certainly is not a request\nto turn t into an empty tree.  Here's a minimal fix.\n\n fast-import.c |    5 +----\n 1 files changed, 1 insertions(+), 4 deletions(-)\n\ndiff --git a/fast-import.c b/fast-import.c\nindex aaf47c5..d2458ea 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -2065,16 +2065,13 @@ static uintmax_t do_change_note_fanout(\n \t\tchar *fullpath, unsigned int fullpath_len,\n \t\tunsigned char fanout)\n {\n-\tstruct tree_content *t;\n+\tstruct tree_content *t = root->tree;\n \tstruct tree_entry *e, leaf;\n \tunsigned int i, tmp_hex_sha1_len, tmp_fullpath_len;\n \tuintmax_t num_notes = 0;\n \tunsigned char sha1[20];\n \tchar realpath[60];\n \n-\tif (!root->tree);\n-\t\tload_tree(root);\n-\tt = root->tree;\n \tfor (i = 0; t && i < t->entry_count; i++) {\n \t\te = t->entries[i];\n \t\ttmp_hex_sha1_len = hex_sha1_len + e->name->str_len;\n-- \n1.7.2.3\n"},{"id":"159539","messageId":"20110116022234.GA28452@burratino","threadId":"25378","inReplyTo":"1286681415-1831-1-git-send-email-david.barr@cordelta.com","subject":"[PATCH] Documentation/fast-import: put explanation of M 040000 <dataref> \"\" in context","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-01-16T02:22:35Z","receivedAt":"2011-01-16T02:22:35Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Omit needless words (\"Additionally ... <path> may also\" is redundant).\nWhile at it, place the explanation of this special case after the\ngeneral rules for paths to provide the reader with some context.\n\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\nA small language tweak.\n\n Documentation/git-fast-import.txt |    6 +++---\n 1 files changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt\nindex f56dfca..e2a46a5 100644\n--- a/Documentation/git-fast-import.txt\n+++ b/Documentation/git-fast-import.txt\n@@ -534,9 +534,6 @@ start with double quote (`\"`).\n If an `LF` or double quote must be encoded into `<path>` shell-style\n quoting should be used, e.g. `\"path/with\\n and \\\" in it\"`.\n \n-Additionally, in `040000` mode, `<path>` may also be an empty string\n-(`\"\"`) to specify the root of the tree.\n-\n The value of `<path>` must be in canonical form. That is it must not:\n \n * contain an empty directory component (e.g. `foo//bar` is invalid),\n@@ -545,6 +542,9 @@ The value of `<path>` must be in canonical form. That is it must not:\n * contain the special component `.` or `..` (e.g. `foo/./bar` and\n   `foo/../bar` are invalid).\n \n+In `040000` mode, `<path>` can be the empty string (`\"\"`)\n+to specify the root of the tree.\n+\n It is recommended that `<path>` always be encoded using UTF-8.\n \n `filedelete`\n-- \n1.7.4.rc2\n"},{"id":"159580","messageId":"7v1v4amex6.fsf@alter.siamese.dyndns.org","threadId":"25378","inReplyTo":"20110116022234.GA28452@burratino","subject":"Re: [PATCH] Documentation/fast-import: put explanation of M 040000 <dataref> \"\" in context","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-01-18T15:04:21Z","receivedAt":"2011-01-18T15:04:21Z","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> Omit needless words (\"Additionally ... <path> may also\" is redundant).\n> While at it, place the explanation of this special case after the\n> general rules for paths to provide the reader with some context.\n>\n> diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt\n> index f56dfca..e2a46a5 100644\n> --- a/Documentation/git-fast-import.txt\n> +++ b/Documentation/git-fast-import.txt\n> @@ -545,6 +542,9 @@ The value of `<path>` must be in canonical form. That is it must not:\n>  * contain the special component `.` or `..` (e.g. `foo/./bar` and\n>    `foo/../bar` are invalid).\n>  \n> +In `040000` mode, `<path>` can be the empty string (`\"\"`)\n> +to specify the root of the tree.\n> +\n\nThanks, but is \"In x mode\" an appropriate wording here in the first place?\nI would expect x to be some action (e.g. In navigation mode, typing many\nkeys just beep, and in edit mode, typing most keys just insert -- vi) but\nthe word \"mode\" doesn't fit that pattern (unless we take a bitpattern \"x\"\nto mean \"the act of creating a path with mode bits x\").\n"},{"id":"159599","messageId":"20110118211654.GA22763@burratino","threadId":"25378","inReplyTo":"7v1v4amex6.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH] Documentation/fast-import: put explanation of M 040000 <dataref> \"\" in context","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-01-18T21:16:54Z","receivedAt":"2011-01-18T21:16:54Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Junio C Hamano wrote:\n> Jonathan Nieder <jrnieder@gmail.com> writes:\n\n>> +++ b/Documentation/git-fast-import.txt\n>> @@ -545,6 +542,9 @@ The value of `<path>` must be in canonical form. That is it must not:\n>>  * contain the special component `.` or `..` (e.g. `foo/./bar` and\n>>    `foo/../bar` are invalid).\n>>  \n>> +In `040000` mode, `<path>` can be the empty string (`\"\"`)\n>> +to specify the root of the tree.\n>> +\n>\n> Thanks, but is \"In x mode\" an appropriate wording here in the first place?\n\nGood point.  No, it isn't.\n\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\nFor squashing.\n\n Documentation/git-fast-import.txt |    2 +-\n 1 files changed, 1 insertions(+), 1 deletions(-)\n\ndiff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt\nindex 43d2174..7068de3 100644\n--- a/Documentation/git-fast-import.txt\n+++ b/Documentation/git-fast-import.txt\n@@ -542,7 +542,7 @@ The value of `<path>` must be in canonical form. That is it must not:\n * contain the special component `.` or `..` (e.g. `foo/./bar` and\n   `foo/../bar` are invalid).\n \n-In `040000` mode, `<path>` can be the empty string (`\"\"`)\n+If `<mode>` is `040000`, `<path>` can be the empty string (`\"\"`)\n to specify the root of the tree.\n \n It is recommended that `<path>` always be encoded using UTF-8.\n-- \n1.7.4.rc2\n"},{"id":"159606","messageId":"7vk4i1khvp.fsf@alter.siamese.dyndns.org","threadId":"25378","inReplyTo":"20110118211654.GA22763@burratino","subject":"Re: [PATCH] Documentation/fast-import: put explanation of M 040000 <dataref> \"\" in context","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-01-18T21:43:22Z","receivedAt":"2011-01-18T21:43:22Z","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> diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt\n> index 43d2174..7068de3 100644\n> --- a/Documentation/git-fast-import.txt\n> +++ b/Documentation/git-fast-import.txt\n> @@ -542,7 +542,7 @@ The value of `<path>` must be in canonical form. That is it must not:\n>  * contain the special component `.` or `..` (e.g. `foo/./bar` and\n>    `foo/../bar` are invalid).\n>  \n> -In `040000` mode, `<path>` can be the empty string (`\"\"`)\n> +If `<mode>` is `040000`, `<path>` can be the empty string (`\"\"`)\n>  to specify the root of the tree.\n\nFor whom is this paragraph written?  People who produce g-f-i streams, or\npeople who interpret somebody else's g-f-i streams?\n\nI am wondering if it is easier to read if we consistently target the\nformer, something like this:\n\n        The root of the tree can be represented by `<mode> 040000` with an\n        empty string as `<path>`.\n\nbecause all the surrounding description seems to describe rules\n(e.g. \"quoting should be used\", \"The value of `<path>` must be ...\").\n"},{"id":"159607","messageId":"20110118220226.GB22763@burratino","threadId":"25378","inReplyTo":"7vk4i1khvp.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH] Documentation/fast-import: put explanation of M 040000 <dataref> \"\" in context","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-01-18T22:02:26Z","receivedAt":"2011-01-18T22:02:26Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Junio C Hamano wrote:\n> Jonathan Nieder <jrnieder@gmail.com> writes:\n\n>> +++ b/Documentation/git-fast-import.txt\n>> @@ -542,7 +542,7 @@ The value of `<path>` must be in canonical form. That is it must not:\n>>  * contain the special component `.` or `..` (e.g. `foo/./bar` and\n>>    `foo/../bar` are invalid).\n>>  \n>> -In `040000` mode, `<path>` can be the empty string (`\"\"`)\n>> +If `<mode>` is `040000`, `<path>` can be the empty string (`\"\"`)\n>>  to specify the root of the tree.\n>\n> For whom is this paragraph written?  People who produce g-f-i streams, or\n> people who interpret somebody else's g-f-i streams?\n> \n> I am wondering if it is easier to read if we consistently target the\n> former, something like this:\n> \n>         The root of the tree can be represented by `<mode> 040000` with an\n>         empty string as `<path>`.\n\nSounds good to me.  I suppose the clause \"by <mode> 040000\" should just\nbe left out --- we already explained that directories must have mode\nS_IFDIR a few lines earlier.\n"}]}