{"thread":{"id":"34818","subject":"[PATCH v3 01/11] replace: forbid replacing an object with one of a different type","startedAt":"2013-08-31T19:12:03Z","lastAt":"2013-09-03T09:29:39Z","messageCount":33,"participants":["Christian Couder","Philip Oakley","Eric Sunshine","Jonathan Nieder"],"isPatch":true,"patchVersion":3,"patchTotal":11},"messages":[{"id":"226433","messageId":"20130831190528.26699.33964.chriscool@tuxfamily.org","threadId":"34818","inReplyTo":null,"subject":"[PATCH v3 00/11] Check replacement object type and minor updates","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2013-08-31T19:12:03Z","receivedAt":"2013-08-31T19:12:03Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"In this new version of the series, the only change in the 5 first\npatches, is a small change in the commit message of patch 1.\n\nPatches from 6/11 to 11/11 are all new:\n\t- 6/11, 7/11 and 8/11 are about bypassing the type check\n\tif -f is used\n\t- 9/11, 10/11 and 11/11 are about adding long option names\n\nChristian Couder (11):\n  replace: forbid replacing an object with one of a different type\n  Documentation/replace: state that objects must be of the same type\n  t6050-replace: test that objects are of the same type\n  t6050-replace: add test to clean up all the replace refs\n  Documentation/replace: add Creating Replacement Objects section\n  replace: bypass the type check if -f option is used\n  Documentation/replace: tell that -f option bypasses the type check\n  t6050-replace: check that -f option bypasses the type check\n  replace: allow long option names\n  Documentation/replace: list long option names\n  t6050-replace: use some long option names\n\n Documentation/git-replace.txt | 28 +++++++++++++++++++++++++---\n builtin/replace.c             | 16 +++++++++++++---\n t/t6050-replace.sh            | 31 ++++++++++++++++++++++++++++---\n 3 files changed, 66 insertions(+), 9 deletions(-)\n\n-- \n1.8.4.rc1.31.g530f5ce.dirty\n"},{"id":"226431","messageId":"20130831191215.26699.18957.chriscool@tuxfamily.org","threadId":"34818","inReplyTo":"20130831190528.26699.33964.chriscool@tuxfamily.org","subject":"[PATCH v3 01/11] replace: forbid replacing an object with one of a different type","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2013-08-31T19:12:04Z","receivedAt":"2013-08-31T19:12:04Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Users replacing an object with one of a different type were not\nprevented to do so, even if it was obvious, and stated in the doc,\nthat bad things would result from doing that.\n\nTo avoid mistakes, it is better to just forbid that though.\n\nIf one object is replaced with one of a different type, the only way\nto keep the history valid is to also replace all the other objects\nthat point to the replaced object. That's because:\n\n* Annotated tags contain the type of the tagged object.\n\n* The tree/parent lines in commits must be a tree and commits, resp.\n\n* The object types referred to by trees are specified in the 'mode'\n  field:\n    100644 and 100755    blob\n    160000               commit\n    040000               tree\n  (these are the only valid modes)\n\n* Blobs don't point at anything.\n\nThe doc will be updated in a later patch.\n\nAcked-by: Philip Oakley <philipoakley@iee.org>\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n builtin/replace.c | 10 ++++++++++\n 1 file changed, 10 insertions(+)\n\ndiff --git a/builtin/replace.c b/builtin/replace.c\nindex 59d3115..9a94769 100644\n--- a/builtin/replace.c\n+++ b/builtin/replace.c\n@@ -85,6 +85,7 @@ static int replace_object(const char *object_ref, const char *replace_ref,\n \t\t\t  int force)\n {\n \tunsigned char object[20], prev[20], repl[20];\n+\tenum object_type obj_type, repl_type;\n \tchar ref[PATH_MAX];\n \tstruct ref_lock *lock;\n \n@@ -100,6 +101,15 @@ static int replace_object(const char *object_ref, const char *replace_ref,\n \tif (check_refname_format(ref, 0))\n \t\tdie(\"'%s' is not a valid ref name.\", ref);\n \n+\tobj_type = sha1_object_info(object, NULL);\n+\trepl_type = sha1_object_info(repl, NULL);\n+\tif (obj_type != repl_type)\n+\t\tdie(\"Objects must be of the same type.\\n\"\n+\t\t    \"'%s' points to a replaced object of type '%s'\\n\"\n+\t\t    \"while '%s' points to a replacement object of type '%s'.\",\n+\t\t    object_ref, typename(obj_type),\n+\t\t    replace_ref, typename(repl_type));\n+\n \tif (read_ref(ref, prev))\n \t\thashclr(prev);\n \telse if (!force)\n-- \n1.8.4.rc1.31.g530f5ce.dirty\n"},{"id":"226435","messageId":"20130831191215.26699.99775.chriscool@tuxfamily.org","threadId":"34818","inReplyTo":"20130831190528.26699.33964.chriscool@tuxfamily.org","subject":"[PATCH v3 02/11] Documentation/replace: state that objects must be of the same type","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2013-08-31T19:12:05Z","receivedAt":"2013-08-31T19:12:05Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"A previous patch ensures that both the replaced and the replacement\nobjects passed to git replace must be of the same type.\n\nWhile at it state that there is no other restriction on both objects.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n Documentation/git-replace.txt | 7 ++++---\n 1 file changed, 4 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-replace.txt b/Documentation/git-replace.txt\nindex e0b4057..aa66d27 100644\n--- a/Documentation/git-replace.txt\n+++ b/Documentation/git-replace.txt\n@@ -20,6 +20,9 @@ The name of the 'replace' reference is the SHA-1 of the object that is\n replaced. The content of the 'replace' reference is the SHA-1 of the\n replacement object.\n \n+The replaced object and the replacement object must be of the same type.\n+There is no other restriction on them.\n+\n Unless `-f` is given, the 'replace' reference must not yet exist.\n \n Replacement references will be used by default by all Git commands\n@@ -69,9 +72,7 @@ go back to a replaced commit will move the branch to the replacement\n commit instead of the replaced commit.\n \n There may be other problems when using 'git rev-list' related to\n-pending objects. And of course things may break if an object of one\n-type is replaced by an object of another type (for example a blob\n-replaced by a commit).\n+pending objects.\n \n SEE ALSO\n --------\n-- \n1.8.4.rc1.31.g530f5ce.dirty\n"},{"id":"226439","messageId":"20130831191215.26699.38193.chriscool@tuxfamily.org","threadId":"34818","inReplyTo":"20130831190528.26699.33964.chriscool@tuxfamily.org","subject":"[PATCH v3 03/11] t6050-replace: test that objects are of the same type","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2013-08-31T19:12:06Z","receivedAt":"2013-08-31T19:12:06Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Signed-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n t/t6050-replace.sh | 13 +++++++++++++\n 1 file changed, 13 insertions(+)\n\ndiff --git a/t/t6050-replace.sh b/t/t6050-replace.sh\nindex decdc33..5c352c4 100755\n--- a/t/t6050-replace.sh\n+++ b/t/t6050-replace.sh\n@@ -263,4 +263,17 @@ test_expect_success 'not just commits' '\n \ttest_cmp file.replaced file\n '\n \n+test_expect_success 'replaced and replacement objects must be of the same type' '\n+\ttest_must_fail git replace mytag $HASH1 2>err &&\n+\tgrep \"mytag. points to a replaced object of type .tag\" err &&\n+\tgrep \"$HASH1. points to a replacement object of type .commit\" err &&\n+\ttest_must_fail git replace HEAD^{tree} HEAD~1 2>err &&\n+\tgrep \"HEAD^{tree}. points to a replaced object of type .tree\" err &&\n+\tgrep \"HEAD~1. points to a replacement object of type .commit\" err &&\n+\tBLOB=$(git rev-parse :file) &&\n+\ttest_must_fail git replace HEAD^ $BLOB 2>err &&\n+\tgrep \"HEAD^. points to a replaced object of type .commit\" err &&\n+\tgrep \"$BLOB. points to a replacement object of type .blob\" err\n+'\n+\n test_done\n-- \n1.8.4.rc1.31.g530f5ce.dirty\n"},{"id":"226432","messageId":"20130831191215.26699.14888.chriscool@tuxfamily.org","threadId":"34818","inReplyTo":"20130831190528.26699.33964.chriscool@tuxfamily.org","subject":"[PATCH v3 04/11] t6050-replace: add test to clean up all the replace refs","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2013-08-31T19:12:07Z","receivedAt":"2013-08-31T19:12:07Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Signed-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n t/t6050-replace.sh | 6 ++++++\n 1 file changed, 6 insertions(+)\n\ndiff --git a/t/t6050-replace.sh b/t/t6050-replace.sh\nindex 5c352c4..05be228 100755\n--- a/t/t6050-replace.sh\n+++ b/t/t6050-replace.sh\n@@ -276,4 +276,10 @@ test_expect_success 'replaced and replacement objects must be of the same type'\n \tgrep \"$BLOB. points to a replacement object of type .blob\" err\n '\n \n+test_expect_success 'replace ref cleanup' '\n+\ttest -n \"$(git replace)\" &&\n+\tgit replace -d $(git replace) &&\n+\ttest -z \"$(git replace)\"\n+'\n+\n test_done\n-- \n1.8.4.rc1.31.g530f5ce.dirty\n"},{"id":"226436","messageId":"20130831191215.26699.37641.chriscool@tuxfamily.org","threadId":"34818","inReplyTo":"20130831190528.26699.33964.chriscool@tuxfamily.org","subject":"[PATCH v3 05/11] Documentation/replace: add Creating Replacement Objects section","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2013-08-31T19:12:08Z","receivedAt":"2013-08-31T19:12:08Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"There were no hints in the documentation about how to create\nreplacement objects.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n Documentation/git-replace.txt | 16 ++++++++++++++++\n 1 file changed, 16 insertions(+)\n\ndiff --git a/Documentation/git-replace.txt b/Documentation/git-replace.txt\nindex aa66d27..736b48c 100644\n--- a/Documentation/git-replace.txt\n+++ b/Documentation/git-replace.txt\n@@ -64,6 +64,19 @@ OPTIONS\n \tTyping \"git replace\" without arguments, also lists all replace\n \trefs.\n \n+CREATING REPLACEMENT OBJECTS\n+----------------------------\n+\n+linkgit:git-filter-branch[1], linkgit:git-hash-object[1] and\n+linkgit:git-rebase[1], among other git commands, can be used to create\n+replacement objects from existing objects.\n+\n+If you want to replace many blobs, trees or commits that are part of a\n+string of commits, you may just want to create a replacement string of\n+commits and then only replace the commit at the tip of the target\n+string of commits with the commit at the tip of the replacement string\n+of commits.\n+\n BUGS\n ----\n Comparing blobs or trees that have been replaced with those that\n@@ -76,6 +89,9 @@ pending objects.\n \n SEE ALSO\n --------\n+linkgit:git-hash-object[1]\n+linkgit:git-filter-branch[1]\n+linkgit:git-rebase[1]\n linkgit:git-tag[1]\n linkgit:git-branch[1]\n linkgit:git[1]\n-- \n1.8.4.rc1.31.g530f5ce.dirty\n"},{"id":"226438","messageId":"20130831191215.26699.25627.chriscool@tuxfamily.org","threadId":"34818","inReplyTo":"20130831190528.26699.33964.chriscool@tuxfamily.org","subject":"[PATCH v3 06/11] replace: bypass the type check if -f option is used","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2013-08-31T19:12:09Z","receivedAt":"2013-08-31T19:12:09Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"If -f option, which means '--force', is used, we can allow an object\nto be replaced with one of a different type, as the user should know\nwhat (s)he is doing.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n builtin/replace.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/replace.c b/builtin/replace.c\nindex 9a94769..95736d9 100644\n--- a/builtin/replace.c\n+++ b/builtin/replace.c\n@@ -103,7 +103,7 @@ static int replace_object(const char *object_ref, const char *replace_ref,\n \n \tobj_type = sha1_object_info(object, NULL);\n \trepl_type = sha1_object_info(repl, NULL);\n-\tif (obj_type != repl_type)\n+\tif (!force && obj_type != repl_type)\n \t\tdie(\"Objects must be of the same type.\\n\"\n \t\t    \"'%s' points to a replaced object of type '%s'\\n\"\n \t\t    \"while '%s' points to a replacement object of type '%s'.\",\n-- \n1.8.4.rc1.31.g530f5ce.dirty\n"},{"id":"226442","messageId":"20130831191215.26699.720.chriscool@tuxfamily.org","threadId":"34818","inReplyTo":"20130831190528.26699.33964.chriscool@tuxfamily.org","subject":"[PATCH v3 07/11] Documentation/replace: tell that -f option bypasses the type check","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2013-08-31T19:12:10Z","receivedAt":"2013-08-31T19:12:10Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Signed-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n Documentation/git-replace.txt | 4 +++-\n 1 file changed, 3 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-replace.txt b/Documentation/git-replace.txt\nindex 736b48c..a2bd2ee 100644\n--- a/Documentation/git-replace.txt\n+++ b/Documentation/git-replace.txt\n@@ -21,10 +21,12 @@ replaced. The content of the 'replace' reference is the SHA-1 of the\n replacement object.\n \n The replaced object and the replacement object must be of the same type.\n-There is no other restriction on them.\n+This restriction can be bypassed using `-f`.\n \n Unless `-f` is given, the 'replace' reference must not yet exist.\n \n+There is no other restriction on the replaced and replacement objects.\n+\n Replacement references will be used by default by all Git commands\n except those doing reachability traversal (prune, pack transfer and\n fsck).\n-- \n1.8.4.rc1.31.g530f5ce.dirty\n"},{"id":"226440","messageId":"20130831191215.26699.37671.chriscool@tuxfamily.org","threadId":"34818","inReplyTo":"20130831190528.26699.33964.chriscool@tuxfamily.org","subject":"[PATCH v3 08/11] t6050-replace: check that -f option bypasses the type check","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2013-08-31T19:12:11Z","receivedAt":"2013-08-31T19:12:11Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Signed-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n t/t6050-replace.sh | 6 ++++++\n 1 file changed, 6 insertions(+)\n\ndiff --git a/t/t6050-replace.sh b/t/t6050-replace.sh\nindex 05be228..0b07a0b 100755\n--- a/t/t6050-replace.sh\n+++ b/t/t6050-replace.sh\n@@ -276,6 +276,12 @@ test_expect_success 'replaced and replacement objects must be of the same type'\n \tgrep \"$BLOB. points to a replacement object of type .blob\" err\n '\n \n+test_expect_success '-f option bypasses the type check' '\n+\tgit replace -f mytag $HASH1 2>err &&\n+\tgit replace -f HEAD^{tree} HEAD~1 2>err &&\n+\tgit replace -f HEAD^ $BLOB 2>err\n+'\n+\n test_expect_success 'replace ref cleanup' '\n \ttest -n \"$(git replace)\" &&\n \tgit replace -d $(git replace) &&\n-- \n1.8.4.rc1.31.g530f5ce.dirty\n"},{"id":"226437","messageId":"20130831191215.26699.17024.chriscool@tuxfamily.org","threadId":"34818","inReplyTo":"20130831190528.26699.33964.chriscool@tuxfamily.org","subject":"[PATCH v3 09/11] replace: allow long option names","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2013-08-31T19:12:12Z","receivedAt":"2013-08-31T19:12:12Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"It is now standard practice in Git to have both short and long option\nnames. So let's give a long option name to the git replace options too.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n builtin/replace.c | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/replace.c b/builtin/replace.c\nindex 95736d9..d4d1b75 100644\n--- a/builtin/replace.c\n+++ b/builtin/replace.c\n@@ -128,9 +128,9 @@ int cmd_replace(int argc, const char **argv, const char *prefix)\n {\n \tint list = 0, delete = 0, force = 0;\n \tstruct option options[] = {\n-\t\tOPT_BOOLEAN('l', NULL, &list, N_(\"list replace refs\")),\n-\t\tOPT_BOOLEAN('d', NULL, &delete, N_(\"delete replace refs\")),\n-\t\tOPT_BOOLEAN('f', NULL, &force, N_(\"replace the ref if it exists\")),\n+\t\tOPT_BOOLEAN('l', \"list\", &list, N_(\"list replace refs\")),\n+\t\tOPT_BOOLEAN('d', \"delete\", &delete, N_(\"delete replace refs\")),\n+\t\tOPT_BOOLEAN('f', \"force\", &force, N_(\"replace the ref if it exists\")),\n \t\tOPT_END()\n \t};\n \n-- \n1.8.4.rc1.31.g530f5ce.dirty\n"},{"id":"226434","messageId":"20130831191215.26699.45790.chriscool@tuxfamily.org","threadId":"34818","inReplyTo":"20130831190528.26699.33964.chriscool@tuxfamily.org","subject":"[PATCH v3 10/11] Documentation/replace: list long option names","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2013-08-31T19:12:13Z","receivedAt":"2013-08-31T19:12:13Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Signed-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n Documentation/git-replace.txt | 3 +++\n 1 file changed, 3 insertions(+)\n\ndiff --git a/Documentation/git-replace.txt b/Documentation/git-replace.txt\nindex a2bd2ee..414000e 100644\n--- a/Documentation/git-replace.txt\n+++ b/Documentation/git-replace.txt\n@@ -54,13 +54,16 @@ achieve the same effect as the `--no-replace-objects` option.\n OPTIONS\n -------\n -f::\n+--force::\n \tIf an existing replace ref for the same object exists, it will\n \tbe overwritten (instead of failing).\n \n -d::\n+--delete::\n \tDelete existing replace refs for the given objects.\n \n -l <pattern>::\n+--list <pattern>::\n \tList replace refs for objects that match the given pattern (or\n \tall if no pattern is given).\n \tTyping \"git replace\" without arguments, also lists all replace\n-- \n1.8.4.rc1.31.g530f5ce.dirty\n"},{"id":"226441","messageId":"20130831191215.26699.76207.chriscool@tuxfamily.org","threadId":"34818","inReplyTo":"20130831190528.26699.33964.chriscool@tuxfamily.org","subject":"[PATCH v3 11/11] t6050-replace: use some long option names","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2013-08-31T19:12:14Z","receivedAt":"2013-08-31T19:12:14Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"So that they are tested a litlle bit too.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n t/t6050-replace.sh | 8 ++++----\n 1 file changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/t/t6050-replace.sh b/t/t6050-replace.sh\nindex 0b07a0b..5dc26e8 100755\n--- a/t/t6050-replace.sh\n+++ b/t/t6050-replace.sh\n@@ -122,9 +122,9 @@ test_expect_success '\"git replace\" listing and deleting' '\n      test \"$HASH2\" = \"$(git replace -l)\" &&\n      test \"$HASH2\" = \"$(git replace)\" &&\n      aa=${HASH2%??????????????????????????????????????} &&\n-     test \"$HASH2\" = \"$(git replace -l \"$aa*\")\" &&\n+     test \"$HASH2\" = \"$(git replace --list \"$aa*\")\" &&\n      test_must_fail git replace -d $R &&\n-     test_must_fail git replace -d &&\n+     test_must_fail git replace --delete &&\n      test_must_fail git replace -l -d $HASH2 &&\n      git replace -d $HASH2 &&\n      git show $HASH2 | grep \"A U Thor\" &&\n@@ -147,7 +147,7 @@ test_expect_success '\"git replace\" resolves sha1' '\n      git show $HASH2 | grep \"O Thor\" &&\n      test_must_fail git replace $HASH2 $R &&\n      git replace -f $HASH2 $R &&\n-     test_must_fail git replace -f &&\n+     test_must_fail git replace --force &&\n      test \"$HASH2\" = \"$(git replace)\"\n '\n \n@@ -278,7 +278,7 @@ test_expect_success 'replaced and replacement objects must be of the same type'\n \n test_expect_success '-f option bypasses the type check' '\n \tgit replace -f mytag $HASH1 2>err &&\n-\tgit replace -f HEAD^{tree} HEAD~1 2>err &&\n+\tgit replace --force HEAD^{tree} HEAD~1 2>err &&\n \tgit replace -f HEAD^ $BLOB 2>err\n '\n \n-- \n1.8.4.rc1.31.g530f5ce.dirty\n"},{"id":"226449","messageId":"7D7C5D53BA544AAD92B05DF9635926C8@PhilipOakley","threadId":"34818","inReplyTo":"20130831191215.26699.18957.chriscool@tuxfamily.org","subject":"Re: [PATCH v3 01/11] replace: forbid replacing an object with one of a different type","fromName":"Philip Oakley","fromEmail":"philipoakley@iee.org","sentAt":"2013-08-31T22:11:26Z","receivedAt":"2013-08-31T22:11:26Z","isPatch":true,"sender":{"key":"philipoakley@iee.email","avatar":"https://avatars.githubusercontent.com/u/914343?v=4"},"body":"Sorry for not replying earlier in the series.\n\nFrom: \"Christian Couder\" <chriscool@tuxfamily.org>\n> Users replacing an object with one of a different type were not\n> prevented to do so, even if it was obvious, and stated in the doc,\n> that bad things would result from doing that.\n>\n> To avoid mistakes, it is better to just forbid that though.\n>\n> If one object is replaced with one of a different type, the only way\n> to keep the history valid is to also replace all the other objects\n> that point to the replaced object.\n\nIsn't this a recursion problem? Taken in that order one unravels the \nwhole DAG.\n\nHowever if considered in the reverse direction, one can replace an \nexisting object within the DAG with a carefully crafted alternative of \nthe same type, but which then wrongly references other dangling objects \nwhich are then replaced by objects which have the right type (this last \nreplacement requires -f force).\n\n> That's because:\n>\n> * Annotated tags contain the type of the tagged object.\n>\n> * The tree/parent lines in commits must be a tree and commits, resp.\n>\n> * The object types referred to by trees are specified in the 'mode'\n>  field:\n>    100644 and 100755    blob\n>    160000               commit\n>    040000               tree\n>  (these are the only valid modes)\n>\n> * Blobs don't point at anything.\n>\n> The doc will be updated in a later patch.\n>\n> Acked-by: Philip Oakley <philipoakley@iee.org>\n> Signed-off-by: Christian Couder <chriscool@tuxfamily.org>\n> ---\n> builtin/replace.c | 10 ++++++++++\n> 1 file changed, 10 insertions(+)\n>\n> diff --git a/builtin/replace.c b/builtin/replace.c\n> index 59d3115..9a94769 100644\n> --- a/builtin/replace.c\n> +++ b/builtin/replace.c\n> @@ -85,6 +85,7 @@ static int replace_object(const char *object_ref, \n> const char *replace_ref,\n>    int force)\n> {\n>  unsigned char object[20], prev[20], repl[20];\n> + enum object_type obj_type, repl_type;\n>  char ref[PATH_MAX];\n>  struct ref_lock *lock;\n>\n> @@ -100,6 +101,15 @@ static int replace_object(const char *object_ref, \n> const char *replace_ref,\n>  if (check_refname_format(ref, 0))\n>  die(\"'%s' is not a valid ref name.\", ref);\n>\n> + obj_type = sha1_object_info(object, NULL);\n> + repl_type = sha1_object_info(repl, NULL);\n> + if (obj_type != repl_type)\n> + die(\"Objects must be of the same type.\\n\"\n> +     \"'%s' points to a replaced object of type '%s'\\n\"\n> +     \"while '%s' points to a replacement object of type '%s'.\",\n> +     object_ref, typename(obj_type),\n> +     replace_ref, typename(repl_type));\n> +\n>  if (read_ref(ref, prev))\n>  hashclr(prev);\n>  else if (!force)\n> -- \n> 1.8.4.rc1.31.g530f5ce.dirty\n>\n>\n> \n"},{"id":"226450","messageId":"70F5C527E29F43A9BE85694F560E01A9@PhilipOakley","threadId":"34818","inReplyTo":"20130831191215.26699.720.chriscool@tuxfamily.org","subject":"Re: [PATCH v3 07/11] Documentation/replace: tell that -f option bypasses the type check","fromName":"Philip Oakley","fromEmail":"philipoakley@iee.org","sentAt":"2013-08-31T22:16:40Z","receivedAt":"2013-08-31T22:16:40Z","isPatch":true,"sender":{"key":"philipoakley@iee.email","avatar":"https://avatars.githubusercontent.com/u/914343?v=4"},"body":"From: \"Christian Couder\" <chriscool@tuxfamily.org>\n> Signed-off-by: Christian Couder <chriscool@tuxfamily.org>\n> ---\n> Documentation/git-replace.txt | 4 +++-\n> 1 file changed, 3 insertions(+), 1 deletion(-)\n>\n> diff --git a/Documentation/git-replace.txt \n> b/Documentation/git-replace.txt\n> index 736b48c..a2bd2ee 100644\n> --- a/Documentation/git-replace.txt\n> +++ b/Documentation/git-replace.txt\n> @@ -21,10 +21,12 @@ replaced. The content of the 'replace' reference \n> is the SHA-1 of the\n> replacement object.\n>\n> The replaced object and the replacement object must be of the same \n> type.\n> -There is no other restriction on them.\n> +This restriction can be bypassed using `-f`.\n>\n> Unless `-f` is given, the 'replace' reference must not yet exist.\n>\n> +There is no other restriction on the replaced and replacement \n> objects.\n\nIs this trying to allude to the fact that merge commits may be exchanged \nwith non-merge commits? I strongly believe that this ability to exchange \nmerge and non-merge commits should be stated _explicitly_ to counteract \nthe false beliefs that are listed out on the internet.\n\nIt's probably better stated in a separate patch for that explicit \npurpose to avoid mixed messages within this commit.\n\n> +\n> Replacement references will be used by default by all Git commands\n> except those doing reachability traversal (prune, pack transfer and\n> fsck).\n> -- \n"},{"id":"226451","messageId":"23F4E42FEAEB41DCA9B6F18EED5DD4D0@PhilipOakley","threadId":"34818","inReplyTo":"20130831191215.26699.37641.chriscool@tuxfamily.org","subject":"Re: [PATCH v3 05/11] Documentation/replace: add Creating Replacement Objects section","fromName":"Philip Oakley","fromEmail":"philipoakley@iee.org","sentAt":"2013-08-31T22:19:48Z","receivedAt":"2013-08-31T22:19:48Z","isPatch":true,"sender":{"key":"philipoakley@iee.email","avatar":"https://avatars.githubusercontent.com/u/914343?v=4"},"body":"From: \"Christian Couder\" <chriscool@tuxfamily.org>\n> There were no hints in the documentation about how to create\n> replacement objects.\n>\n> Signed-off-by: Christian Couder <chriscool@tuxfamily.org>\n> ---\n> Documentation/git-replace.txt | 16 ++++++++++++++++\n> 1 file changed, 16 insertions(+)\n>\n> diff --git a/Documentation/git-replace.txt \n> b/Documentation/git-replace.txt\n> index aa66d27..736b48c 100644\n> --- a/Documentation/git-replace.txt\n> +++ b/Documentation/git-replace.txt\n> @@ -64,6 +64,19 @@ OPTIONS\n>  Typing \"git replace\" without arguments, also lists all replace\n>  refs.\n>\n> +CREATING REPLACEMENT OBJECTS\n> +----------------------------\n> +\n> +linkgit:git-filter-branch[1], linkgit:git-hash-object[1] and\n> +linkgit:git-rebase[1],\n\nLet's not forget the obvious 'git commit' or 'git merge' on a temporary \nbranch for creating a replacement commit.\n\nIn particular we need to have covered the alternate to a graft of \"A B \nC\" (i.e. A is now a merge of B & C) if we are to deprecate grafts with \nany conviction. (https://git.wiki.kernel.org/index.php/GraftPoint)\n\n> among other git commands, can be used to create\n> +replacement objects from existing objects.\n> +\n> +If you want to replace many blobs, trees or commits that are part of \n> a\n> +string of commits, you may just want to create a replacement string \n> of\n> +commits and then only replace the commit at the tip of the target\n> +string of commits with the commit at the tip of the replacement \n> string\n> +of commits.\n> +\n> BUGS\n> ----\n> Comparing blobs or trees that have been replaced with those that\n> @@ -76,6 +89,9 @@ pending objects.\n>\n> SEE ALSO\n> --------\n> +linkgit:git-hash-object[1]\n> +linkgit:git-filter-branch[1]\n> +linkgit:git-rebase[1]\n> linkgit:git-tag[1]\n> linkgit:git-branch[1]\n> linkgit:git[1]\n> -- \n> 1.8.4.rc1.31.g530f5ce.dirty\n>\n>\n> \n"},{"id":"226452","messageId":"B7EE9969D317426D9897AE75E7A84462@PhilipOakley","threadId":"34818","inReplyTo":"20130831191215.26699.76207.chriscool@tuxfamily.org","subject":"Re: [PATCH v3 11/11] t6050-replace: use some long option names","fromName":"Philip Oakley","fromEmail":"philipoakley@iee.org","sentAt":"2013-08-31T22:19:53Z","receivedAt":"2013-08-31T22:19:53Z","isPatch":true,"sender":{"key":"philipoakley@iee.email","avatar":"https://avatars.githubusercontent.com/u/914343?v=4"},"body":"From: \"Christian Couder\" <chriscool@tuxfamily.org>\nSubject: [PATCH v3 11/11] t6050-replace: use some long option names\n\n\n> So that they are tested a litlle bit too.\ns /litlle/little/\n\n>\n> Signed-off-by: Christian Couder <chriscool@tuxfamily.org>\n> ---\n> t/t6050-replace.sh | 8 ++++----\n> 1 file changed, 4 insertions(+), 4 deletions(-)\n>\n> diff --git a/t/t6050-replace.sh b/t/t6050-replace.sh\n> index 0b07a0b..5dc26e8 100755\n> --- a/t/t6050-replace.sh\n> +++ b/t/t6050-replace.sh\n> @@ -122,9 +122,9 @@ test_expect_success '\"git replace\" listing and \n> deleting' '\n>      test \"$HASH2\" = \"$(git replace -l)\" &&\n>      test \"$HASH2\" = \"$(git replace)\" &&\n>      aa=${HASH2%??????????????????????????????????????} &&\n> -     test \"$HASH2\" = \"$(git replace -l \"$aa*\")\" &&\n> +     test \"$HASH2\" = \"$(git replace --list \"$aa*\")\" &&\n>      test_must_fail git replace -d $R &&\n> -     test_must_fail git replace -d &&\n> +     test_must_fail git replace --delete &&\n>      test_must_fail git replace -l -d $HASH2 &&\n>      git replace -d $HASH2 &&\n>      git show $HASH2 | grep \"A U Thor\" &&\n> @@ -147,7 +147,7 @@ test_expect_success '\"git replace\" resolves sha1' \n> '\n>      git show $HASH2 | grep \"O Thor\" &&\n>      test_must_fail git replace $HASH2 $R &&\n>      git replace -f $HASH2 $R &&\n> -     test_must_fail git replace -f &&\n> +     test_must_fail git replace --force &&\n>      test \"$HASH2\" = \"$(git replace)\"\n> '\n>\n> @@ -278,7 +278,7 @@ test_expect_success 'replaced and replacement \n> objects must be of the same type'\n>\n> test_expect_success '-f option bypasses the type check' '\n>  git replace -f mytag $HASH1 2>err &&\n> - git replace -f HEAD^{tree} HEAD~1 2>err &&\n> + git replace --force HEAD^{tree} HEAD~1 2>err &&\n>  git replace -f HEAD^ $BLOB 2>err\n> '\n>\n> -- \n> 1.8.4.rc1.31.g530f5ce.dirty\n>\n> \n"},{"id":"226468","messageId":"CAPig+cTSTk7f+EwwwMZpNU5QsiU3_Nu92aQz1AsZ2bSGzEgcTg@mail.gmail.com","threadId":"34818","inReplyTo":"20130831191215.26699.37671.chriscool@tuxfamily.org","subject":"Re: [PATCH v3 08/11] t6050-replace: check that -f option bypasses the type check","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2013-09-01T07:50:44Z","receivedAt":"2013-09-01T07:50:44Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sat, Aug 31, 2013 at 3:12 PM, Christian Couder\n<chriscool@tuxfamily.org> wrote:\n> Signed-off-by: Christian Couder <chriscool@tuxfamily.org>\n> ---\n>  t/t6050-replace.sh | 6 ++++++\n>  1 file changed, 6 insertions(+)\n>\n> diff --git a/t/t6050-replace.sh b/t/t6050-replace.sh\n> index 05be228..0b07a0b 100755\n> --- a/t/t6050-replace.sh\n> +++ b/t/t6050-replace.sh\n> @@ -276,6 +276,12 @@ test_expect_success 'replaced and replacement objects must be of the same type'\n>         grep \"$BLOB. points to a replacement object of type .blob\" err\n>  '\n>\n> +test_expect_success '-f option bypasses the type check' '\n> +       git replace -f mytag $HASH1 2>err &&\n> +       git replace -f HEAD^{tree} HEAD~1 2>err &&\n> +       git replace -f HEAD^ $BLOB 2>err\n> +'\n\nIs there a non-obvious reason you are redirecting stderr to a file in\nthis test? Unlike the test added earlier, this one never consults the\nerror output. By dropping this apparently unnecessary redirection,\ndiagnosis of a regression potentially becomes simpler since any error\noutput from git-replace will become visible when the test is run\nverbosely.\n\n> +\n>  test_expect_success 'replace ref cleanup' '\n>         test -n \"$(git replace)\" &&\n>         git replace -d $(git replace) &&\n> --\n> 1.8.4.rc1.31.g530f5ce.dirty\n"},{"id":"226469","messageId":"CAPig+cSwQdhybTzRwqGLbdxGRcAZfBeU6jjWYy43G0oT0hxkNw@mail.gmail.com","threadId":"34818","inReplyTo":"20130831191215.26699.76207.chriscool@tuxfamily.org","subject":"Re: [PATCH v3 11/11] t6050-replace: use some long option names","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2013-09-01T08:07:46Z","receivedAt":"2013-09-01T08:07:46Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sat, Aug 31, 2013 at 3:12 PM, Christian Couder\n<chriscool@tuxfamily.org> wrote:\n> So that they are tested a litlle bit too.\n>\n> Signed-off-by: Christian Couder <chriscool@tuxfamily.org>\n> ---\n>  t/t6050-replace.sh | 8 ++++----\n>  1 file changed, 4 insertions(+), 4 deletions(-)\n>\n> diff --git a/t/t6050-replace.sh b/t/t6050-replace.sh\n> index 0b07a0b..5dc26e8 100755\n> --- a/t/t6050-replace.sh\n> +++ b/t/t6050-replace.sh\n> @@ -122,9 +122,9 @@ test_expect_success '\"git replace\" listing and deleting' '\n>       test \"$HASH2\" = \"$(git replace -l)\" &&\n>       test \"$HASH2\" = \"$(git replace)\" &&\n>       aa=${HASH2%??????????????????????????????????????} &&\n> -     test \"$HASH2\" = \"$(git replace -l \"$aa*\")\" &&\n> +     test \"$HASH2\" = \"$(git replace --list \"$aa*\")\" &&\n>       test_must_fail git replace -d $R &&\n> -     test_must_fail git replace -d &&\n> +     test_must_fail git replace --delete &&\n>       test_must_fail git replace -l -d $HASH2 &&\n\nIs this sort of change a good idea? A person reading the code, but not\nfamiliar with this particular patch, might not understand the\nseemingly random choice of short versus long option usage. Such a\nperson might be led to wonder if there is some subtle difference\nbetween the short and long forms, and then unnecessarily spend time\ndigging into the code and documentation in an attempt to figure it\nout. Alternately, someone reading the code might be led to assume that\nthe person who added the tests was being sloppy.\n\nHopefully, t0040-parse-options should already be proof enough that\nlong options are correctly handled, but if you really want to test\nthem here too, it seems like a separate test would be more appropriate\nthan randomly changing short form options to long in various tests.\n\n>       git replace -d $HASH2 &&\n>       git show $HASH2 | grep \"A U Thor\" &&\n> @@ -147,7 +147,7 @@ test_expect_success '\"git replace\" resolves sha1' '\n>       git show $HASH2 | grep \"O Thor\" &&\n>       test_must_fail git replace $HASH2 $R &&\n>       git replace -f $HASH2 $R &&\n> -     test_must_fail git replace -f &&\n> +     test_must_fail git replace --force &&\n>       test \"$HASH2\" = \"$(git replace)\"\n>  '\n>\n> @@ -278,7 +278,7 @@ test_expect_success 'replaced and replacement objects must be of the same type'\n>\n>  test_expect_success '-f option bypasses the type check' '\n>         git replace -f mytag $HASH1 2>err &&\n> -       git replace -f HEAD^{tree} HEAD~1 2>err &&\n> +       git replace --force HEAD^{tree} HEAD~1 2>err &&\n>         git replace -f HEAD^ $BLOB 2>err\n>  '\n>\n> --\n> 1.8.4.rc1.31.g530f5ce.dirty\n"},{"id":"226478","messageId":"20130901.120132.1611298105222242724.chriscool@tuxfamily.org","threadId":"34818","inReplyTo":"CAPig+cSwQdhybTzRwqGLbdxGRcAZfBeU6jjWYy43G0oT0hxkNw@mail.gmail.com","subject":"Re: [PATCH v3 11/11] t6050-replace: use some long option names","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2013-09-01T10:01:32Z","receivedAt":"2013-09-01T10:01:32Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"From: Eric Sunshine <sunshine@sunshineco.com>\n>\n>> diff --git a/t/t6050-replace.sh b/t/t6050-replace.sh\n>> index 0b07a0b..5dc26e8 100755\n>> --- a/t/t6050-replace.sh\n>> +++ b/t/t6050-replace.sh\n>> @@ -122,9 +122,9 @@ test_expect_success '\"git replace\" listing and deleting' '\n>>       test \"$HASH2\" = \"$(git replace -l)\" &&\n>>       test \"$HASH2\" = \"$(git replace)\" &&\n>>       aa=${HASH2%??????????????????????????????????????} &&\n>> -     test \"$HASH2\" = \"$(git replace -l \"$aa*\")\" &&\n>> +     test \"$HASH2\" = \"$(git replace --list \"$aa*\")\" &&\n>>       test_must_fail git replace -d $R &&\n>> -     test_must_fail git replace -d &&\n>> +     test_must_fail git replace --delete &&\n>>       test_must_fail git replace -l -d $HASH2 &&\n> \n> Is this sort of change a good idea? A person reading the code, but not\n> familiar with this particular patch, might not understand the\n> seemingly random choice of short versus long option usage. Such a\n> person might be led to wonder if there is some subtle difference\n> between the short and long forms,\n\nI don't think that we should care about people who might wonder if\nthere are subtle differences between short and long forms, because of\nsuch tests.\n\nThe doc says that there is no difference, and there is also no\ndifference in other git commands, and git replace is an advanced\ncommand, and very few regular users probably read tests, ...\n\n> and then unnecessarily spend time\n> digging into the code and documentation in an attempt to figure it\n> out. Alternately, someone reading the code might be led to assume that\n> the person who added the tests was being sloppy.\n\nWhy not just assume that the person who added the tests is so great as\nto even take care of testing the long options names?\n\n> Hopefully, t0040-parse-options should already be proof enough that\n> long options are correctly handled, \n\nYeah, indeed!\n\n> but if you really want to test\n> them here too, it seems like a separate test would be more appropriate\n> than randomly changing short form options to long in various tests.\n\nIntroducing some randomness in tests also has some value, you\nknow. And at the same time it doesn't even slow down the test suite\nwhile adding separate tests would slow it down, and make readers spend\nmore time reading the whole test suite, and would be a bigger burden\nfor git developers to maintain for no good reason.\n\nBest,\nChristian.\n"},{"id":"226479","messageId":"20130901.120228.1211524158553068971.chriscool@tuxfamily.org","threadId":"34818","inReplyTo":"CAPig+cTSTk7f+EwwwMZpNU5QsiU3_Nu92aQz1AsZ2bSGzEgcTg@mail.gmail.com","subject":"Re: [PATCH v3 08/11] t6050-replace: check that -f option bypasses the type check","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2013-09-01T10:02:28Z","receivedAt":"2013-09-01T10:02:28Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"From: Eric Sunshine <sunshine@sunshineco.com>\n>\n> On Sat, Aug 31, 2013 at 3:12 PM, Christian Couder\n> <chriscool@tuxfamily.org> wrote:\n>> Signed-off-by: Christian Couder <chriscool@tuxfamily.org>\n>> ---\n>>  t/t6050-replace.sh | 6 ++++++\n>>  1 file changed, 6 insertions(+)\n>>\n>> diff --git a/t/t6050-replace.sh b/t/t6050-replace.sh\n>> index 05be228..0b07a0b 100755\n>> --- a/t/t6050-replace.sh\n>> +++ b/t/t6050-replace.sh\n>> @@ -276,6 +276,12 @@ test_expect_success 'replaced and replacement objects must be of the same type'\n>>         grep \"$BLOB. points to a replacement object of type .blob\" err\n>>  '\n>>\n>> +test_expect_success '-f option bypasses the type check' '\n>> +       git replace -f mytag $HASH1 2>err &&\n>> +       git replace -f HEAD^{tree} HEAD~1 2>err &&\n>> +       git replace -f HEAD^ $BLOB 2>err\n>> +'\n> \n> Is there a non-obvious reason you are redirecting stderr to a file in\n> this test? Unlike the test added earlier, this one never consults the\n> error output. By dropping this apparently unnecessary redirection,\n> diagnosis of a regression potentially becomes simpler since any error\n> output from git-replace will become visible when the test is run\n> verbosely.\n\nYou are right! I will drop these redirections.\n\nThanks,\nChristian.\n"},{"id":"226480","messageId":"20130901.121122.931701013873281627.chriscool@tuxfamily.org","threadId":"34818","inReplyTo":"B7EE9969D317426D9897AE75E7A84462@PhilipOakley","subject":"Re: [PATCH v3 11/11] t6050-replace: use some long option names","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2013-09-01T10:11:22Z","receivedAt":"2013-09-01T10:11:22Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"From: \"Philip Oakley\" <philipoakley@iee.org>\n>\n>> So that they are tested a litlle bit too.\n> s /litlle/little/\n\nThanks,\nChristian.\n"},{"id":"226481","messageId":"20130901.122716.141236934846069455.chriscool@tuxfamily.org","threadId":"34818","inReplyTo":"23F4E42FEAEB41DCA9B6F18EED5DD4D0@PhilipOakley","subject":"Re: [PATCH v3 05/11] Documentation/replace: add Creating Replacement Objects section","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2013-09-01T10:27:16Z","receivedAt":"2013-09-01T10:27:16Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"From: \"Philip Oakley\" <philipoakley@iee.org>\n>\n> From: \"Christian Couder\" <chriscool@tuxfamily.org>\n>\n>> +CREATING REPLACEMENT OBJECTS\n>> +----------------------------\n>> +\n>> +linkgit:git-filter-branch[1], linkgit:git-hash-object[1] and\n>> +linkgit:git-rebase[1],\n> \n> Let's not forget the obvious 'git commit' or 'git merge' on a\n> temporary branch for creating a replacement commit.\n\nAs it is obvious, and as it is somehow addressed in the below part of\nthis section, I don't think it is worth talking about git commit or\ngit merge or git cherry-pick or any other command.\n \n> In particular we need to have covered the alternate to a graft of \"A B\n> C\" (i.e. A is now a merge of B & C) if we are to deprecate grafts with\n> any conviction. (https://git.wiki.kernel.org/index.php/GraftPoint)\n\nAdding such an example in a new EXAMPLE section would address this\nbetter. If people agree I will do it in a following patch.\n\n>> among other git commands, can be used to create\n>> +replacement objects from existing objects.\n>> +\n>> +If you want to replace many blobs, trees or commits that are part of\n>> a\n>> +string of commits, you may just want to create a replacement string\n>> of\n>> +commits and then only replace the commit at the tip of the target\n>> +string of commits with the commit at the tip of the replacement\n>> string\n>> +of commits.\n\nThanks,\nChristian.\n"},{"id":"226483","messageId":"20130901.134900.829124962244710553.chriscool@tuxfamily.org","threadId":"34818","inReplyTo":"70F5C527E29F43A9BE85694F560E01A9@PhilipOakley","subject":"Re: [PATCH v3 07/11] Documentation/replace: tell that -f option bypasses the type check","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2013-09-01T11:49:00Z","receivedAt":"2013-09-01T11:49:00Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"From: \"Philip Oakley\" <philipoakley@iee.org>\n>\n> From: \"Christian Couder\" <chriscool@tuxfamily.org>\n>>\n>> The replaced object and the replacement object must be of the same\n>> type.\n>> -There is no other restriction on them.\n>> +This restriction can be bypassed using `-f`.\n>>\n>> Unless `-f` is given, the 'replace' reference must not yet exist.\n>>\n>> +There is no other restriction on the replaced and replacement\n>> objects.\n> \n> Is this trying to allude to the fact that merge commits may be\n> exchanged with non-merge commits? I strongly believe that this ability\n> to exchange merge and non-merge commits should be stated _explicitly_\n> to counteract the false beliefs that are listed out on the internet.\n\nMaybe we can show that in an example. But I think the patch is quite\nclear as it is and should be enough.\n\nIf we really want to correct some false beliefs, the best would be to\nstate the truth where those false beliefs are stated.\n\n> It's probably better stated in a separate patch for that explicit\n> purpose to avoid mixed messages within this commit.\n\nIf people agree, I will add a another patch with an example in an\nEXAMPLE section.\n\nThanks,\nChristian.\n"},{"id":"226484","messageId":"20130901.135321.1182162250658468787.chriscool@tuxfamily.org","threadId":"34818","inReplyTo":"7D7C5D53BA544AAD92B05DF9635926C8@PhilipOakley","subject":"Re: [PATCH v3 01/11] replace: forbid replacing an object with one of a different type","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2013-09-01T11:53:21Z","receivedAt":"2013-09-01T11:53:21Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"From: \"Philip Oakley\" <philipoakley@iee.org>\n>\n> Sorry for not replying earlier in the series.\n> \n> From: \"Christian Couder\" <chriscool@tuxfamily.org>\n>> Users replacing an object with one of a different type were not\n>> prevented to do so, even if it was obvious, and stated in the doc,\n>> that bad things would result from doing that.\n>>\n>> To avoid mistakes, it is better to just forbid that though.\n>>\n>> If one object is replaced with one of a different type, the only way\n>> to keep the history valid is to also replace all the other objects\n>> that point to the replaced object.\n> \n> Isn't this a recursion problem? Taken in that order one unravels the\n> whole DAG.\n> \n> However if considered in the reverse direction, one can replace an\n> existing object within the DAG with a carefully crafted alternative of\n> the same type, but which then wrongly references other dangling\n> objects which are then replaced by objects which have the right type\n> (this last replacement requires -f force).\n\nI am not sure I understand what you are saying.\n\nAnyway in a previous version of this patch I tried to be more explicit\nabout this, but Junio basically said that he found no value in\ndiscussing this more explicitely...\n\nThanks,\nChristian.\n"},{"id":"226487","messageId":"9D27EE89D9994C0997D19E0C0AF7493F@PhilipOakley","threadId":"34818","inReplyTo":"20130901.135321.1182162250658468787.chriscool@tuxfamily.org","subject":"Re: [PATCH v3 01/11] replace: forbid replacing an object with one of a different type","fromName":"Philip Oakley","fromEmail":"philipoakley@iee.org","sentAt":"2013-09-01T19:26:28Z","receivedAt":"2013-09-01T19:26:28Z","isPatch":true,"sender":{"key":"philipoakley@iee.email","avatar":"https://avatars.githubusercontent.com/u/914343?v=4"},"body":"From: \"Christian Couder\" <chriscool@tuxfamily.org>\n> From: \"Philip Oakley\" <philipoakley@iee.org>\n>>\n>> Sorry for not replying earlier in the series.\n>>\n>> From: \"Christian Couder\" <chriscool@tuxfamily.org>\n>>> Users replacing an object with one of a different type were not\n>>> prevented to do so, even if it was obvious, and stated in the doc,\n>>> that bad things would result from doing that.\n>>>\n>>> To avoid mistakes, it is better to just forbid that though.\n>>>\n>>> If one object is replaced with one of a different type, the only way\n>>> to keep the history valid is to also replace all the other objects\n>>> that point to the replaced object.\n>>\n>> Isn't this a recursion problem? Taken in that order one unravels the\n>> whole DAG.\n>>\n>> However if considered in the reverse direction, one can replace an\n>> existing object within the DAG with a carefully crafted alternative \n>> of\n>> the same type, but which then wrongly references other dangling\n>> objects which are then replaced by objects which have the right type\n>> (this last replacement requires -f force).\n>\n> I am not sure I understand what you are saying.\n>\n> Anyway in a previous version of this patch I tried to be more explicit\n> about this, but Junio basically said that he found no value in\n> discussing this more explicitely...\n\nI would agree that it's not worth discussing it more explicitly.\n\nMy comment was more about the direction of the line of reasoning which I \nfelt was a bit Catch 22 when starting from an existing complete DAG (no \ngarbage) and attempting to replace an object with another of a different \ntype and still have a valid DAG.  The construction of the replacement \nitems needs to be in the right order if one of the replacements is of \nthe 'wrong' type (such a construction requires the creation or uses, and \nultimately replacement of, extraneous objects that aren't (yet) in the \nDAG).\n\nBut as already been said that's a problem for the user of the --force \noption ;-)\n\nPhilip\n\n>\n> Thanks,\n> Christian.\n> \n"},{"id":"226491","messageId":"29D8721CD44F4C3180D6F1BA5CDCF38E@PhilipOakley","threadId":"34818","inReplyTo":"20130901.134900.829124962244710553.chriscool@tuxfamily.org","subject":"Re: [PATCH v3 07/11] Documentation/replace: tell that -f option bypasses the type check","fromName":"Philip Oakley","fromEmail":"philipoakley@iee.org","sentAt":"2013-09-01T20:11:24Z","receivedAt":"2013-09-01T20:11:24Z","isPatch":true,"sender":{"key":"philipoakley@iee.email","avatar":"https://avatars.githubusercontent.com/u/914343?v=4"},"body":"From: \"Christian Couder\" <chriscool@tuxfamily.org>\n> From: \"Philip Oakley\" <philipoakley@iee.org>\n>>\n>> From: \"Christian Couder\" <chriscool@tuxfamily.org>\n>>>\n>>> The replaced object and the replacement object must be of the same\n>>> type.\n>>> -There is no other restriction on them.\n>>> +This restriction can be bypassed using `-f`.\n>>>\n>>> Unless `-f` is given, the 'replace' reference must not yet exist.\n>>>\n>>> +There is no other restriction on the replaced and replacement\n>>> objects.\n>>\n>> Is this trying to allude to the fact that merge commits may be\n>> exchanged with non-merge commits? I strongly believe that this\n>> ability\n>> to exchange merge and non-merge commits should be stated _explicitly_\n>> to counteract the false beliefs that are listed out on the internet.\n>\n> Maybe we can show that in an example. But I think the patch is quite\n> clear as it is and should be enough.\n>\n> If we really want to correct some false beliefs, the best would be to\n> state the truth where those false beliefs are stated.\n>\nI've added a sub-comment to the original SO post that started this\nthread (my post $gmane/231598 - SO/a/18027030/717355), but given the\nguy's blog has comments going back to 2009 I suspect its a bit of a\nhttp://xkcd.com/386/ task, hence my desire that it's explicitly\nmentioned in the 'replace' documentation. In addition, if the guy \ndoesn't correct his post I'll mark it down in a couple of days to make \nit plain to other readers it's in error.\n\nThe creation of a (merge?) commit that's equivalent to a graft line\nisn't something that jumps out (to me) as an easy couple lines of bash\nscript.\n\nA 'graft2replace' script (or 'git-graft' command) which takes an\nexisting graft file (or command line list) and creates the replacement \nobjects and then does the replace, all while still in a dirty tree would \nbe the holy grail for properly deprecating grafts (which are sooo easy \nto create)\n\n>> It's probably better stated in a separate patch for that explicit\n>> purpose to avoid mixed messages within this commit.\n>\n> If people agree, I will add a another patch with an example in an\n> EXAMPLE section.\n>\n> Thanks,\n> Christian.\n>\n>\nThanks for your work on this.\nPhilip \n"},{"id":"226498","messageId":"20130902.081157.986549849748779440.chriscool@tuxfamily.org","threadId":"34818","inReplyTo":"29D8721CD44F4C3180D6F1BA5CDCF38E@PhilipOakley","subject":"Re: [PATCH v3 07/11] Documentation/replace: tell that -f option bypasses the type check","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2013-09-02T06:11:57Z","receivedAt":"2013-09-02T06:11:57Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"From: \"Philip Oakley\" <philipoakley@iee.org>\n>\n> From: \"Christian Couder\" <chriscool@tuxfamily.org>\n>\n>> Maybe we can show that in an example. But I think the patch is quite\n>> clear as it is and should be enough.\n>>\n>> If we really want to correct some false beliefs, the best would be to\n>> state the truth where those false beliefs are stated.\n>>\n> I've added a sub-comment to the original SO post that started this\n> thread (my post $gmane/231598 - SO/a/18027030/717355), but given the\n> guy's blog has comments going back to 2009 I suspect its a bit of a\n> http://xkcd.com/386/ task, hence my desire that it's explicitly\n> mentioned in the 'replace' documentation. In addition, if the guy\n> doesn't correct his post I'll mark it down in a couple of days to make\n> it plain to other readers it's in error.\n> \n> The creation of a (merge?) commit that's equivalent to a graft line\n> isn't something that jumps out (to me) as an easy couple lines of bash\n> script.\n>\n> A 'graft2replace' script (or 'git-graft' command) which takes an\n> existing graft file (or command line list) and creates the replacement\n> objects and then does the replace, all while still in a dirty tree\n> would be the holy grail for properly deprecating grafts (which are\n> sooo easy to create)\n\nYou mean something like the following:\n\n$ cat  ./graft2replace.sh \n#!/bin/bash\n\nwhile read orig parents\ndo\n        printf \"%s\" \"git cat-file commit $orig\"\n        printf \"%s\" \" | perl -n -e 'print unless /^parent /'\"\n        insn=''\n        for commit in $parents; do insn=\"$insn print \\\"parent $commit\\\\n\\\";\"; done\n        printf \"%s\" \" | perl -n -e 'print; if (/^tree /) { $insn }'\"\n        printf \"%s\\n\" \" > new_commit.txt\"\n        printf \"%s\\n\" 'REPL=$(git hash-object -t commit -w new_commit.txt)'\n        printf \"%s\\n\" \"git replace $orig \\$REPL\"\ndone\n\nThis generates shell instructions from a graft file. Then you only need to execute the generated shell instructions.\nFor example:\n\n$ cat graft_file.txt \n5bf34fff3186254d7254583675d10ddf98df989b 79fe155489351e8af829a3106e7150397c57d863 dcfbab6bea3df3166503f3084cec2679f10f9e80\nfb5657082148297b61fbca7e64d51c1e7870309a\n\n$ cat graft_file.txt | ./graft2replace.sh \ngit cat-file commit 5bf34fff3186254d7254583675d10ddf98df989b | perl -n -e 'print unless /^parent /' | perl -n -e 'print; if (/^tree /) {  print \"parent 79fe155489351e8af829a3106e7150397c57d863\\n\"; print \"parent dcfbab6bea3df3166503f3084cec2679f10f9e80\\n\"; }' > new_commit.txt\nREPL=$(git hash-object -t commit -w new_commit.txt)\ngit replace 5bf34fff3186254d7254583675d10ddf98df989b $REPL\ngit cat-file commit fb5657082148297b61fbca7e64d51c1e7870309a | perl -n -e 'print unless /^parent /' | perl -n -e 'print; if (/^tree /) {  }' > new_commit.txt\nREPL=$(git hash-object -t commit -w new_commit.txt)\ngit replace fb5657082148297b61fbca7e64d51c1e7870309a $REPL\n\nNote that I haven't really tested it.\n\nBest,\nChristian.\n"},{"id":"226557","messageId":"66A16BF0137D40568A34C316DDA6D32E@PhilipOakley","threadId":"34818","inReplyTo":"20130902.081157.986549849748779440.chriscool@tuxfamily.org","subject":"Re: [PATCH v3 07/11] Documentation/replace: tell that -f option bypasses the type check","fromName":"Philip Oakley","fromEmail":"philipoakley@iee.org","sentAt":"2013-09-02T21:50:06Z","receivedAt":"2013-09-02T21:50:06Z","isPatch":true,"sender":{"key":"philipoakley@iee.email","avatar":"https://avatars.githubusercontent.com/u/914343?v=4"},"body":"From: \"Christian Couder\" <chriscool@tuxfamily.org>\n> From: \"Philip Oakley\" <philipoakley@iee.org>\n>>\n>> From: \"Christian Couder\" <chriscool@tuxfamily.org>\n>>\n>>> Maybe we can show that in an example. But I think the patch is quite\n>>> clear as it is and should be enough.\n>>>\n>>> If we really want to correct some false beliefs, the best would be \n>>> to\n>>> state the truth where those false beliefs are stated.\n>>>\n>> I've added a sub-comment to the original SO post that started this\n>> thread (my post $gmane/231598 - SO/a/18027030/717355), but given the\n>> guy's blog has comments going back to 2009 I suspect its a bit of a\n>> http://xkcd.com/386/ task, hence my desire that it's explicitly\n>> mentioned in the 'replace' documentation. In addition, if the guy\n>> doesn't correct his post I'll mark it down in a couple of days to \n>> make\n>> it plain to other readers it's in error.\n>>\n>> The creation of a (merge?) commit that's equivalent to a graft line\n>> isn't something that jumps out (to me) as an easy couple lines of \n>> bash\n>> script.\n>>\n>> A 'graft2replace' script (or 'git-graft' command) which takes an\n>> existing graft file (or command line list) and creates the \n>> replacement\n>> objects and then does the replace, all while still in a dirty tree\n>> would be the holy grail for properly deprecating grafts (which are\n>> sooo easy to create)\n>\n> You mean something like the following:\n>\n> $ cat  ./graft2replace.sh\n> #!/bin/bash\n>\n> while read orig parents\n> do\n>        printf \"%s\" \"git cat-file commit $orig\"\n>        printf \"%s\" \" | perl -n -e 'print unless /^parent /'\"\n>        insn=''\n>        for commit in $parents; do insn=\"$insn print \\\"parent \n> $commit\\\\n\\\";\"; done\n>        printf \"%s\" \" | perl -n -e 'print; if (/^tree /) { $insn }'\"\n>        printf \"%s\\n\" \" > new_commit.txt\"\n>        printf \"%s\\n\" 'REPL=$(git hash-object -t commit -w \n> new_commit.txt)'\n\nDoes `hash-object` do the inverese of `cat-file commit`?\n\nI didn't find the hash-object(1) man page very informative on that \nmatter and a (very) quick look at its code made me think it was just \nhashing the raw contents which wouldn't be what what was wanted.\n\n>        printf \"%s\\n\" \"git replace $orig \\$REPL\"\n> done\n>\n> This generates shell instructions from a graft file. Then you only \n> need to execute the generated shell instructions.\n> For example:\n>\n> $ cat graft_file.txt\n> 5bf34fff3186254d7254583675d10ddf98df989b \n> 79fe155489351e8af829a3106e7150397c57d863 \n> dcfbab6bea3df3166503f3084cec2679f10f9e80\n> fb5657082148297b61fbca7e64d51c1e7870309a\n>\n> $ cat graft_file.txt | ./graft2replace.sh\n> git cat-file commit 5bf34fff3186254d7254583675d10ddf98df989b | \n> perl -n -e 'print unless /^parent /' | perl -n -e 'print; if (/^tree \n> /) {  print \"parent 79fe155489351e8af829a3106e7150397c57d863\\n\"; print \n> \"parent dcfbab6bea3df3166503f3084cec2679f10f9e80\\n\"; }' > \n> new_commit.txt\n> REPL=$(git hash-object -t commit -w new_commit.txt)\n> git replace 5bf34fff3186254d7254583675d10ddf98df989b $REPL\n> git cat-file commit fb5657082148297b61fbca7e64d51c1e7870309a | \n> perl -n -e 'print unless /^parent /' | perl -n -e 'print; if (/^tree \n> /) {  }' > new_commit.txt\n> REPL=$(git hash-object -t commit -w new_commit.txt)\n> git replace fb5657082148297b61fbca7e64d51c1e7870309a $REPL\n>\n> Note that I haven't really tested it.\n>\n> Best,\n> Christian.\n> --\n\nI think we could call it 'git-graft', being the help function/script \nthat converts raw grafts to proper object replacements ;-)\n\nPhilip \n"},{"id":"226558","messageId":"20130902215545.GA2668@elie.Belkin","threadId":"34818","inReplyTo":"66A16BF0137D40568A34C316DDA6D32E@PhilipOakley","subject":"Re: [PATCH v3 07/11] Documentation/replace: tell that -f option bypasses the type check","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2013-09-02T21:55:45Z","receivedAt":"2013-09-02T21:55:45Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi,\n\nPhilip Oakley wrote:\n\n> Does `hash-object` do the inverese of `cat-file commit`?\n>\n> I didn't find the hash-object(1) man page very informative on that matter\n\nHm.  The manpage says:\n\n\tComputes the object ID value for an object with specified type\n\twith the contents of the named file [...], and optionally writes\n\tthe resulting object into the object database.\n\nAnd then:\n\n\t-w\n\t\tActually write the object into the object database.\n\nAny ideas for making this clearer?\n\nThanks,\nJonathan\n"},{"id":"226559","messageId":"857C171CD0E84268B296C9F3FCDFB277@PhilipOakley","threadId":"34818","inReplyTo":"20130902215545.GA2668@elie.Belkin","subject":"Re: [PATCH v3 07/11] Documentation/replace: tell that -f option bypasses the type check","fromName":"Philip Oakley","fromEmail":"philipoakley@iee.org","sentAt":"2013-09-02T22:13:49Z","receivedAt":"2013-09-02T22:13:49Z","isPatch":true,"sender":{"key":"philipoakley@iee.email","avatar":"https://avatars.githubusercontent.com/u/914343?v=4"},"body":"From: \"Jonathan Nieder\" <jrnieder@gmail.com>\n> Hi,\n>\n> Philip Oakley wrote:\n>\n>> Does `hash-object` do the inverese of `cat-file commit`?\n>>\n>> I didn't find the hash-object(1) man page very informative on that \n>> matter\n>\n> Hm.  The manpage says:\n>\n> Computes the object ID value for an object with specified type\n> with the contents of the named file [...], and optionally writes\n> the resulting object into the object database.\n>\n> And then:\n>\n> -w\n> Actually write the object into the object database.\n>\n> Any ideas for making this clearer?\n\nThe problem is the file format, in the sense that the earlier `git \ncat-file commit $orig` has a human readable output which is a \ndescription of the commit header, rather than the specific binary \ncontent. I couldn't tell if the command would cope with such a human \nreadable file.\n\nIn Christian's quick untested script he'd matched the two commands as \nopposites, which doesn't appear to be the case, and I'm somewhat \nignorant of what hash-object is doing - I'd expect that it simply hashed \nthe already constructed data, but my ignorance starts showing at this \npoint ;-)\n\nregards\n\nPhilip \n"},{"id":"226568","messageId":"20130902222625.GB2668@elie.Belkin","threadId":"34818","inReplyTo":"857C171CD0E84268B296C9F3FCDFB277@PhilipOakley","subject":"Re: [PATCH v3 07/11] Documentation/replace: tell that -f option bypasses the type check","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2013-09-02T22:26:25Z","receivedAt":"2013-09-02T22:26:25Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Philip Oakley wrote:\n\n> The problem is the file format, in the sense that the earlier `git cat-file\n> commit $orig` has a human readable output which is a description of the\n> commit header, rather than the specific binary content.\n\nAh.  That's the actual \"raw\" commit object format, though.\n\nThe manpage for git-cat-file(1) says:\n\n\tSYNOPSIS\n\t\tgit cat-file (-t | -s | -e | -p | <type> | --textconv ) <object>\n\t\tgit cat-file (--batch | --batch-check) < <list-of-objects>\n\n\tDESCRIPTION\n\t\tIn its first form, the command provides the content or the\n\t\ttype of an object in the repository. [...]\n\n\tOUTPUT\n\t\t...\n\t\tIf <type> is specified, the raw (though uncompressed)\n\t\tcontents of the <object> will be returned.\n\nI agree that this isn't as clear as it should be.  I see a few problems:\n\n (1) The synopsis treats \"git cat-file -t/-s/-e/-p <object>\",\n     \"git cat-file --textconv <tree>:<path>\", and\n     \"git cat-file <type> <object>\" as the same form of the command.\n     It would be easier to explain these as three different forms.\n\n (2) There is no EXAMPLES section and no examples.\n\n (3) There is no pointer to the git object formats.  A pointer to a\n     new gitobject(5) manpage would presumably make everything clearer.\n\nhttps://www.kernel.org/pub/software/scm/git/docs/user-manual.html#examining-the-data\nmight be a good source of text to start from for solving (1), since\nit explains the command a little better.\n\nThanks,\nJonathan\n"},{"id":"226569","messageId":"733E4B5A574946859D178D425231C172@PhilipOakley","threadId":"34818","inReplyTo":"20130902222625.GB2668@elie.Belkin","subject":"Re: [PATCH v3 07/11] Documentation/replace: tell that -f option bypasses the type check","fromName":"Philip Oakley","fromEmail":"philipoakley@iee.org","sentAt":"2013-09-02T22:45:57Z","receivedAt":"2013-09-02T22:45:57Z","isPatch":true,"sender":{"key":"philipoakley@iee.email","avatar":"https://avatars.githubusercontent.com/u/914343?v=4"},"body":"From: \"Jonathan Nieder\" <jrnieder@gmail.com>\n> Philip Oakley wrote:\n>\n>> The problem is the file format, in the sense that the earlier `git \n>> cat-file\n>> commit $orig` has a human readable output which is a description of \n>> the\n>> commit header, rather than the specific binary content.\n>\n> Ah.  That's the actual \"raw\" commit object format, though.\n>\n\nAha.. Sudden realisation that the cat-file _is_ the 'raw' format and \nthat the sha1's etc are shown in ascii hex, rather than being in a \ncompact binary format (same for 'unix' dates etc.)\n\nSo the 'human readable' output is exactly the 'type_name' field followed \nby a single space (SP) followed by the sha1 in ascii hex (i.e. \ntree/parent), or appropriate data in the well defined format (for \nauthor/committer) SP 'email' SP date. etc.\n\nIt was the Human readable == Machine readable that I'd missed.\n\n> The manpage for git-cat-file(1) says:\n>\n> SYNOPSIS\n> git cat-file (-t | -s | -e | -p | <type> | --textconv ) <object>\n> git cat-file (--batch | --batch-check) < <list-of-objects>\n>\n> DESCRIPTION\n> In its first form, the command provides the content or the\n> type of an object in the repository. [...]\n>\n> OUTPUT\n> ...\n> If <type> is specified, the raw (though uncompressed)\n> contents of the <object> will be returned.\n>\n> I agree that this isn't as clear as it should be.  I see a few \n> problems:\n>\n> (1) The synopsis treats \"git cat-file -t/-s/-e/-p <object>\",\n>     \"git cat-file --textconv <tree>:<path>\", and\n>     \"git cat-file <type> <object>\" as the same form of the command.\n>     It would be easier to explain these as three different forms.\n>\n> (2) There is no EXAMPLES section and no examples.\n>\n> (3) There is no pointer to the git object formats.  A pointer to a\n>     new gitobject(5) manpage would presumably make everything clearer.\n>\n> https://www.kernel.org/pub/software/scm/git/docs/user-manual.html#examining-the-data\n> might be a good source of text to start from for solving (1), since\n> it explains the command a little better.\n\nA quick run of the example \"git cat-file commit HEAD\", seen in the \ncontext of your email helped me appreciate the situation.\n\n>\n> Thanks,\n> Jonathan\n>\n\nPhilip \n"},{"id":"226607","messageId":"CAP8UFD31dawrGEiukHYvfUFtDtqrK-OLMLdqFfdOBU=rDYuAcQ@mail.gmail.com","threadId":"34818","inReplyTo":"66A16BF0137D40568A34C316DDA6D32E@PhilipOakley","subject":"Re: [PATCH v3 07/11] Documentation/replace: tell that -f option bypasses the type check","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2013-09-03T09:29:39Z","receivedAt":"2013-09-03T09:29:39Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Mon, Sep 2, 2013 at 11:50 PM, Philip Oakley <philipoakley@iee.org> wrote:\n>\n> From: \"Christian Couder\" <chriscool@tuxfamily.org>\n>\n>> You mean something like the following:\n>>\n>> $ cat  ./graft2replace.sh\n>> #!/bin/bash\n>>\n>> while read orig parents\n>> do\n>>        printf \"%s\" \"git cat-file commit $orig\"\n>>        printf \"%s\" \" | perl -n -e 'print unless /^parent /'\"\n>>        insn=''\n>>        for commit in $parents; do insn=\"$insn print \\\"parent\n>> $commit\\\\n\\\";\"; done\n>>        printf \"%s\" \" | perl -n -e 'print; if (/^tree /) { $insn }'\"\n>>        printf \"%s\\n\" \" > new_commit.txt\"\n>>        printf \"%s\\n\" 'REPL=$(git hash-object -t commit -w new_commit.txt)'\n>\n>\n> Does `hash-object` do the inverese of `cat-file commit`?\n>\n> I didn't find the hash-object(1) man page very informative on that matter\n> and a (very) quick look at its code made me think it was just hashing the\n> raw contents which wouldn't be what what was wanted.\n\nI agree with Jonathan's suggest to add an EXAMPLE section in\nhash-object(1) manpage and maybe a new gitobject(5) manpage too.\n\nYou can also find a few examples of how git hash-object can be used in\nt/t6050-replace.sh:\n\nFor example:\n\n     R=$(git cat-file commit $HASH2 | sed -e \"s/A U/O/\" | git\nhash-object -t commit --stdin -w) &&\n     git cat-file commit $R | grep \"author O Thor\" &&\n     git update-ref refs/replace/$HASH2 $R\n\n>>        printf \"%s\\n\" \"git replace $orig \\$REPL\"\n>> done\n>>\n>> This generates shell instructions from a graft file. Then you only need to\n>> execute the generated shell instructions.\n>> For example:\n>>\n>> $ cat graft_file.txt\n>> 5bf34fff3186254d7254583675d10ddf98df989b\n>> 79fe155489351e8af829a3106e7150397c57d863\n>> dcfbab6bea3df3166503f3084cec2679f10f9e80\n>> fb5657082148297b61fbca7e64d51c1e7870309a\n>>\n>> $ cat graft_file.txt | ./graft2replace.sh\n>> git cat-file commit 5bf34fff3186254d7254583675d10ddf98df989b | perl -n -e\n>> 'print unless /^parent /' | perl -n -e 'print; if (/^tree /) {  print\n>> \"parent 79fe155489351e8af829a3106e7150397c57d863\\n\"; print \"parent\n>> dcfbab6bea3df3166503f3084cec2679f10f9e80\\n\"; }' > new_commit.txt\n>> REPL=$(git hash-object -t commit -w new_commit.txt)\n>> git replace 5bf34fff3186254d7254583675d10ddf98df989b $REPL\n>> git cat-file commit fb5657082148297b61fbca7e64d51c1e7870309a | perl -n -e\n>> 'print unless /^parent /' | perl -n -e 'print; if (/^tree /) {  }' >\n>> new_commit.txt\n>> REPL=$(git hash-object -t commit -w new_commit.txt)\n>> git replace fb5657082148297b61fbca7e64d51c1e7870309a $REPL\n>>\n>> Note that I haven't really tested it.\n\nAlso note that it is obviously broken if you have commits with a\ncommit message that has lines starting with 'parent ' or 'tree '.\n\n> I think we could call it 'git-graft', being the help function/script that\n> converts raw grafts to proper object replacements ;-)\n\nI will have a look at improving it, testing it and sending a patch to\nput it in contrib/.\n\nThanks,\nChristian.\n"}]}