{"thread":{"id":"25620","subject":"[PATCHv7 0/6] Add commit message options for rebase --autosquash","startedAt":"2010-11-02T19:59:06Z","lastAt":"2010-11-03T09:20:16Z","messageCount":9,"participants":["Pat Notz","Thiago Farina","Stephen Boyd"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"154991","messageId":"1288727952-57498-1-git-send-email-patnotz@gmail.com","threadId":"25620","inReplyTo":null,"subject":"[PATCHv7 0/6] Add commit message options for rebase --autosquash","fromName":"Pat Notz","fromEmail":"patnotz@gmail.com","sentAt":"2010-11-02T19:59:06Z","receivedAt":"2010-11-02T19:59:06Z","isPatch":false,"sender":{"key":"patnotz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45364?v=4"},"body":"This patch series adds new command line options to git-commit to make\nit easy to specify messages for commits correctly formatted for use\nwith 'rebase -i --autosquash'.\n\nThis iteration (v7) addresses criticisms about implementation details\nraised against the v6 series.  For details, see\n\nhttp://thread.gmane.org/gmane.comp.version-control.git/159547\n\nThe first patch introduces minor refactorings that set the stage\nfor subsequent patches, mostly preventing copy-n-paste coding in what\nfollows.\n\nThe second patch teaches format_commit_message to reencode the content\nif the caller's commit object uses an encoding different from the\ncommit encoding.\n\nThe remaining patches add the --fixup and --squash commands to\ngit-commit including tests of commit, interactions with rebase and\ni18n encodings.  \n\nOne issue which limits the testing (but not the implementation, I\nthink) is that when 'rebase --autosquash' is comparing commit subject\nlines it does not first make sure that the commits use a common\nencoding.  That's follow-on work.\n\nPat Notz (6):\n  commit: helper methods to reduce redundant blocks of code\n  pretty.c: teach format_commit_message() to reencode the output\n  commit: --fixup option for use with rebase --autosquash\n  add tests of commit --fixup\n  commit: --squash option for use with rebase --autosquash\n  add tests of commit --squash\n\n Documentation/git-commit.txt |   21 +++++++++--\n builtin/commit.c             |   81 ++++++++++++++++++++++++++++--------------\n builtin/log.c                |    3 +-\n builtin/mailinfo.c           |    2 +-\n cache.h                      |    3 ++\n commit.c                     |   13 +++++++\n commit.h                     |    4 ++\n environment.c                |   11 ++++++\n pretty.c                     |   36 ++++++++++++-------\n t/t3415-rebase-autosquash.sh |   29 ++++++++++++++-\n t/t3900-i18n-commit.sh       |   29 +++++++++++++++\n t/t7500-commit.sh            |   80 +++++++++++++++++++++++++++++++++++++++++\n t/t7500/edit-content         |    4 ++\n 13 files changed, 267 insertions(+), 49 deletions(-)\n create mode 100755 t/t7500/edit-content\n\n-- \n1.7.3.2\n"},{"id":"154997","messageId":"1288727952-57498-2-git-send-email-patnotz@gmail.com","threadId":"25620","inReplyTo":"1288727952-57498-1-git-send-email-patnotz@gmail.com","subject":"[PATCHv7 1/6] commit: helper methods to reduce redundant blocks of code","fromName":"Pat Notz","fromEmail":"patnotz@gmail.com","sentAt":"2010-11-02T19:59:07Z","receivedAt":"2010-11-02T19:59:07Z","isPatch":false,"sender":{"key":"patnotz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45364?v=4"},"body":"* builtin/commit.c: Replace block of code with a one-liner call to\n  logmsg_reencode().\n\n* commit.c: new function for looking up a comit by name\n\n* pretty.c: helper methods for getting output encodings\n\n  Add helpers get_log_output_encoding() and\n  get_commit_output_encoding() that eliminate some messy and duplicate\n  if-blocks.\n\nSigned-off-by: Pat Notz <patnotz@gmail.com>\n---\n builtin/commit.c   |   26 ++++----------------------\n builtin/log.c      |    3 +--\n builtin/mailinfo.c |    2 +-\n cache.h            |    3 +++\n commit.c           |   13 +++++++++++++\n commit.h           |    1 +\n environment.c      |   11 +++++++++++\n pretty.c           |    9 ++-------\n 8 files changed, 36 insertions(+), 32 deletions(-)\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 66fdd22..54fcc6d 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -896,30 +896,14 @@ static int parse_and_validate_options(int argc, const char *argv[],\n \tif (!use_message && renew_authorship)\n \t\tdie(\"--reset-author can be used only with -C, -c or --amend.\");\n \tif (use_message) {\n-\t\tunsigned char sha1[20];\n-\t\tstatic char utf8[] = \"UTF-8\";\n \t\tconst char *out_enc;\n-\t\tchar *enc, *end;\n \t\tstruct commit *commit;\n \n-\t\tif (get_sha1(use_message, sha1))\n+\t\tcommit = lookup_commit_reference_by_name(use_message);\n+\t\tif (!commit)\n \t\t\tdie(\"could not lookup commit %s\", use_message);\n-\t\tcommit = lookup_commit_reference(sha1);\n-\t\tif (!commit || parse_commit(commit))\n-\t\t\tdie(\"could not parse commit %s\", use_message);\n-\n-\t\tenc = strstr(commit->buffer, \"\\nencoding\");\n-\t\tif (enc) {\n-\t\t\tend = strchr(enc + 10, '\\n');\n-\t\t\tenc = xstrndup(enc + 10, end - (enc + 10));\n-\t\t} else {\n-\t\t\tenc = utf8;\n-\t\t}\n-\t\tout_enc = git_commit_encoding ? git_commit_encoding : utf8;\n-\n-\t\tif (strcmp(out_enc, enc))\n-\t\t\tuse_message_buffer =\n-\t\t\t\treencode_string(commit->buffer, out_enc, enc);\n+\t\tout_enc = get_commit_output_encoding();\n+\t\tuse_message_buffer = logmsg_reencode(commit, out_enc);\n \n \t\t/*\n \t\t * If we failed to reencode the buffer, just copy it\n@@ -929,8 +913,6 @@ static int parse_and_validate_options(int argc, const char *argv[],\n \t\t */\n \t\tif (use_message_buffer == NULL)\n \t\t\tuse_message_buffer = xstrdup(commit->buffer);\n-\t\tif (enc != utf8)\n-\t\t\tfree(enc);\n \t}\n \n \tif (!!also + !!only + !!all + !!interactive > 1)\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 22d1290..90e05ac 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -329,8 +329,7 @@ static void show_tagger(char *buf, int len, struct rev_info *rev)\n \tstruct strbuf out = STRBUF_INIT;\n \n \tpp_user_info(\"Tagger\", rev->commit_format, &out, buf, rev->date_mode,\n-\t\tgit_log_output_encoding ?\n-\t\tgit_log_output_encoding: git_commit_encoding);\n+\t\tget_log_output_encoding());\n \tprintf(\"%s\", out.buf);\n \tstrbuf_release(&out);\n }\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 2320d98..71e6262 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -1032,7 +1032,7 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)\n \t */\n \tgit_config(git_mailinfo_config, NULL);\n \n-\tdef_charset = (git_commit_encoding ? git_commit_encoding : \"UTF-8\");\n+\tdef_charset = get_commit_output_encoding();\n \tmetainfo_charset = def_charset;\n \n \twhile (1 < argc && argv[1][0] == '-') {\ndiff --git a/cache.h b/cache.h\nindex 33decd9..5ed5374 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1003,6 +1003,9 @@ extern int git_env_bool(const char *, int);\n extern int git_config_system(void);\n extern int git_config_global(void);\n extern int config_error_nonbool(const char *);\n+extern const char *get_log_output_encoding(void);\n+extern const char *get_commit_output_encoding(void);\n+\n extern const char *config_exclusive_filename;\n \n #define MAX_GITNAME (1000)\ndiff --git a/commit.c b/commit.c\nindex 0094ec1..5ed9ccd 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -49,6 +49,19 @@ struct commit *lookup_commit(const unsigned char *sha1)\n \treturn check_commit(obj, sha1, 0);\n }\n \n+struct commit *lookup_commit_reference_by_name(const char *name)\n+{\n+\tunsigned char sha1[20];\n+\tstruct commit *commit;\n+\n+\tif (get_sha1(name, sha1))\n+\t\treturn NULL;\n+\tcommit = lookup_commit_reference(sha1);\n+\tif (!commit || parse_commit(commit))\n+\t\treturn NULL;\n+\treturn commit;\n+}\n+\n static unsigned long parse_commit_date(const char *buf, const char *tail)\n {\n \tconst char *dateptr;\ndiff --git a/commit.h b/commit.h\nindex 9113bbe..a0b710f 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -36,6 +36,7 @@ struct commit *lookup_commit(const unsigned char *sha1);\n struct commit *lookup_commit_reference(const unsigned char *sha1);\n struct commit *lookup_commit_reference_gently(const unsigned char *sha1,\n \t\t\t\t\t      int quiet);\n+struct commit *lookup_commit_reference_by_name(const char *name);\n \n int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size);\n \ndiff --git a/environment.c b/environment.c\nindex de5581f..a9d44a2 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -192,3 +192,14 @@ int set_git_dir(const char *path)\n \tsetup_git_env();\n \treturn 0;\n }\n+\n+const char *get_log_output_encoding(void)\n+{\n+\treturn git_log_output_encoding ? git_log_output_encoding\n+\t\t: get_commit_output_encoding();\n+}\n+\n+const char *get_commit_output_encoding(void)\n+{\n+\treturn git_commit_encoding ? git_commit_encoding : \"UTF-8\";\n+}\ndiff --git a/pretty.c b/pretty.c\nindex f85444b..c253172 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -886,8 +886,7 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,\n \tcase 'N':\n \t\tif (c->pretty_ctx->show_notes) {\n \t\t\tformat_display_notes(commit->object.sha1, sb,\n-\t\t\t\t    git_log_output_encoding ? git_log_output_encoding\n-\t\t\t\t\t\t\t    : git_commit_encoding, 0);\n+\t\t\t\t    get_log_output_encoding(), 0);\n \t\t\treturn 1;\n \t\t}\n \t\treturn 0;\n@@ -1159,11 +1158,7 @@ char *reencode_commit_message(const struct commit *commit, const char **encoding\n {\n \tconst char *encoding;\n \n-\tencoding = (git_log_output_encoding\n-\t\t    ? git_log_output_encoding\n-\t\t    : git_commit_encoding);\n-\tif (!encoding)\n-\t\tencoding = \"UTF-8\";\n+\tencoding = get_log_output_encoding();\n \tif (encoding_p)\n \t\t*encoding_p = encoding;\n \treturn logmsg_reencode(commit, encoding);\n-- \n1.7.3.2\n"},{"id":"154994","messageId":"1288727952-57498-3-git-send-email-patnotz@gmail.com","threadId":"25620","inReplyTo":"1288727952-57498-1-git-send-email-patnotz@gmail.com","subject":"[PATCHv7 2/6] pretty.c: teach format_commit_message() to reencode the output","fromName":"Pat Notz","fromEmail":"patnotz@gmail.com","sentAt":"2010-11-02T19:59:08Z","receivedAt":"2010-11-02T19:59:08Z","isPatch":false,"sender":{"key":"patnotz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45364?v=4"},"body":"format_commit_message() will now reencode the content if the desired\noutput encoding is different from the encoding in the passed in\ncommit.  Callers wanting to specify the output encoding do so via the\npretty_print_context struct.\n\nSigned-off-by: Pat Notz <patnotz@gmail.com>\n---\n commit.h |    3 +++\n pretty.c |   27 +++++++++++++++++++++------\n 2 files changed, 24 insertions(+), 6 deletions(-)\n\ndiff --git a/commit.h b/commit.h\nindex a0b710f..3bfb31b 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -77,6 +77,7 @@ struct pretty_print_context\n \tint need_8bit_cte;\n \tint show_notes;\n \tstruct reflog_walk_info *reflog_info;\n+\tconst char *output_encoding;\n };\n \n struct userformat_want {\n@@ -85,6 +86,8 @@ struct userformat_want {\n \n extern int has_non_ascii(const char *text);\n struct rev_info; /* in revision.h, it circularly uses enum cmit_fmt */\n+extern char *logmsg_reencode(const struct commit *commit,\n+\t\t\t     const char *output_encoding);\n extern char *reencode_commit_message(const struct commit *commit,\n \t\t\t\t     const char **encoding_p);\n extern void get_commit_format(const char *arg, struct rev_info *);\ndiff --git a/pretty.c b/pretty.c\nindex c253172..8549934 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -403,8 +403,8 @@ static char *replace_encoding_header(char *buf, const char *encoding)\n \treturn strbuf_detach(&tmp, NULL);\n }\n \n-static char *logmsg_reencode(const struct commit *commit,\n-\t\t\t     const char *output_encoding)\n+char *logmsg_reencode(const struct commit *commit,\n+\t\t      const char *output_encoding)\n {\n \tstatic const char *utf8 = \"UTF-8\";\n \tconst char *use_encoding;\n@@ -555,6 +555,7 @@ struct format_commit_context {\n \tconst struct pretty_print_context *pretty_ctx;\n \tunsigned commit_header_parsed:1;\n \tunsigned commit_message_parsed:1;\n+\tchar *message;\n \tsize_t width, indent1, indent2;\n \n \t/* These offsets are relative to the start of the commit message. */\n@@ -591,7 +592,7 @@ static int add_again(struct strbuf *sb, struct chunk *chunk)\n \n static void parse_commit_header(struct format_commit_context *context)\n {\n-\tconst char *msg = context->commit->buffer;\n+\tconst char *msg = context->message;\n \tint i;\n \n \tfor (i = 0; msg[i]; i++) {\n@@ -677,8 +678,8 @@ const char *format_subject(struct strbuf *sb, const char *msg,\n \n static void parse_commit_message(struct format_commit_context *c)\n {\n-\tconst char *msg = c->commit->buffer + c->message_off;\n-\tconst char *start = c->commit->buffer;\n+\tconst char *msg = c->message + c->message_off;\n+\tconst char *start = c->message;\n \n \tmsg = skip_empty_lines(msg);\n \tc->subject_off = msg - start;\n@@ -741,7 +742,7 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,\n {\n \tstruct format_commit_context *c = context;\n \tconst struct commit *commit = c->commit;\n-\tconst char *msg = commit->buffer;\n+\tconst char *msg = c->message;\n \tstruct commit_list *p;\n \tint h1, h2;\n \n@@ -1011,13 +1012,27 @@ void format_commit_message(const struct commit *commit,\n \t\t\t   const struct pretty_print_context *pretty_ctx)\n {\n \tstruct format_commit_context context;\n+\tstatic const char utf8[] = \"UTF-8\";\n+\tconst char *enc;\n+\tconst char *output_enc = pretty_ctx->output_encoding;\n \n \tmemset(&context, 0, sizeof(context));\n \tcontext.commit = commit;\n \tcontext.pretty_ctx = pretty_ctx;\n \tcontext.wrap_start = sb->len;\n+\tcontext.message = commit->buffer;\n+\tif (output_enc) {\n+\t\tenc = get_header(commit, \"encoding\");\n+\t\tenc = enc ? enc : utf8;\n+\t\tif (strcmp(enc, output_enc))\n+\t\t\tcontext.message = logmsg_reencode(commit, output_enc);\n+\t}\n+\n \tstrbuf_expand(sb, format, format_commit_item, &context);\n \trewrap_message_tail(sb, &context, 0, 0, 0);\n+\n+\tif (context.message != commit->buffer)\n+\t\tfree(context.message);\n }\n \n static void pp_header(enum cmit_fmt fmt,\n-- \n1.7.3.2\n"},{"id":"154992","messageId":"1288727952-57498-4-git-send-email-patnotz@gmail.com","threadId":"25620","inReplyTo":"1288727952-57498-1-git-send-email-patnotz@gmail.com","subject":"[PATCHv7 3/6] commit: --fixup option for use with rebase --autosquash","fromName":"Pat Notz","fromEmail":"patnotz@gmail.com","sentAt":"2010-11-02T19:59:09Z","receivedAt":"2010-11-02T19:59:09Z","isPatch":false,"sender":{"key":"patnotz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45364?v=4"},"body":"This option makes it convenient to construct commit messages for use\nwith 'rebase --autosquash'.  The resulting commit message will be\n\"fixup! ...\" where \"...\" is the subject line of the specified commit\nmessage.\n\nExample usage:\n  $ git commit --fixup HEAD~2\n\nSigned-off-by: Pat Notz <patnotz@gmail.com>\n---\n Documentation/git-commit.txt |   14 ++++++++++----\n builtin/commit.c             |   22 ++++++++++++++++++----\n 2 files changed, 28 insertions(+), 8 deletions(-)\n\ndiff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt\nindex 42fb1f5..f4a2b8c 100644\n--- a/Documentation/git-commit.txt\n+++ b/Documentation/git-commit.txt\n@@ -9,10 +9,10 @@ SYNOPSIS\n --------\n [verse]\n 'git commit' [-a | --interactive] [-s] [-v] [-u<mode>] [--amend] [--dry-run]\n-\t   [(-c | -C) <commit>] [-F <file> | -m <msg>] [--reset-author]\n-\t   [--allow-empty] [--allow-empty-message] [--no-verify] [-e] [--author=<author>]\n-\t   [--date=<date>] [--cleanup=<mode>] [--status | --no-status] [--]\n-\t   [[-i | -o ]<file>...]\n+\t   [(-c | -C | --fixup) <commit>] [-F <file> | -m <msg>]\n+\t   [--reset-author] [--allow-empty] [--allow-empty-message] [--no-verify]\n+\t   [-e] [--author=<author>] [--date=<date>] [--cleanup=<mode>]\n+\t   [--status | --no-status] [--] [[-i | -o ]<file>...]\n \n DESCRIPTION\n -----------\n@@ -70,6 +70,12 @@ OPTIONS\n \tLike '-C', but with '-c' the editor is invoked, so that\n \tthe user can further edit the commit message.\n \n+--fixup=<commit>::\n+\tConstruct a commit message for use with `rebase --autosquash`.\n+\tThe commit message will be the subject line from the specified\n+\tcommit with a prefix of \"fixup! \".  See linkgit:git-rebase[1]\n+\tfor details.\n+\n --reset-author::\n \tWhen used with -C/-c/--amend options, declare that the\n \tauthorship of the resulting commit now belongs of the committer.\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 54fcc6d..22498c6 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -69,6 +69,7 @@ static enum {\n static const char *logfile, *force_author;\n static const char *template_file;\n static char *edit_message, *use_message;\n+static char *fixup_message;\n static char *author_name, *author_email, *author_date;\n static int all, edit_flag, also, interactive, only, amend, signoff;\n static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;\n@@ -124,6 +125,7 @@ static struct option builtin_commit_options[] = {\n \tOPT_CALLBACK('m', \"message\", &message, \"MESSAGE\", \"specify commit message\", opt_parse_m),\n \tOPT_STRING('c', \"reedit-message\", &edit_message, \"COMMIT\", \"reuse and edit message from specified commit\"),\n \tOPT_STRING('C', \"reuse-message\", &use_message, \"COMMIT\", \"reuse message from specified commit\"),\n+\tOPT_STRING(0, \"fixup\", &fixup_message, \"COMMIT\", \"use autosquash formatted message to fixup specified commit\"),\n \tOPT_BOOLEAN(0, \"reset-author\", &renew_authorship, \"the commit is authored by me now (used with -C-c/--amend)\"),\n \tOPT_BOOLEAN('s', \"signoff\", &signoff, \"add Signed-off-by:\"),\n \tOPT_FILENAME('t', \"template\", &template_file, \"use specified template file\"),\n@@ -586,6 +588,16 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n \t\tstrbuf_add(&sb, buffer + 2, strlen(buffer + 2));\n \t\thook_arg1 = \"commit\";\n \t\thook_arg2 = use_message;\n+\t} else if (fixup_message) {\n+\t\tstruct pretty_print_context ctx = {0};\n+\t\tstruct commit *commit;\n+\t\tcommit = lookup_commit_reference_by_name(fixup_message);\n+\t\tif (!commit)\n+\t\t\tdie(\"could not lookup commit %s\", fixup_message);\n+\t\tctx.output_encoding = get_commit_output_encoding();\n+\t\tformat_commit_message(commit, \"fixup! %s\\n\\n\",\n+\t\t\t\t      &sb, &ctx);\n+\t\thook_arg1 = \"message\";\n \t} else if (!stat(git_path(\"MERGE_MSG\"), &statbuf)) {\n \t\tif (strbuf_read_file(&sb, git_path(\"MERGE_MSG\"), 0) < 0)\n \t\t\tdie_errno(\"could not read MERGE_MSG\");\n@@ -863,7 +875,7 @@ static int parse_and_validate_options(int argc, const char *argv[],\n \tif (force_author && renew_authorship)\n \t\tdie(\"Using both --reset-author and --author does not make sense\");\n \n-\tif (logfile || message.len || use_message)\n+\tif (logfile || message.len || use_message || fixup_message)\n \t\tuse_editor = 0;\n \tif (edit_flag)\n \t\tuse_editor = 1;\n@@ -883,15 +895,17 @@ static int parse_and_validate_options(int argc, const char *argv[],\n \t\tf++;\n \tif (edit_message)\n \t\tf++;\n+\tif (fixup_message)\n+\t\tf++;\n \tif (logfile)\n \t\tf++;\n \tif (f > 1)\n-\t\tdie(\"Only one of -c/-C/-F can be used.\");\n+\t\tdie(\"Only one of -c/-C/-F/--fixup can be used.\");\n \tif (message.len && f > 0)\n-\t\tdie(\"Option -m cannot be combined with -c/-C/-F.\");\n+\t\tdie(\"Option -m cannot be combined with -c/-C/-F/--fixup.\");\n \tif (edit_message)\n \t\tuse_message = edit_message;\n-\tif (amend && !use_message)\n+\tif (amend && !use_message && !fixup_message)\n \t\tuse_message = \"HEAD\";\n \tif (!use_message && renew_authorship)\n \t\tdie(\"--reset-author can be used only with -C, -c or --amend.\");\n-- \n1.7.3.2\n"},{"id":"154996","messageId":"1288727952-57498-5-git-send-email-patnotz@gmail.com","threadId":"25620","inReplyTo":"1288727952-57498-1-git-send-email-patnotz@gmail.com","subject":"[PATCHv7 4/6] add tests of commit --fixup","fromName":"Pat Notz","fromEmail":"patnotz@gmail.com","sentAt":"2010-11-02T19:59:10Z","receivedAt":"2010-11-02T19:59:10Z","isPatch":false,"sender":{"key":"patnotz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45364?v=4"},"body":"t7500: test expected behavior of commit --fixup\nt3415: test interaction of commit --fixup with rebase --autosquash\nt3900: test commit --fixup with i18n encodings\n\nSigned-off-by: Pat Notz <patnotz@gmail.com>\n---\n t/t3415-rebase-autosquash.sh |   25 +++++++++++++++++++++++--\n t/t3900-i18n-commit.sh       |   27 +++++++++++++++++++++++++++\n t/t7500-commit.sh            |   33 +++++++++++++++++++++++++++++++++\n 3 files changed, 83 insertions(+), 2 deletions(-)\n\ndiff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh\nindex fd2184c..b77a413 100755\n--- a/t/t3415-rebase-autosquash.sh\n+++ b/t/t3415-rebase-autosquash.sh\n@@ -14,6 +14,7 @@ test_expect_success setup '\n \tgit add . &&\n \ttest_tick &&\n \tgit commit -m \"first commit\" &&\n+\tgit tag first-commit &&\n \techo 3 >file3 &&\n \tgit add . &&\n \ttest_tick &&\n@@ -21,7 +22,7 @@ test_expect_success setup '\n \tgit tag base\n '\n \n-test_auto_fixup() {\n+test_auto_fixup () {\n \tgit reset --hard base &&\n \techo 1 >file1 &&\n \tgit add -u &&\n@@ -50,7 +51,7 @@ test_expect_success 'auto fixup (config)' '\n \ttest_must_fail test_auto_fixup final-fixup-config-false\n '\n \n-test_auto_squash() {\n+test_auto_squash () {\n \tgit reset --hard base &&\n \techo 1 >file1 &&\n \tgit add -u &&\n@@ -94,4 +95,24 @@ test_expect_success 'misspelled auto squash' '\n \ttest 0 = $(git rev-list final-missquash...HEAD | wc -l)\n '\n \n+test_auto_commit_flags () {\n+\tgit reset --hard base &&\n+\techo 1 >file1 &&\n+\tgit add -u &&\n+\ttest_tick &&\n+\tgit commit --$1 first-commit &&\n+\tgit tag final-commit-$1 &&\n+\ttest_tick &&\n+\tgit rebase --autosquash -i HEAD^^^ &&\n+\tgit log --oneline >actual &&\n+\ttest 3 = $(wc -l <actual) &&\n+\tgit diff --exit-code final-commit-$1 &&\n+\ttest 1 = \"$(git cat-file blob HEAD^:file1)\" &&\n+\ttest $2 = $(git cat-file commit HEAD^ | grep first | wc -l)\n+}\n+\n+test_expect_success 'use commit --fixup' '\n+\ttest_auto_commit_flags fixup 1\n+'\n+\n test_done\ndiff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh\nindex 256c4c9..f4775ee 100755\n--- a/t/t3900-i18n-commit.sh\n+++ b/t/t3900-i18n-commit.sh\n@@ -133,4 +133,31 @@ do\n \t'\n done\n \n+test_commit_autosquash_flags () {\n+\tH=$1\n+\tflag=$2\n+\ttest_expect_success \"commit --$flag with $H encoding\" '\n+\t\tgit config i18n.commitencoding $H &&\n+\t\tgit checkout -b $H-$flag C0 &&\n+\t\techo $H >>F &&\n+\t\tgit commit -a -F \"$TEST_DIRECTORY\"/t3900/$H.txt &&\n+\t\ttest_tick &&\n+\t\techo intermediate stuff >>G &&\n+\t\tgit add G &&\n+\t\tgit commit -a -m \"intermediate commit\" &&\n+\t\ttest_tick &&\n+\t\techo $H $flag >>F &&\n+\t\tgit commit -a --$flag HEAD~1 $3 &&\n+\t\tE=$(git cat-file commit '$H-$flag' |\n+\t\t\tsed -ne \"s/^encoding //p\") &&\n+\t\ttest \"z$E\" = \"z$H\" &&\n+\t\tgit config --unset-all i18n.commitencoding &&\n+\t\tgit rebase --autosquash -i HEAD^^^ &&\n+\t\tgit log --oneline >actual &&\n+\t\ttest 3 = $(wc -l <actual)\n+\t'\n+}\n+\n+test_commit_autosquash_flags eucJP fixup\n+\n test_done\ndiff --git a/t/t7500-commit.sh b/t/t7500-commit.sh\nindex aa9c577..a41b819 100755\n--- a/t/t7500-commit.sh\n+++ b/t/t7500-commit.sh\n@@ -215,4 +215,37 @@ test_expect_success 'Commit a message with --allow-empty-message' '\n \tcommit_msg_is \"hello there\"\n '\n \n+commit_for_rebase_autosquash_setup () {\n+\techo \"first content line\" >>foo &&\n+\tgit add foo &&\n+\tcat >log <<EOF &&\n+target message subject line\n+\n+target message body line 1\n+target message body line 2\n+EOF\n+\tgit commit -F log &&\n+\techo \"second content line\" >>foo &&\n+\tgit add foo &&\n+\tgit commit -m \"intermediate commit\" &&\n+\techo \"third content line\" >>foo &&\n+\tgit add foo\n+}\n+\n+test_expect_success 'commit --fixup provides correct one-line commit message' '\n+\tcommit_for_rebase_autosquash_setup &&\n+\tgit commit --fixup HEAD~1 &&\n+\tcommit_msg_is \"fixup! target message subject line\"\n+'\n+\n+test_expect_success 'invalid message options when using --fixup' '\n+\techo changes >>foo &&\n+\techo \"message\" >log &&\n+\tgit add foo &&\n+\ttest_must_fail git commit --fixup HEAD~1 -C HEAD~2 &&\n+\ttest_must_fail git commit --fixup HEAD~1 -c HEAD~2 &&\n+\ttest_must_fail git commit --fixup HEAD~1 -m \"cmdline message\" &&\n+\ttest_must_fail git commit --fixup HEAD~1 -F log\n+'\n+\n test_done\n-- \n1.7.3.2\n"},{"id":"154993","messageId":"1288727952-57498-6-git-send-email-patnotz@gmail.com","threadId":"25620","inReplyTo":"1288727952-57498-1-git-send-email-patnotz@gmail.com","subject":"[PATCHv7 5/6] commit: --squash option for use with rebase --autosquash","fromName":"Pat Notz","fromEmail":"patnotz@gmail.com","sentAt":"2010-11-02T19:59:11Z","receivedAt":"2010-11-02T19:59:11Z","isPatch":false,"sender":{"key":"patnotz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45364?v=4"},"body":"This option makes it convenient to construct commit messages for use\nwith 'rebase --autosquash'.  The resulting commit message will be\n\"squash! ...\" where \"...\" is the subject line of the specified commit\nmessage.  This option can be used with other commit message options\nsuch as -m, -c, -C and -F.\n\nIf an editor is invoked (as with -c or -eF or no message options) the\ncommit message is seeded with the correctly formatted subject line.\n\nExample usage:\n  $ git commit --squash HEAD~2\n  $ git commit --squash HEAD~2 -m \"clever comment\"\n  $ git commit --squash HEAD~2 -F msgfile\n  $ git commit --squash HEAD~2 -C deadbeef\n\nSigned-off-by: Pat Notz <patnotz@gmail.com>\n---\n Documentation/git-commit.txt |    9 ++++++++-\n builtin/commit.c             |   35 +++++++++++++++++++++++++++++++++--\n 2 files changed, 41 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt\nindex f4a2b8c..6e4c220 100644\n--- a/Documentation/git-commit.txt\n+++ b/Documentation/git-commit.txt\n@@ -9,7 +9,7 @@ SYNOPSIS\n --------\n [verse]\n 'git commit' [-a | --interactive] [-s] [-v] [-u<mode>] [--amend] [--dry-run]\n-\t   [(-c | -C | --fixup) <commit>] [-F <file> | -m <msg>]\n+\t   [(-c | -C | --fixup | --squash) <commit>] [-F <file> | -m <msg>]\n \t   [--reset-author] [--allow-empty] [--allow-empty-message] [--no-verify]\n \t   [-e] [--author=<author>] [--date=<date>] [--cleanup=<mode>]\n \t   [--status | --no-status] [--] [[-i | -o ]<file>...]\n@@ -76,6 +76,13 @@ OPTIONS\n \tcommit with a prefix of \"fixup! \".  See linkgit:git-rebase[1]\n \tfor details.\n \n+--squash=<commit>::\n+\tConstruct a commit message for use with `rebase --autosquash`.\n+\tThe commit message subject line is taken from the specified\n+\tcommit with a prefix of \"squash! \".  Can be used with additional\n+\tcommit message options (`-m`/`-c`/`-C`/`-F`). See\n+\tlinkgit:git-rebase[1] for details.\n+\n --reset-author::\n \tWhen used with -C/-c/--amend options, declare that the\n \tauthorship of the resulting commit now belongs of the committer.\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 22498c6..05c2c81 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -69,7 +69,7 @@ static enum {\n static const char *logfile, *force_author;\n static const char *template_file;\n static char *edit_message, *use_message;\n-static char *fixup_message;\n+static char *fixup_message, *squash_message;\n static char *author_name, *author_email, *author_date;\n static int all, edit_flag, also, interactive, only, amend, signoff;\n static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;\n@@ -126,6 +126,7 @@ static struct option builtin_commit_options[] = {\n \tOPT_STRING('c', \"reedit-message\", &edit_message, \"COMMIT\", \"reuse and edit message from specified commit\"),\n \tOPT_STRING('C', \"reuse-message\", &use_message, \"COMMIT\", \"reuse message from specified commit\"),\n \tOPT_STRING(0, \"fixup\", &fixup_message, \"COMMIT\", \"use autosquash formatted message to fixup specified commit\"),\n+\tOPT_STRING(0, \"squash\", &squash_message, \"COMMIT\", \"use autosquash formatted message to squash specified commit\"),\n \tOPT_BOOLEAN(0, \"reset-author\", &renew_authorship, \"the commit is authored by me now (used with -C-c/--amend)\"),\n \tOPT_BOOLEAN('s', \"signoff\", &signoff, \"add Signed-off-by:\"),\n \tOPT_FILENAME('t', \"template\", &template_file, \"use specified template file\"),\n@@ -567,6 +568,25 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n \tif (!no_verify && run_hook(index_file, \"pre-commit\", NULL))\n \t\treturn 0;\n \n+\tif (squash_message) {\n+\t\t/*\n+\t\t * Insert the proper subject line before other commit\n+\t\t * message options add their content.\n+\t\t */\n+\t\tif (use_message && !strcmp(use_message, squash_message))\n+\t\t\tstrbuf_addstr(&sb, \"squash! \");\n+\t\telse {\n+\t\t\tstruct pretty_print_context ctx = {0};\n+\t\t\tstruct commit *c;\n+\t\t\tc = lookup_commit_reference_by_name(squash_message);\n+\t\t\tif (!c)\n+\t\t\t\tdie(\"could not lookup commit %s\", squash_message);\n+\t\t\tctx.output_encoding = get_commit_output_encoding();\n+\t\t\tformat_commit_message(c, \"squash! %s\\n\\n\", &sb,\n+\t\t\t\t\t      &ctx);\n+\t\t}\n+\t}\n+\n \tif (message.len) {\n \t\tstrbuf_addbuf(&sb, &message);\n \t\thook_arg1 = \"message\";\n@@ -619,6 +639,16 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n \telse if (in_merge)\n \t\thook_arg1 = \"merge\";\n \n+\tif (squash_message) {\n+\t\t/*\n+\t\t * If squash_commit was used for the commit subject,\n+\t\t * then we're possibly hijacking other commit log options.\n+\t\t * Reset the hook args to tell the real story.\n+\t\t */\n+\t\thook_arg1 = \"message\";\n+\t\thook_arg2 = \"\";\n+\t}\n+\n \tfp = fopen(git_path(commit_editmsg), \"w\");\n \tif (fp == NULL)\n \t\tdie_errno(\"could not open '%s'\", git_path(commit_editmsg));\n@@ -890,7 +920,8 @@ static int parse_and_validate_options(int argc, const char *argv[],\n \t\tdie(\"You have nothing to amend.\");\n \tif (amend && in_merge)\n \t\tdie(\"You are in the middle of a merge -- cannot amend.\");\n-\n+\tif (fixup_message && squash_message)\n+\t\tdie(\"Options --squash and --fixup cannot be used together\");\n \tif (use_message)\n \t\tf++;\n \tif (edit_message)\n-- \n1.7.3.2\n"},{"id":"154995","messageId":"1288727952-57498-7-git-send-email-patnotz@gmail.com","threadId":"25620","inReplyTo":"1288727952-57498-1-git-send-email-patnotz@gmail.com","subject":"[PATCHv7 6/6] add tests of commit --squash","fromName":"Pat Notz","fromEmail":"patnotz@gmail.com","sentAt":"2010-11-02T19:59:12Z","receivedAt":"2010-11-02T19:59:12Z","isPatch":false,"sender":{"key":"patnotz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45364?v=4"},"body":"t7500: test expected behavior of commit --squash\nt3415: test interaction of commit --squash with rebase --autosquash\nt3900: test commit --squash with i18n encodings\n\nSigned-off-by: Pat Notz <patnotz@gmail.com>\n---\n t/t3415-rebase-autosquash.sh |    4 +++\n t/t3900-i18n-commit.sh       |    2 +\n t/t7500-commit.sh            |   47 ++++++++++++++++++++++++++++++++++++++++++\n t/t7500/edit-content         |    4 +++\n 4 files changed, 57 insertions(+), 0 deletions(-)\n create mode 100755 t/t7500/edit-content\n\ndiff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh\nindex b77a413..0028533 100755\n--- a/t/t3415-rebase-autosquash.sh\n+++ b/t/t3415-rebase-autosquash.sh\n@@ -115,4 +115,8 @@ test_expect_success 'use commit --fixup' '\n \ttest_auto_commit_flags fixup 1\n '\n \n+test_expect_success 'use commit --squash' '\n+\ttest_auto_commit_flags squash 2\n+'\n+\n test_done\ndiff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh\nindex f4775ee..c06a5ee 100755\n--- a/t/t3900-i18n-commit.sh\n+++ b/t/t3900-i18n-commit.sh\n@@ -160,4 +160,6 @@ test_commit_autosquash_flags () {\n \n test_commit_autosquash_flags eucJP fixup\n \n+test_commit_autosquash_flags ISO-2022-JP squash '-m \"squash message\"'\n+\n test_done\ndiff --git a/t/t7500-commit.sh b/t/t7500-commit.sh\nindex a41b819..162527c 100755\n--- a/t/t7500-commit.sh\n+++ b/t/t7500-commit.sh\n@@ -238,10 +238,57 @@ test_expect_success 'commit --fixup provides correct one-line commit message' '\n \tcommit_msg_is \"fixup! target message subject line\"\n '\n \n+test_expect_success 'commit --squash works with -F' '\n+\tcommit_for_rebase_autosquash_setup &&\n+\techo \"log message from file\" >msgfile &&\n+\tgit commit --squash HEAD~1 -F msgfile  &&\n+\tcommit_msg_is \"squash! target message subject linelog message from file\"\n+'\n+\n+test_expect_success 'commit --squash works with -m' '\n+\tcommit_for_rebase_autosquash_setup &&\n+\tgit commit --squash HEAD~1 -m \"foo bar\\nbaz\" &&\n+\tcommit_msg_is \"squash! target message subject linefoo bar\\nbaz\"\n+'\n+\n+test_expect_success 'commit --squash works with -C' '\n+\tcommit_for_rebase_autosquash_setup &&\n+\tgit commit --squash HEAD~1 -C HEAD &&\n+\tcommit_msg_is \"squash! target message subject lineintermediate commit\"\n+'\n+\n+test_expect_success 'commit --squash works with -c' '\n+\tcommit_for_rebase_autosquash_setup &&\n+\ttest_set_editor \"$TEST_DIRECTORY\"/t7500/edit-content &&\n+\tgit commit --squash HEAD~1 -c HEAD &&\n+\tcommit_msg_is \"squash! target message subject lineedited commit\"\n+'\n+\n+test_expect_success 'commit --squash works with -C for same commit' '\n+\tcommit_for_rebase_autosquash_setup &&\n+\tgit commit --squash HEAD -C HEAD &&\n+\tcommit_msg_is \"squash! intermediate commit\"\n+'\n+\n+test_expect_success 'commit --squash works with -c for same commit' '\n+\tcommit_for_rebase_autosquash_setup &&\n+\ttest_set_editor \"$TEST_DIRECTORY\"/t7500/edit-content &&\n+\tgit commit --squash HEAD -c HEAD &&\n+\tcommit_msg_is \"squash! edited commit\"\n+'\n+\n+test_expect_success 'commit --squash works with editor' '\n+\tcommit_for_rebase_autosquash_setup &&\n+\ttest_set_editor \"$TEST_DIRECTORY\"/t7500/add-content &&\n+\tgit commit --squash HEAD~1 &&\n+\tcommit_msg_is \"squash! target message subject linecommit message\"\n+'\n+\n test_expect_success 'invalid message options when using --fixup' '\n \techo changes >>foo &&\n \techo \"message\" >log &&\n \tgit add foo &&\n+\ttest_must_fail git commit --fixup HEAD~1 --squash HEAD~2 &&\n \ttest_must_fail git commit --fixup HEAD~1 -C HEAD~2 &&\n \ttest_must_fail git commit --fixup HEAD~1 -c HEAD~2 &&\n \ttest_must_fail git commit --fixup HEAD~1 -m \"cmdline message\" &&\ndiff --git a/t/t7500/edit-content b/t/t7500/edit-content\nnew file mode 100755\nindex 0000000..08db9fd\n--- /dev/null\n+++ b/t/t7500/edit-content\n@@ -0,0 +1,4 @@\n+#!/bin/sh\n+sed -e \"s/intermediate/edited/g\" <\"$1\" >\"$1-\"\n+mv \"$1-\" \"$1\"\n+exit 0\n-- \n1.7.3.2\n"},{"id":"155000","messageId":"AANLkTinX=aSm-Dh2jDuxLdXk90528v5BdbnLsTyaHYD1@mail.gmail.com","threadId":"25620","inReplyTo":"1288727952-57498-2-git-send-email-patnotz@gmail.com","subject":"Re: [PATCHv7 1/6] commit: helper methods to reduce redundant blocks of code","fromName":"Thiago Farina","fromEmail":"tfransosi@gmail.com","sentAt":"2010-11-02T20:42:10Z","receivedAt":"2010-11-02T20:42:10Z","isPatch":false,"sender":{"key":"tfransosi@gmail.com","avatar":"https://avatars.githubusercontent.com/u/970071?v=4"},"body":"On Tue, Nov 2, 2010 at 5:59 PM, Pat Notz <patnotz@gmail.com> wrote:\n> * builtin/commit.c: Replace block of code with a one-liner call to\n>  logmsg_reencode().\n>\n> * commit.c: new function for looking up a comit by name\n>\nnit: s/comit/commit\n"},{"id":"155038","messageId":"4CD12950.2080901@gmail.com","threadId":"25620","inReplyTo":"1288727952-57498-6-git-send-email-patnotz@gmail.com","subject":"Re: [PATCHv7 5/6] commit: --squash option for use with rebase --autosquash","fromName":"Stephen Boyd","fromEmail":"bebarino@gmail.com","sentAt":"2010-11-03T09:20:16Z","receivedAt":"2010-11-03T09:20:16Z","isPatch":false,"sender":{"key":"bebarino@gmail.com","avatar":"https://avatars.githubusercontent.com/u/38832?v=4"},"body":"Sorry if I've missed earlier versions and this has already been\nanswered. You can carry forward Cc's if you like and thus earlier\ncommentators will be more likely to re-review your code.\n\nOn 11/02/10 12:59, Pat Notz wrote:\n> +--squash=<commit>::\n> +\tConstruct a commit message for use with `rebase --autosquash`.\n> +\tThe commit message subject line is taken from the specified\n> +\tcommit with a prefix of \"squash! \".  Can be used with additional\n> +\tcommit message options (`-m`/`-c`/`-C`/`-F`). See\n> +\tlinkgit:git-rebase[1] for details.\n\nThis doesn't mention the editor being invoked. The editor is invoked\nonly with certain option combinations right? I'm expecting this:\n\nuses editor\n------------\n--squash\n--squash -c\n--squash -t\n--squash -eF\n--squash -eC\n--squash -em\n--squash --amend\n\ndoesn't use editor\n------------------\n--squash -C = no editor\n--squash -m = no editor\n--squash -F = no editor\n\nI haven't thoroughly checked the code to make sure that's happening.\n\n> @@ -619,6 +639,16 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n>  \telse if (in_merge)\n>  \t\thook_arg1 = \"merge\";\n>  \n> +\tif (squash_message) {\n> +\t\t/*\n> +\t\t * If squash_commit was used for the commit subject,\n\nsquash_commit or squash_message?\n"}]}