{"thread":{"id":"17127","subject":"git-format-patch with -o ../ in subdir of working copy writes output in wrong place","startedAt":"2009-01-12T22:04:32Z","lastAt":"2009-01-13T09:24:58Z","messageCount":5,"participants":["Cesar Eduardo Barros","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"100179","messageId":"496BBE70.9060405@cesarb.net","threadId":"17127","inReplyTo":null,"subject":"git-format-patch with -o ../ in subdir of working copy writes output in wrong place","fromName":"Cesar Eduardo Barros","fromEmail":"cesarb@cesarb.net","sentAt":"2009-01-12T22:04:32Z","receivedAt":"2009-01-12T22:04:32Z","isPatch":false,"sender":{"key":"cesarb@cesarb.net","avatar":"https://avatars.githubusercontent.com/u/31324?v=4"},"body":"If you are in a subdirectory of your working copy (for instance, \nlinux-2.6/drivers/net) and use git-format-patch with -o to a sequence of \n../ (for instance, -o ../../../) to write to the working copy's parent \ndirectory, it instead interprets the directory passed to -o as relative \nto the root of the working copy, instead of the expected current directory.\n\nTestcase:\nmkdir a\ncd a\ngit init\nmkdir b\ntouch b/c\ngit add b/c\ngit commit -m 'test'\ncd b\necho 'test' > c\ngit commit -a -m 'test'\ngit format-patch -o ../ HEAD^..HEAD\n\nExpected result: put the patch within the \"a\" directory\nResult with v1.6.1: put the patch within the parent of the \"a\" directory\n\n(This testcase uses ../ instead of ../../ to avoid putting the patch \nfile in an unexpected place, like in your home directory, which is what \nwould happen in practice.)\n\n-- \nCesar Eduardo Barros\ncesarb@cesarb.net\ncesar.barros@gmail.com\n"},{"id":"100187","messageId":"7vab9wgmwe.fsf@gitster.siamese.dyndns.org","threadId":"17127","inReplyTo":"496BBE70.9060405@cesarb.net","subject":"[PATCH] Teach format-patch to handle output directory relative to cwd","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-01-12T22:49:53Z","receivedAt":"2009-01-12T22:49:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Without any explicit -o parameter, we correctly avoided putting the\nresulting patch output to the toplevel.  We should do the same when\nthe user gave a relative pathname to be consistent with this case and also\nwith how other commands handle relative pathnames.\n\nNoticed by Cesar Eduardo Barros.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\nCesar Eduardo Barros <cesarb@cesarb.net> writes:\n\n> If you are in a subdirectory of your working copy (for instance,\n> linux-2.6/drivers/net) and use git-format-patch with -o to a sequence\n> of ../ (for instance, -o ../../../) to write to the working copy's\n> parent directory, it instead interprets the directory passed to -o as\n> relative to the root of the working copy, instead of the expected\n> current directory.\n\n builtin-log.c           |   13 ++++++++++-\n t/t4014-format-patch.sh |   52 ++++++++++++++++++++++++++++++++++++++++++++++-\n 2 files changed, 62 insertions(+), 3 deletions(-)\n\ndiff --git c/builtin-log.c w/builtin-log.c\nindex 4a02ee9..3e404ae 100644\n--- c/builtin-log.c\n+++ w/builtin-log.c\n@@ -731,6 +731,15 @@ static const char *clean_message_id(const char *msg_id)\n \treturn xmemdupz(a, z - a);\n }\n \n+static const char *set_outdir(const char *prefix, const char *output_directory)\n+{\n+\tif (!output_directory)\n+\t\toutput_directory = \".\";\n+\tif (prefix)\n+\t\toutput_directory = xstrdup(prefix_filename(prefix, strlen(prefix), output_directory));\n+\treturn output_directory;\n+}\n+\n int cmd_format_patch(int argc, const char **argv, const char *prefix)\n {\n \tstruct commit *commit;\n@@ -908,8 +917,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \tif (!DIFF_OPT_TST(&rev.diffopt, TEXT) && !no_binary_diff)\n \t\tDIFF_OPT_SET(&rev.diffopt, BINARY);\n \n-\tif (!output_directory && !use_stdout)\n-\t\toutput_directory = prefix;\n+\tif (!use_stdout)\n+\t\toutput_directory = set_outdir(prefix, output_directory);\n \n \tif (output_directory) {\n \t\tif (use_stdout)\ndiff --git c/t/t4014-format-patch.sh w/t/t4014-format-patch.sh\nindex 9d99dc2..5a9a63d 100755\n--- c/t/t4014-format-patch.sh\n+++ w/t/t4014-format-patch.sh\n@@ -3,7 +3,7 @@\n # Copyright (c) 2006 Junio C Hamano\n #\n \n-test_description='Format-patch skipping already incorporated patches'\n+test_description='various format-patch tests'\n \n . ./test-lib.sh\n \n@@ -255,4 +255,54 @@ test_expect_success 'format-patch respects -U' '\n \n '\n \n+test_expect_success 'format-patch from a subdirectory (1)' '\n+\tfilename=$(\n+\t\trm -rf sub &&\n+\t\tmkdir -p sub/dir &&\n+\t\tcd sub/dir &&\n+\t\tgit format-patch -1\n+\t) &&\n+\tcase \"$filename\" in\n+\tsub/dir/*)\n+\t\t;; # ok\n+\t*)\n+\t\techo \"Oops? $filename\"\n+\t\tfalse\n+\t\t;;\n+\tesac &&\n+\ttest -f \"$filename\"\n+'\n+\n+test_expect_success 'format-patch from a subdirectory (2)' '\n+\tfilename=$(\n+\t\trm -rf sub &&\n+\t\tmkdir -p sub/dir &&\n+\t\tcd sub/dir &&\n+\t\tgit format-patch -1 -o ..\n+\t) &&\n+\tcase \"$filename\" in\n+\tsub/dir/../0*)\n+\t\t;; # ok\n+\t*)\n+\t\techo \"Oops? $filename\"\n+\t\tfalse\n+\t\t;;\n+\tesac &&\n+\tbasename=$(expr \"$filename\" : \".*/\\(.*\\)\") &&\n+\ttest -f \"sub/$basename\"\n+'\n+\n+test_expect_success 'format-patch from a subdirectory (3)' '\n+\there=\"$TEST_DIRECTORY/$test\" &&\n+\trm -f 0* &&\n+\tfilename=$(\n+\t\trm -rf sub &&\n+\t\tmkdir -p sub/dir &&\n+\t\tcd sub/dir &&\n+\t\tgit format-patch -1 -o \"$here\"\n+\t) &&\n+\tbasename=$(expr \"$filename\" : \".*/\\(.*\\)\") &&\n+\ttest -f \"$basename\"\n+'\n+\n test_done\n"},{"id":"100192","messageId":"496BCE55.8030407@cesarb.net","threadId":"17127","inReplyTo":"7vab9wgmwe.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] Teach format-patch to handle output directory relative to cwd","fromName":"Cesar Eduardo Barros","fromEmail":"cesarb@cesarb.net","sentAt":"2009-01-12T23:12:21Z","receivedAt":"2009-01-12T23:12:21Z","isPatch":true,"sender":{"key":"cesarb@cesarb.net","avatar":"https://avatars.githubusercontent.com/u/31324?v=4"},"body":"Junio C Hamano escreveu:\n> Without any explicit -o parameter, we correctly avoided putting the\n> resulting patch output to the toplevel.  We should do the same when\n> the user gave a relative pathname to be consistent with this case and also\n> with how other commands handle relative pathnames.\n\nWorks great, only the resulting output to the screen is a bit \nugly/confusing:\n\ndrivers/net/../../../0001-sc92031-more-useful-banner-in-kernel-log.patch\ndrivers/net/../../../0002-sc92031-remove-meaningless-version-string.patch\ndrivers/net/../../../0003-sc92031-inline-SC92031_DESCRIPTION.patch\ndrivers/net/../../../0004-sc92031-use-device-id-directly-instead-of-made-up-n.patch\ndrivers/net/../../../0005-sc92031-add-a-link-to-the-datasheet.patch\n\nI would expect:\n\n../../../0001-sc92031-more-useful-banner-in-kernel-log.patch\n../../../0002-sc92031-remove-meaningless-version-string.patch\n../../../0003-sc92031-inline-SC92031_DESCRIPTION.patch\n../../../0004-sc92031-use-device-id-directly-instead-of-made-up-n.patch\n../../../0005-sc92031-add-a-link-to-the-datasheet.patch\n\n(after all, I am still inside the drivers/net directory)\n\n-- \nCesar Eduardo Barros\ncesarb@cesarb.net\ncesar.barros@gmail.com\n"},{"id":"100211","messageId":"7vmydwf2a9.fsf@gitster.siamese.dyndns.org","threadId":"17127","inReplyTo":"496BCE55.8030407@cesarb.net","subject":"Re: [PATCH] Teach format-patch to handle output directory relative to cwd","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-01-13T01:00:30Z","receivedAt":"2009-01-13T01:00:30Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Cesar Eduardo Barros <cesarb@cesarb.net> writes:\n\n> Works great, only the resulting output to the screen is a bit\n> ugly/confusing:\n>\n> drivers/net/../../../0001-sc92031-more-useful-banner-in-kernel-log.patch\n> ...\n> (after all, I am still inside the drivers/net directory)\n\nFair enough.  Here is a replacement diff.\n\n builtin-log.c           |   28 ++++++++++++++++++++++--\n t/t4014-format-patch.sh |   52 ++++++++++++++++++++++++++++++++++++++++++++++-\n 2 files changed, 76 insertions(+), 4 deletions(-)\n\ndiff --git c/builtin-log.c w/builtin-log.c\nindex db71e0d..16a0f11 100644\n--- c/builtin-log.c\n+++ w/builtin-log.c\n@@ -568,6 +568,7 @@ static const char *get_oneline_for_filename(struct commit *commit,\n \n static FILE *realstdout = NULL;\n static const char *output_directory = NULL;\n+static int outdir_offset;\n \n static int reopen_stdout(const char *oneline, int nr, int total)\n {\n@@ -594,7 +595,7 @@ static int reopen_stdout(const char *oneline, int nr, int total)\n \t\tstrcpy(filename + len, fmt_patch_suffix);\n \t}\n \n-\tfprintf(realstdout, \"%s\\n\", filename);\n+\tfprintf(realstdout, \"%s\\n\", filename + outdir_offset);\n \tif (freopen(filename, \"w\", stdout) == NULL)\n \t\treturn error(\"Cannot open patch file %s\",filename);\n \n@@ -757,6 +758,27 @@ static const char *clean_message_id(const char *msg_id)\n \treturn xmemdupz(a, z - a);\n }\n \n+static const char *set_outdir(const char *prefix, const char *output_directory)\n+{\n+\tif (output_directory && is_absolute_path(output_directory))\n+\t\treturn output_directory;\n+\n+\tif (!prefix || !*prefix) {\n+\t\tif (output_directory)\n+\t\t\treturn output_directory;\n+\t\t/* The user did not explicitly ask for \"./\" */\n+\t\toutdir_offset = 2;\n+\t\treturn \"./\";\n+\t}\n+\n+\toutdir_offset = strlen(prefix);\n+\tif (!output_directory)\n+\t\treturn prefix;\n+\n+\treturn xstrdup(prefix_filename(prefix, outdir_offset,\n+\t\t\t\t       output_directory));\n+}\n+\n int cmd_format_patch(int argc, const char **argv, const char *prefix)\n {\n \tstruct commit *commit;\n@@ -935,8 +957,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \tif (!DIFF_OPT_TST(&rev.diffopt, TEXT) && !no_binary_diff)\n \t\tDIFF_OPT_SET(&rev.diffopt, BINARY);\n \n-\tif (!output_directory && !use_stdout)\n-\t\toutput_directory = prefix;\n+\tif (!use_stdout)\n+\t\toutput_directory = set_outdir(prefix, output_directory);\n \n \tif (output_directory) {\n \t\tif (use_stdout)\ndiff --git c/t/t4014-format-patch.sh w/t/t4014-format-patch.sh\nindex 7fe853c..16de436 100755\n--- c/t/t4014-format-patch.sh\n+++ w/t/t4014-format-patch.sh\n@@ -3,7 +3,7 @@\n # Copyright (c) 2006 Junio C Hamano\n #\n \n-test_description='Format-patch skipping already incorporated patches'\n+test_description='various format-patch tests'\n \n . ./test-lib.sh\n \n@@ -230,4 +230,54 @@ test_expect_success 'shortlog of cover-letter wraps overly-long onelines' '\n \n '\n \n+test_expect_success 'format-patch from a subdirectory (1)' '\n+\tfilename=$(\n+\t\trm -rf sub &&\n+\t\tmkdir -p sub/dir &&\n+\t\tcd sub/dir &&\n+\t\tgit format-patch -1\n+\t) &&\n+\tcase \"$filename\" in\n+\t0*)\n+\t\t;; # ok\n+\t*)\n+\t\techo \"Oops? $filename\"\n+\t\tfalse\n+\t\t;;\n+\tesac &&\n+\ttest -f \"$filename\"\n+'\n+\n+test_expect_success 'format-patch from a subdirectory (2)' '\n+\tfilename=$(\n+\t\trm -rf sub &&\n+\t\tmkdir -p sub/dir &&\n+\t\tcd sub/dir &&\n+\t\tgit format-patch -1 -o ..\n+\t) &&\n+\tcase \"$filename\" in\n+\t../0*)\n+\t\t;; # ok\n+\t*)\n+\t\techo \"Oops? $filename\"\n+\t\tfalse\n+\t\t;;\n+\tesac &&\n+\tbasename=$(expr \"$filename\" : \".*/\\(.*\\)\") &&\n+\ttest -f \"sub/$basename\"\n+'\n+\n+test_expect_success 'format-patch from a subdirectory (3)' '\n+\there=\"$TEST_DIRECTORY/$test\" &&\n+\trm -f 0* &&\n+\tfilename=$(\n+\t\trm -rf sub &&\n+\t\tmkdir -p sub/dir &&\n+\t\tcd sub/dir &&\n+\t\tgit format-patch -1 -o \"$here\"\n+\t) &&\n+\tbasename=$(expr \"$filename\" : \".*/\\(.*\\)\") &&\n+\ttest -f \"$basename\"\n+'\n+\n test_done\n"},{"id":"100258","messageId":"496C5DEA.4020305@cesarb.net","threadId":"17127","inReplyTo":"7vmydwf2a9.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] Teach format-patch to handle output directory relative to cwd","fromName":"Cesar Eduardo Barros","fromEmail":"cesarb@cesarb.net","sentAt":"2009-01-13T09:24:58Z","receivedAt":"2009-01-13T09:24:58Z","isPatch":true,"sender":{"key":"cesarb@cesarb.net","avatar":"https://avatars.githubusercontent.com/u/31324?v=4"},"body":"Junio C Hamano escreveu:\n> Cesar Eduardo Barros <cesarb@cesarb.net> writes:\n> \n>> Works great, only the resulting output to the screen is a bit\n>> ugly/confusing:\n>>\n>> drivers/net/../../../0001-sc92031-more-useful-banner-in-kernel-log.patch\n>> ...\n>> (after all, I am still inside the drivers/net directory)\n> \n> Fair enough.  Here is a replacement diff.\n\nWorks fine, thanks.\n\n-- \nCesar Eduardo Barros\ncesarb@cesarb.net\ncesar.barros@gmail.com\n"}]}