{"thread":{"id":"60469","subject":"[PATCH 2/2] docs: rewrite rebase --(no-)autosquash description","startedAt":"2023-11-03T21:30:54Z","lastAt":"2023-11-16T00:27:49Z","messageCount":32,"participants":["Andy Koppe","Junio C Hamano","Phillip Wood"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"484412","messageId":"20231103212958.18472-2-andy.koppe@gmail.com","threadId":"60469","inReplyTo":"20231103212958.18472-1-andy.koppe@gmail.com","subject":"[PATCH 2/2] docs: rewrite rebase --(no-)autosquash description","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-11-03T21:29:58Z","receivedAt":"2023-11-03T21:30:54Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"Rewrite the description of the rebase --(no-)autosquash options to try\nto make it a bit clearer. Don't use \"the '...'\" to refer to part of a\ncommit message, mention how --interactive can be used to review the\ntodo list, and add a bit more detail on commit --squash/amend.\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n Documentation/git-rebase.txt | 32 ++++++++++++++++++--------------\n 1 file changed, 18 insertions(+), 14 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex 102ff91493..594158fcbc 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -589,21 +589,25 @@ See also INCOMPATIBLE OPTIONS below.\n \n --autosquash::\n --no-autosquash::\n-\tWhen the commit log message begins with \"squash! ...\" or \"fixup! ...\"\n-\tor \"amend! ...\", and there is already a commit in the todo list that\n-\tmatches the same `...`, automatically modify the todo list of\n-\t`rebase`, so that the commit marked for squashing comes right after\n-\tthe commit to be modified, and change the action of the moved commit\n-\tfrom `pick` to `squash` or `fixup` or `fixup -C` respectively. A commit\n-\tmatches the `...` if the commit subject matches, or if the `...` refers\n-\tto the commit's hash. As a fall-back, partial matches of the commit\n-\tsubject work, too. The recommended way to create fixup/amend/squash\n-\tcommits is by using the `--fixup`, `--fixup=amend:` or `--fixup=reword:`\n-\tand `--squash` options respectively of linkgit:git-commit[1].\n+\tAutomatically squash commits with specially formatted messages into\n+\tprevious commits.  If a commit message starts with \"squash! \",\n+\t\"fixup! \" or \"amend! \", the remainder of the subject line is taken\n+\tas a commit specifier, which matches a previous commit if it matches\n+\tthe start of the subject line or the hash of that commit.\n +\n-If the `--autosquash` option is enabled by default using the\n-configuration variable `rebase.autoSquash`, this option can be\n-used to override and disable this setting.\n+In the rebase todo list, commits marked for squashing are moved right after\n+the commits they modify, and their action is changed from `pick` to `squash`,\n+`fixup` or `fixup -C`, depending on the squash marker.  The `--interactive`\n+option can be used to review and edit the todo list before proceeding.\n++\n+The recommended way to create commits with squash markers is by using the\n+`--squash`, `--fixup`, `--fixup=amend:` or `--fixup=reword:` options of\n+linkgit:git-commit[1], which take the target commit as an argument and\n+automatically fill in the subject line of the new commit from that.\n++\n+The configuration variable `rebase.autoSquash` can be used to enable\n+`--autosquash` by default.  See the CONFIGURATION section below for details.\n+The `--no-autosquash` option overrides that setting.\n +\n See also INCOMPATIBLE OPTIONS below.\n \n-- \n2.43.0-rc0\n\n"},{"id":"484413","messageId":"20231103212958.18472-1-andy.koppe@gmail.com","threadId":"60469","inReplyTo":null,"subject":"[PATCH 1/2] rebase: support non-interactive autosquash","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-11-03T21:29:57Z","receivedAt":"2023-11-03T21:30:54Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"So far, the rebase --autosquash option and rebase.autoSquash=true\nconfig setting are quietly ignored when used without --interactive,\nexcept that they prevent fast-forward and that they trigger conflicts\nwith --apply and relatives, which is less than helpful particularly for\nthe config setting.\n\nSince the \"merge\" backend used for interactive rebase also is the\ndefault for non-interactive rebase, there does not appear to be a\nreason not to do --autosquash without --interactive, so support that.\n\nTurn rebase.autoSquash into a multi-choice setting, with \"interactive\"\nenabling autosquashing for --interactive, and \"always\" enabling it\nwithout --interactive as well. Make boolean true values synonyms for\n\"interactive\" for backward compatibility.\n\nDon't prevent fast-forwards or report conflicts with --apply options\nfor rebase.autoSquash=interactive mode when rebase is invoked without\n--interactive.\n\nChange the git-rebase and config/rebase documentation accordingly, and\nextend t3415-rebase-autosquash.sh to test the new rebase.autosquash\nvalues and combinations with and without --interactive.\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n Documentation/config/rebase.txt        |  4 +-\n Documentation/git-rebase.txt           |  2 +-\n builtin/rebase.c                       | 45 +++++++++++------\n t/t3415-rebase-autosquash.sh           | 70 ++++++++++++++++++++------\n t/t3422-rebase-incompatible-options.sh |  2 +-\n 5 files changed, 92 insertions(+), 31 deletions(-)\n\ndiff --git a/Documentation/config/rebase.txt b/Documentation/config/rebase.txt\nindex 9c248accec..7e5ec74e00 100644\n--- a/Documentation/config/rebase.txt\n+++ b/Documentation/config/rebase.txt\n@@ -9,7 +9,9 @@ rebase.stat::\n \trebase. False by default.\n \n rebase.autoSquash::\n-\tIf set to true enable `--autosquash` option by default.\n+\tWhen set to 'interactive' or 'true', enable the `--autosquash` option\n+\tfor interactive rebase. When set to 'always', enable it for\n+\tnon-interactive rebase as well. Defaults to 'false'.\n \n rebase.autoStash::\n \tWhen set to true, automatically create a temporary stash entry\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex e7b39ad244..102ff91493 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -592,7 +592,7 @@ See also INCOMPATIBLE OPTIONS below.\n \tWhen the commit log message begins with \"squash! ...\" or \"fixup! ...\"\n \tor \"amend! ...\", and there is already a commit in the todo list that\n \tmatches the same `...`, automatically modify the todo list of\n-\t`rebase -i`, so that the commit marked for squashing comes right after\n+\t`rebase`, so that the commit marked for squashing comes right after\n \tthe commit to be modified, and change the action of the moved commit\n \tfrom `pick` to `squash` or `fixup` or `fixup -C` respectively. A commit\n \tmatches the `...` if the commit subject matches, or if the `...` refers\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 261a9a61fc..35792744fc 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -85,6 +85,12 @@ static const char *action_names[] = {\n \t\"show_current_patch\"\n };\n \n+enum config_autosquash {\n+\tAUTOSQUASH_NO = 0,\n+\tAUTOSQUASH_INTERACTIVE = 1,\n+\tAUTOSQUASH_ALWAYS\n+};\n+\n struct rebase_options {\n \tenum rebase_type type;\n \tenum empty_type empty;\n@@ -131,7 +137,7 @@ struct rebase_options {\n \tint reapply_cherry_picks;\n \tint fork_point;\n \tint update_refs;\n-\tint config_autosquash;\n+\tenum config_autosquash config_autosquash;\n \tint config_rebase_merges;\n \tint config_update_refs;\n };\n@@ -149,7 +155,6 @@ struct rebase_options {\n \t\t.reapply_cherry_picks = -1,             \\\n \t\t.allow_empty_message = 1,               \\\n \t\t.autosquash = -1,                       \\\n-\t\t.config_autosquash = -1,                \\\n \t\t.rebase_merges = -1,                    \\\n \t\t.config_rebase_merges = -1,             \\\n \t\t.update_refs = -1,                      \\\n@@ -711,10 +716,8 @@ static int run_specific_rebase(struct rebase_options *opts)\n \tif (opts->type == REBASE_MERGE) {\n \t\t/* Run sequencer-based rebase */\n \t\tsetenv(\"GIT_CHERRY_PICK_HELP\", resolvemsg, 1);\n-\t\tif (!(opts->flags & REBASE_INTERACTIVE_EXPLICIT)) {\n+\t\tif (!(opts->flags & REBASE_INTERACTIVE_EXPLICIT))\n \t\t\tsetenv(\"GIT_SEQUENCE_EDITOR\", \":\", 1);\n-\t\t\topts->autosquash = 0;\n-\t\t}\n \t\tif (opts->gpg_sign_opt) {\n \t\t\t/* remove the leading \"-S\" */\n \t\t\tchar *tmp = xstrdup(opts->gpg_sign_opt + 2);\n@@ -772,7 +775,16 @@ static int rebase_config(const char *var, const char *value,\n \t}\n \n \tif (!strcmp(var, \"rebase.autosquash\")) {\n-\t\topts->config_autosquash = git_config_bool(var, value);\n+\t\tint b = git_parse_maybe_bool(value);\n+\n+\t\tif (b == 0)\n+\t\t\topts->config_autosquash = AUTOSQUASH_NO;\n+\t\telse if (b == 1 || !strcmp(value, \"interactive\"))\n+\t\t\topts->config_autosquash = AUTOSQUASH_INTERACTIVE;\n+\t\telse if (!strcmp(value, \"always\"))\n+\t\t\topts->config_autosquash = AUTOSQUASH_ALWAYS;\n+\t\telse\n+\t\t\tdie(_(\"invalid value for '%s': '%s'\"), var, value);\n \t\treturn 0;\n \t}\n \n@@ -1402,13 +1414,22 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t    state_dir_base, cmd_live_rebase, buf.buf);\n \t}\n \n+\tif (options.autosquash == 1) {\n+\t\timply_merge(&options, \"--autosquash\");\n+\t} else if (options.autosquash == -1) {\n+\t\toptions.autosquash =\n+\t\t\toptions.config_autosquash == AUTOSQUASH_ALWAYS ||\n+\t\t\t(options.config_autosquash == AUTOSQUASH_INTERACTIVE &&\n+\t\t\t options.flags & REBASE_INTERACTIVE_EXPLICIT);\n+\t}\n+\n \tif ((options.flags & REBASE_INTERACTIVE_EXPLICIT) ||\n \t    (options.action != ACTION_NONE) ||\n \t    (options.exec.nr > 0) ||\n-\t    (options.autosquash == -1 && options.config_autosquash == 1) ||\n-\t    options.autosquash == 1) {\n+\t    options.autosquash) {\n \t\tallow_preemptive_ff = 0;\n \t}\n+\n \tif (options.committer_date_is_author_date || options.ignore_date)\n \t\toptions.flags |= REBASE_FORCE;\n \n@@ -1508,7 +1529,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\tif (is_merge(&options))\n \t\t\t\tdie(_(\"apply options and merge options \"\n \t\t\t\t\t  \"cannot be used together\"));\n-\t\t\telse if (options.autosquash == -1 && options.config_autosquash == 1)\n+\t\t\telse if (options.autosquash && options.config_autosquash)\n \t\t\t\tdie(_(\"apply options are incompatible with rebase.autoSquash.  Consider adding --no-autosquash\"));\n \t\t\telse if (options.rebase_merges == -1 && options.config_rebase_merges == 1)\n \t\t\t\tdie(_(\"apply options are incompatible with rebase.rebaseMerges.  Consider adding --no-rebase-merges\"));\n@@ -1529,11 +1550,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \toptions.rebase_merges = (options.rebase_merges >= 0) ? options.rebase_merges :\n \t\t\t\t((options.config_rebase_merges >= 0) ? options.config_rebase_merges : 0);\n \n-\tif (options.autosquash == 1)\n-\t\timply_merge(&options, \"--autosquash\");\n-\toptions.autosquash = (options.autosquash >= 0) ? options.autosquash :\n-\t\t\t     ((options.config_autosquash >= 0) ? options.config_autosquash : 0);\n-\n \tif (options.type == REBASE_UNSPECIFIED) {\n \t\tif (!strcmp(options.default_backend, \"merge\"))\n \t\t\toptions.type = REBASE_MERGE;\n@@ -1858,3 +1874,4 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tfree(keep_base_onto_name);\n \treturn !!ret;\n }\n+\ndiff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh\nindex a364530d76..4b48414b3d 100755\n--- a/t/t3415-rebase-autosquash.sh\n+++ b/t/t3415-rebase-autosquash.sh\n@@ -43,7 +43,7 @@ test_auto_fixup () {\n \n \tgit tag $1 &&\n \ttest_tick &&\n-\tgit rebase $2 -i HEAD^^^ &&\n+\tgit rebase $2 HEAD^^^ &&\n \tgit log --oneline >actual &&\n \tif test -n \"$no_squash\"\n \tthen\n@@ -61,15 +61,36 @@ test_auto_fixup () {\n }\n \n test_expect_success 'auto fixup (option)' '\n-\ttest_auto_fixup final-fixup-option --autosquash\n+\ttest_auto_fixup fixup-option --autosquash &&\n+\ttest_auto_fixup fixup-option-i \"-i --autosquash\"\n '\n \n-test_expect_success 'auto fixup (config)' '\n-\tgit config rebase.autosquash true &&\n-\ttest_auto_fixup final-fixup-config-true &&\n-\ttest_auto_fixup ! fixup-config-true-no --no-autosquash &&\n+test_expect_success 'auto fixup (config false)' '\n \tgit config rebase.autosquash false &&\n-\ttest_auto_fixup ! final-fixup-config-false\n+\ttest_auto_fixup ! fixup-config-false &&\n+\ttest_auto_fixup ! fixup-config-false-i -i\n+'\n+\n+test_expect_success 'auto fixup (config true)' '\n+\tgit config rebase.autosquash true &&\n+\ttest_auto_fixup ! fixup-config-true &&\n+\ttest_auto_fixup fixup-config-true-i -i &&\n+\ttest_auto_fixup ! fixup-config-true-i-no \"-i --no-autosquash\"\n+'\n+\n+test_expect_success 'auto fixup (config interactive)' '\n+\tgit config rebase.autosquash interactive &&\n+\ttest_auto_fixup ! fixup-config-interactive &&\n+\ttest_auto_fixup fixup-config-interactive-i -i &&\n+\ttest_auto_fixup ! fixup-config-interactive-i-no \"-i --no-autosquash\"\n+'\n+\n+test_expect_success 'auto fixup (config always)' '\n+\tgit config rebase.autosquash always &&\n+\ttest_auto_fixup fixup-config-always &&\n+\ttest_auto_fixup fixup-config-always-i -i &&\n+\ttest_auto_fixup ! fixup-config-always-no --no-autosquash &&\n+\ttest_auto_fixup ! fixup-config-always-i-no \"-i --no-autosquash\"\n '\n \n test_auto_squash () {\n@@ -87,7 +108,7 @@ test_auto_squash () {\n \tgit commit -m \"squash! first\" -m \"extra para for first\" &&\n \tgit tag $1 &&\n \ttest_tick &&\n-\tgit rebase $2 -i HEAD^^^ &&\n+\tgit rebase $2 HEAD^^^ &&\n \tgit log --oneline >actual &&\n \tif test -n \"$no_squash\"\n \tthen\n@@ -105,15 +126,36 @@ test_auto_squash () {\n }\n \n test_expect_success 'auto squash (option)' '\n-\ttest_auto_squash final-squash --autosquash\n+\ttest_auto_squash squash-option --autosquash &&\n+\ttest_auto_squash squash-option-i \"-i --autosquash\"\n '\n \n-test_expect_success 'auto squash (config)' '\n-\tgit config rebase.autosquash true &&\n-\ttest_auto_squash final-squash-config-true &&\n-\ttest_auto_squash ! squash-config-true-no --no-autosquash &&\n+test_expect_success 'auto squash (config false)' '\n \tgit config rebase.autosquash false &&\n-\ttest_auto_squash ! final-squash-config-false\n+\ttest_auto_squash ! squash-config-false &&\n+\ttest_auto_squash ! squash-config-false-i -i\n+'\n+\n+test_expect_success 'auto squash (config true)' '\n+\tgit config rebase.autosquash true &&\n+\ttest_auto_squash ! squash-config-true &&\n+\ttest_auto_squash squash-config-true-i -i &&\n+\ttest_auto_squash ! squash-config-true-i-no \"-i --no-autosquash\"\n+'\n+\n+test_expect_success 'auto squash (config interactive)' '\n+\tgit config rebase.autosquash interactive &&\n+\ttest_auto_squash ! squash-config-interactive &&\n+\ttest_auto_squash squash-config-interactive-i -i &&\n+\ttest_auto_squash ! squash-config-interactive-i-no \"-i --no-autosquash\"\n+'\n+\n+test_expect_success 'auto squash (config always)' '\n+\tgit config rebase.autosquash always &&\n+\ttest_auto_squash squash-config-always &&\n+\ttest_auto_squash squash-config-always-i -i &&\n+\ttest_auto_squash ! squash-config-always-no --no-autosquash &&\n+\ttest_auto_squash ! squash-config-always-i-no \"-i --no-autosquash\"\n '\n \n test_expect_success 'misspelled auto squash' '\ndiff --git a/t/t3422-rebase-incompatible-options.sh b/t/t3422-rebase-incompatible-options.sh\nindex 2eba00bdf5..d9feb3a89d 100755\n--- a/t/t3422-rebase-incompatible-options.sh\n+++ b/t/t3422-rebase-incompatible-options.sh\n@@ -102,7 +102,7 @@ test_rebase_am_only () {\n \n \ttest_expect_success \"$opt incompatible with rebase.autosquash\" \"\n \t\tgit checkout B^0 &&\n-\t\ttest_must_fail git -c rebase.autosquash=true rebase $opt A 2>err &&\n+\t\ttest_must_fail git -c rebase.autosquash=always rebase $opt A 2>err &&\n \t\tgrep -e --no-autosquash err\n \t\"\n \n-- \n2.43.0-rc0\n\n"},{"id":"484421","messageId":"xmqqil6iiacq.fsf@gitster.g","threadId":"60469","inReplyTo":"20231103212958.18472-1-andy.koppe@gmail.com","subject":"Re: [PATCH 1/2] rebase: support non-interactive autosquash","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-11-04T01:19:17Z","receivedAt":"2023-11-04T01:19:23Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Andy Koppe <andy.koppe@gmail.com> writes:\n\n>  rebase.autoSquash::\n> -\tIf set to true enable `--autosquash` option by default.\n> +\tWhen set to 'interactive' or 'true', enable the `--autosquash` option\n> +\tfor interactive rebase. When set to 'always', enable it for\n> +\tnon-interactive rebase as well. Defaults to 'false'.\n\nI think a better and more extensible way to coax the new feature\ninto the configuration system is to arrange it more like so:\n\n    false\t  - synonym for \"\".\n    true\t  - synonym for \"interactive\".\n    anything else - comman separated list of rebase methods, e.g.,\n\t\t    \"interactive,noninteractive\"\n\n\t\t    possible rebase method names might include other\n\t\t    stuff like \"apply\" or \"merge\", but I haven't\n\t\t    thought it through, so take this part with a\n\t\t    grain of salt.\n\nThat way, the Boolean versions can be considered historical spelling\nof a more general system where you can exactly tell when autosquash\ntakes place.  When we add to a new variant on top of 'interactive'\nand 'non-interactive' variants the current rebase has, we do not\nknow if it makes sense to allow it to also handle autosquash without\nknowing how that new variant's behavior appears to the end user, so\n'always' that blindly enables autosquash for any unforseen future\nvariants of 'rebase' is probably not what you want.\n"},{"id":"484435","messageId":"20231104220330.14577-1-andy.koppe@gmail.com","threadId":"60469","inReplyTo":"20231103212958.18472-1-andy.koppe@gmail.com","subject":"[PATCH v2 1/2] rebase: support non-interactive autosquash","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-11-04T22:03:29Z","receivedAt":"2023-11-04T22:04:07Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"So far, the rebase --autosquash option and rebase.autoSquash=true\nconfig setting are quietly ignored when used without --interactive,\nexcept that they prevent fast-forward and that they trigger conflicts\nwith --apply and relatives, which is less than helpful particularly for\nthe config setting.\n\nSince the \"merge\" backend used for interactive rebase also is the\ndefault for non-interactive rebase, there doesn't appear to be a\nreason not to do --autosquash without --interactive, so support that.\n\nTurn rebase.autoSquash into a comma-separated list of flags, with\n\"interactive\" or \"i\" enabling auto-squashing with --interactive, and\n\"no-interactive\" or \"no-i\" enabling it without. Make boolean true mean\n\"interactive\" for backward compatibility.\n\nDon't prevent fast-forwards or report conflicts with --apply options\nwhen auto-squashing is not active.\n\nChange the git-rebase and config/rebase documentation accordingly, and\nextend t3415-rebase-autosquash.sh to test the new rebase.autosquash\nvalues and combinations with and without --interactive.\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n Documentation/config/rebase.txt        | 11 +++-\n Documentation/git-rebase.txt           |  2 +-\n builtin/rebase.c                       | 63 ++++++++++++++-----\n t/t3415-rebase-autosquash.sh           | 83 +++++++++++++++++++++-----\n t/t3422-rebase-incompatible-options.sh |  2 +-\n 5 files changed, 129 insertions(+), 32 deletions(-)\n\ndiff --git a/Documentation/config/rebase.txt b/Documentation/config/rebase.txt\nindex 9c248accec..68191e5673 100644\n--- a/Documentation/config/rebase.txt\n+++ b/Documentation/config/rebase.txt\n@@ -9,7 +9,16 @@ rebase.stat::\n \trebase. False by default.\n \n rebase.autoSquash::\n-\tIf set to true enable `--autosquash` option by default.\n+\tA comma-separated list of flags for when to enable auto-squashing.\n+\tSpecifying `interactive` or `i` enables auto-squashing for rebasing with\n+\t`--interactive`, whereas `no-interactive` or `no-i` enables it for\n+\trebasing without that option. For example, setting this to `i,no-i`\n+\tenables auto-squashing for both types. Setting it to true is equivalent\n+\tto setting it to `interactive`.\n+\n+\tThe `--autosquash` and `--no-autosquash` options of\n+\tlinkgit:git-rebase[1] override the setting here.\n+\tAuto-squashing is disabled by default.\n \n rebase.autoStash::\n \tWhen set to true, automatically create a temporary stash entry\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex e7b39ad244..102ff91493 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -592,7 +592,7 @@ See also INCOMPATIBLE OPTIONS below.\n \tWhen the commit log message begins with \"squash! ...\" or \"fixup! ...\"\n \tor \"amend! ...\", and there is already a commit in the todo list that\n \tmatches the same `...`, automatically modify the todo list of\n-\t`rebase -i`, so that the commit marked for squashing comes right after\n+\t`rebase`, so that the commit marked for squashing comes right after\n \tthe commit to be modified, and change the action of the moved commit\n \tfrom `pick` to `squash` or `fixup` or `fixup -C` respectively. A commit\n \tmatches the `...` if the commit subject matches, or if the `...` refers\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 261a9a61fc..0403c7415c 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -131,7 +131,10 @@ struct rebase_options {\n \tint reapply_cherry_picks;\n \tint fork_point;\n \tint update_refs;\n-\tint config_autosquash;\n+\tenum {\n+\t\tAUTOSQUASH_INTERACTIVE = 1 << 0,\n+\t\tAUTOSQUASH_NO_INTERACTIVE = 1 << 1,\n+\t} config_autosquash;\n \tint config_rebase_merges;\n \tint config_update_refs;\n };\n@@ -149,7 +152,6 @@ struct rebase_options {\n \t\t.reapply_cherry_picks = -1,             \\\n \t\t.allow_empty_message = 1,               \\\n \t\t.autosquash = -1,                       \\\n-\t\t.config_autosquash = -1,                \\\n \t\t.rebase_merges = -1,                    \\\n \t\t.config_rebase_merges = -1,             \\\n \t\t.update_refs = -1,                      \\\n@@ -711,10 +713,8 @@ static int run_specific_rebase(struct rebase_options *opts)\n \tif (opts->type == REBASE_MERGE) {\n \t\t/* Run sequencer-based rebase */\n \t\tsetenv(\"GIT_CHERRY_PICK_HELP\", resolvemsg, 1);\n-\t\tif (!(opts->flags & REBASE_INTERACTIVE_EXPLICIT)) {\n+\t\tif (!(opts->flags & REBASE_INTERACTIVE_EXPLICIT))\n \t\t\tsetenv(\"GIT_SEQUENCE_EDITOR\", \":\", 1);\n-\t\t\topts->autosquash = 0;\n-\t\t}\n \t\tif (opts->gpg_sign_opt) {\n \t\t\t/* remove the leading \"-S\" */\n \t\t\tchar *tmp = xstrdup(opts->gpg_sign_opt + 2);\n@@ -748,6 +748,27 @@ static int run_specific_rebase(struct rebase_options *opts)\n \treturn status ? -1 : 0;\n }\n \n+static void parse_rebase_autosquash_value(struct rebase_options *opts,\n+\t\t\t\t\t  const char *var, const char *value)\n+{\n+\tstruct string_list tokens = STRING_LIST_INIT_NODUP;\n+\tchar *buf = xstrdup(value);\n+\n+\topts->config_autosquash = 0;\n+\tstring_list_split_in_place(&tokens, buf, \",\", -1);\n+\n+\tfor (int i = 0; i < tokens.nr; i++) {\n+\t\tconst char *s = tokens.items[i].string;\n+\n+\t\tif (!strcmp(s, \"i\") || !strcmp(s, \"interactive\"))\n+\t\t\topts->config_autosquash |= AUTOSQUASH_INTERACTIVE;\n+\t\telse if (!strcmp(s, \"no-i\") || !strcmp(s, \"no-interactive\"))\n+\t\t\topts->config_autosquash |= AUTOSQUASH_NO_INTERACTIVE;\n+\t\telse\n+\t\t\tdie(_(\"invalid value for '%s': '%s'\"), var, s);\n+\t}\n+}\n+\n static void parse_rebase_merges_value(struct rebase_options *options, const char *value)\n {\n \tif (!strcmp(\"no-rebase-cousins\", value))\n@@ -772,8 +793,14 @@ static int rebase_config(const char *var, const char *value,\n \t}\n \n \tif (!strcmp(var, \"rebase.autosquash\")) {\n-\t\topts->config_autosquash = git_config_bool(var, value);\n-\t\treturn 0;\n+\t\tint b = git_parse_maybe_bool(value);\n+\n+\t\tif (b < 0)\n+\t\t\tparse_rebase_autosquash_value(opts, var, value);\n+\t\telse if (b)\n+\t\t\topts->config_autosquash = AUTOSQUASH_INTERACTIVE;\n+\t\telse\n+\t\t\topts->config_autosquash = 0;\n \t}\n \n \tif (!strcmp(var, \"commit.gpgsign\")) {\n@@ -1402,13 +1429,23 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t    state_dir_base, cmd_live_rebase, buf.buf);\n \t}\n \n+\tif (options.autosquash == 1) {\n+\t\timply_merge(&options, \"--autosquash\");\n+\t} else if (options.autosquash == -1) {\n+\t\tint conf = options.config_autosquash;\n+\t\toptions.autosquash =\n+\t\t\t(options.flags & REBASE_INTERACTIVE_EXPLICIT)\n+\t\t\t? !!(conf & AUTOSQUASH_INTERACTIVE)\n+\t\t\t: !!(conf & AUTOSQUASH_NO_INTERACTIVE);\n+\t}\n+\n \tif ((options.flags & REBASE_INTERACTIVE_EXPLICIT) ||\n \t    (options.action != ACTION_NONE) ||\n \t    (options.exec.nr > 0) ||\n-\t    (options.autosquash == -1 && options.config_autosquash == 1) ||\n-\t    options.autosquash == 1) {\n+\t    options.autosquash) {\n \t\tallow_preemptive_ff = 0;\n \t}\n+\n \tif (options.committer_date_is_author_date || options.ignore_date)\n \t\toptions.flags |= REBASE_FORCE;\n \n@@ -1508,7 +1545,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\tif (is_merge(&options))\n \t\t\t\tdie(_(\"apply options and merge options \"\n \t\t\t\t\t  \"cannot be used together\"));\n-\t\t\telse if (options.autosquash == -1 && options.config_autosquash == 1)\n+\t\t\telse if (options.autosquash && options.config_autosquash)\n \t\t\t\tdie(_(\"apply options are incompatible with rebase.autoSquash.  Consider adding --no-autosquash\"));\n \t\t\telse if (options.rebase_merges == -1 && options.config_rebase_merges == 1)\n \t\t\t\tdie(_(\"apply options are incompatible with rebase.rebaseMerges.  Consider adding --no-rebase-merges\"));\n@@ -1529,11 +1566,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \toptions.rebase_merges = (options.rebase_merges >= 0) ? options.rebase_merges :\n \t\t\t\t((options.config_rebase_merges >= 0) ? options.config_rebase_merges : 0);\n \n-\tif (options.autosquash == 1)\n-\t\timply_merge(&options, \"--autosquash\");\n-\toptions.autosquash = (options.autosquash >= 0) ? options.autosquash :\n-\t\t\t     ((options.config_autosquash >= 0) ? options.config_autosquash : 0);\n-\n \tif (options.type == REBASE_UNSPECIFIED) {\n \t\tif (!strcmp(options.default_backend, \"merge\"))\n \t\t\toptions.type = REBASE_MERGE;\n@@ -1858,3 +1890,4 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tfree(keep_base_onto_name);\n \treturn !!ret;\n }\n+\ndiff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh\nindex a364530d76..1386eb6394 100755\n--- a/t/t3415-rebase-autosquash.sh\n+++ b/t/t3415-rebase-autosquash.sh\n@@ -43,7 +43,7 @@ test_auto_fixup () {\n \n \tgit tag $1 &&\n \ttest_tick &&\n-\tgit rebase $2 -i HEAD^^^ &&\n+\tgit rebase $2 HEAD^^^ &&\n \tgit log --oneline >actual &&\n \tif test -n \"$no_squash\"\n \tthen\n@@ -61,15 +61,43 @@ test_auto_fixup () {\n }\n \n test_expect_success 'auto fixup (option)' '\n-\ttest_auto_fixup final-fixup-option --autosquash\n+\ttest_auto_fixup fixup-option --autosquash &&\n+\ttest_auto_fixup fixup-option-i \"-i --autosquash\"\n '\n \n-test_expect_success 'auto fixup (config)' '\n-\tgit config rebase.autosquash true &&\n-\ttest_auto_fixup final-fixup-config-true &&\n-\ttest_auto_fixup ! fixup-config-true-no --no-autosquash &&\n+test_expect_success 'auto fixup (config false)' '\n \tgit config rebase.autosquash false &&\n-\ttest_auto_fixup ! final-fixup-config-false\n+\ttest_auto_fixup ! fixup-config-false &&\n+\ttest_auto_fixup ! fixup-config-false-i -i\n+'\n+\n+test_expect_success 'auto fixup (config true)' '\n+\tgit config rebase.autosquash true &&\n+\ttest_auto_fixup ! fixup-config-true &&\n+\ttest_auto_fixup fixup-config-true-i -i &&\n+\ttest_auto_fixup ! fixup-config-true-i-no \"-i --no-autosquash\"\n+'\n+\n+test_expect_success 'auto fixup (config interactive)' '\n+\tgit config rebase.autosquash interactive &&\n+\ttest_auto_fixup ! fixup-config-interactive &&\n+\ttest_auto_fixup fixup-config-interactive-i -i &&\n+\ttest_auto_fixup ! fixup-config-interactive-i-no \"-i --no-autosquash\"\n+'\n+\n+test_expect_success 'auto fixup (config no-interactive)' '\n+\tgit config rebase.autosquash no-interactive &&\n+\ttest_auto_fixup fixup-config-no-interactive &&\n+\ttest_auto_fixup ! fixup-config-no-interactive-i -i &&\n+\ttest_auto_fixup ! fixup-config-no-interactive-no \"--no-autosquash\"\n+'\n+\n+test_expect_success 'auto fixup (config always)' '\n+\tgit config rebase.autosquash i,no-i &&\n+\ttest_auto_fixup fixup-config-always &&\n+\ttest_auto_fixup fixup-config-always-i -i &&\n+\ttest_auto_fixup ! fixup-config-always-no --no-autosquash &&\n+\ttest_auto_fixup ! fixup-config-always-i-no \"-i --no-autosquash\"\n '\n \n test_auto_squash () {\n@@ -87,7 +115,7 @@ test_auto_squash () {\n \tgit commit -m \"squash! first\" -m \"extra para for first\" &&\n \tgit tag $1 &&\n \ttest_tick &&\n-\tgit rebase $2 -i HEAD^^^ &&\n+\tgit rebase $2 HEAD^^^ &&\n \tgit log --oneline >actual &&\n \tif test -n \"$no_squash\"\n \tthen\n@@ -105,15 +133,42 @@ test_auto_squash () {\n }\n \n test_expect_success 'auto squash (option)' '\n-\ttest_auto_squash final-squash --autosquash\n+\ttest_auto_squash squash-option --autosquash &&\n+\ttest_auto_squash squash-option-i \"-i --autosquash\"\n '\n \n-test_expect_success 'auto squash (config)' '\n-\tgit config rebase.autosquash true &&\n-\ttest_auto_squash final-squash-config-true &&\n-\ttest_auto_squash ! squash-config-true-no --no-autosquash &&\n+test_expect_success 'auto squash (config false)' '\n \tgit config rebase.autosquash false &&\n-\ttest_auto_squash ! final-squash-config-false\n+\ttest_auto_squash ! squash-config-false &&\n+\ttest_auto_squash ! squash-config-false-i -i\n+'\n+\n+test_expect_success 'auto squash (config true)' '\n+\tgit config rebase.autosquash true &&\n+\ttest_auto_squash ! squash-config-true &&\n+\ttest_auto_squash squash-config-true-i -i &&\n+\ttest_auto_squash ! squash-config-true-i-no \"-i --no-autosquash\"\n+'\n+\n+test_expect_success 'auto squash (config interactive)' '\n+\tgit config rebase.autosquash i &&\n+\ttest_auto_squash ! squash-config-interactive &&\n+\ttest_auto_squash squash-config-interactive-i -i &&\n+\ttest_auto_squash ! squash-config-interactive-i-no \"-i --no-autosquash\"\n+'\n+\n+test_expect_success 'auto squash (config no-interactive)' '\n+\tgit config rebase.autosquash no-i &&\n+\ttest_auto_squash squash-config-no-interactive &&\n+\ttest_auto_squash ! squash-config-no-interactive-i -i &&\n+\ttest_auto_squash ! squash-config-no-interactive-no \"--no-autosquash\"\n+'\n+test_expect_success 'auto squash (config always)' '\n+\tgit config rebase.autosquash interactive,no-interactive &&\n+\ttest_auto_squash squash-config-always &&\n+\ttest_auto_squash squash-config-always-i -i &&\n+\ttest_auto_squash ! squash-config-always-no --no-autosquash &&\n+\ttest_auto_squash ! squash-config-always-i-no \"-i --no-autosquash\"\n '\n \n test_expect_success 'misspelled auto squash' '\ndiff --git a/t/t3422-rebase-incompatible-options.sh b/t/t3422-rebase-incompatible-options.sh\nindex 2eba00bdf5..e5119e7371 100755\n--- a/t/t3422-rebase-incompatible-options.sh\n+++ b/t/t3422-rebase-incompatible-options.sh\n@@ -102,7 +102,7 @@ test_rebase_am_only () {\n \n \ttest_expect_success \"$opt incompatible with rebase.autosquash\" \"\n \t\tgit checkout B^0 &&\n-\t\ttest_must_fail git -c rebase.autosquash=true rebase $opt A 2>err &&\n+\t\ttest_must_fail git -c rebase.autosquash=no-i rebase $opt A 2>err &&\n \t\tgrep -e --no-autosquash err\n \t\"\n \n-- \n2.43.0-rc0\n\n"},{"id":"484436","messageId":"20231104220330.14577-2-andy.koppe@gmail.com","threadId":"60469","inReplyTo":"20231104220330.14577-1-andy.koppe@gmail.com","subject":"[PATCH v2 2/2] docs: rewrite rebase --(no-)autosquash description","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-11-04T22:03:30Z","receivedAt":"2023-11-04T22:04:10Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"Rewrite the description of the rebase --(no-)autosquash options to try\nto make it a bit clearer. Don't use \"the '...'\" to refer to part of a\ncommit message, mention how --interactive can be used to review the\ntodo list, and add a bit more detail on commit --squash/amend.\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n Documentation/git-rebase.txt | 32 ++++++++++++++++++--------------\n 1 file changed, 18 insertions(+), 14 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex 102ff91493..594158fcbc 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -589,21 +589,25 @@ See also INCOMPATIBLE OPTIONS below.\n \n --autosquash::\n --no-autosquash::\n-\tWhen the commit log message begins with \"squash! ...\" or \"fixup! ...\"\n-\tor \"amend! ...\", and there is already a commit in the todo list that\n-\tmatches the same `...`, automatically modify the todo list of\n-\t`rebase`, so that the commit marked for squashing comes right after\n-\tthe commit to be modified, and change the action of the moved commit\n-\tfrom `pick` to `squash` or `fixup` or `fixup -C` respectively. A commit\n-\tmatches the `...` if the commit subject matches, or if the `...` refers\n-\tto the commit's hash. As a fall-back, partial matches of the commit\n-\tsubject work, too. The recommended way to create fixup/amend/squash\n-\tcommits is by using the `--fixup`, `--fixup=amend:` or `--fixup=reword:`\n-\tand `--squash` options respectively of linkgit:git-commit[1].\n+\tAutomatically squash commits with specially formatted messages into\n+\tprevious commits.  If a commit message starts with \"squash! \",\n+\t\"fixup! \" or \"amend! \", the remainder of the subject line is taken\n+\tas a commit specifier, which matches a previous commit if it matches\n+\tthe start of the subject line or the hash of that commit.\n +\n-If the `--autosquash` option is enabled by default using the\n-configuration variable `rebase.autoSquash`, this option can be\n-used to override and disable this setting.\n+In the rebase todo list, commits marked for squashing are moved right after\n+the commits they modify, and their action is changed from `pick` to `squash`,\n+`fixup` or `fixup -C`, depending on the squash marker.  The `--interactive`\n+option can be used to review and edit the todo list before proceeding.\n++\n+The recommended way to create commits with squash markers is by using the\n+`--squash`, `--fixup`, `--fixup=amend:` or `--fixup=reword:` options of\n+linkgit:git-commit[1], which take the target commit as an argument and\n+automatically fill in the subject line of the new commit from that.\n++\n+The configuration variable `rebase.autoSquash` can be used to enable\n+`--autosquash` by default.  See the CONFIGURATION section below for details.\n+The `--no-autosquash` option overrides that setting.\n +\n See also INCOMPATIBLE OPTIONS below.\n \n-- \n2.43.0-rc0\n\n"},{"id":"484437","messageId":"20531e2a-deb5-4bbf-93dc-a83648f59fca@gmail.com","threadId":"60469","inReplyTo":"xmqqil6iiacq.fsf@gitster.g","subject":"Re: [PATCH 1/2] rebase: support non-interactive autosquash","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-11-04T22:05:56Z","receivedAt":"2023-11-04T22:06:02Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"On 04/11/2023 01:19, Junio C Hamano wrote:\n> Andy Koppe <andy.koppe@gmail.com> writes:\n> \n>>   rebase.autoSquash::\n>> -\tIf set to true enable `--autosquash` option by default.\n>> +\tWhen set to 'interactive' or 'true', enable the `--autosquash` option\n>> +\tfor interactive rebase. When set to 'always', enable it for\n>> +\tnon-interactive rebase as well. Defaults to 'false'.\n> \n> I think a better and more extensible way to coax the new feature\n> into the configuration system is to arrange it more like so:\n> \n>      false\t  - synonym for \"\".\n>      true\t  - synonym for \"interactive\".\n>      anything else - comman separated list of rebase methods, e.g.,\n> \t\t    \"interactive,noninteractive\"\n> \n> \t\t    possible rebase method names might include other\n> \t\t    stuff like \"apply\" or \"merge\", but I haven't\n> \t\t    thought it through, so take this part with a\n> \t\t    grain of salt.\n> \n> That way, the Boolean versions can be considered historical spelling\n> of a more general system where you can exactly tell when autosquash\n> takes place.  When we add to a new variant on top of 'interactive'\n> and 'non-interactive' variants the current rebase has, we do not\n> know if it makes sense to allow it to also handle autosquash without\n> knowing how that new variant's behavior appears to the end user, so\n> 'always' that blindly enables autosquash for any unforseen future\n> variants of 'rebase' is probably not what you want.\n\nThanks, done in v2.\n\nAndy\n"},{"id":"484440","messageId":"20231105000808.10171-2-andy.koppe@gmail.com","threadId":"60469","inReplyTo":"20231105000808.10171-1-andy.koppe@gmail.com","subject":"[PATCH v3 2/2] docs: rewrite rebase --(no-)autosquash description","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-11-05T00:08:08Z","receivedAt":"2023-11-05T00:08:44Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"Rewrite the description of the rebase --(no-)autosquash options to try\nto make it a bit clearer. Don't use \"the '...'\" to refer to part of a\ncommit message, mention how --interactive can be used to review the\ntodo list, and add a bit more detail on commit --squash/amend.\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n Documentation/git-rebase.txt | 32 ++++++++++++++++++--------------\n 1 file changed, 18 insertions(+), 14 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex 102ff91493..594158fcbc 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -589,21 +589,25 @@ See also INCOMPATIBLE OPTIONS below.\n \n --autosquash::\n --no-autosquash::\n-\tWhen the commit log message begins with \"squash! ...\" or \"fixup! ...\"\n-\tor \"amend! ...\", and there is already a commit in the todo list that\n-\tmatches the same `...`, automatically modify the todo list of\n-\t`rebase`, so that the commit marked for squashing comes right after\n-\tthe commit to be modified, and change the action of the moved commit\n-\tfrom `pick` to `squash` or `fixup` or `fixup -C` respectively. A commit\n-\tmatches the `...` if the commit subject matches, or if the `...` refers\n-\tto the commit's hash. As a fall-back, partial matches of the commit\n-\tsubject work, too. The recommended way to create fixup/amend/squash\n-\tcommits is by using the `--fixup`, `--fixup=amend:` or `--fixup=reword:`\n-\tand `--squash` options respectively of linkgit:git-commit[1].\n+\tAutomatically squash commits with specially formatted messages into\n+\tprevious commits.  If a commit message starts with \"squash! \",\n+\t\"fixup! \" or \"amend! \", the remainder of the subject line is taken\n+\tas a commit specifier, which matches a previous commit if it matches\n+\tthe start of the subject line or the hash of that commit.\n +\n-If the `--autosquash` option is enabled by default using the\n-configuration variable `rebase.autoSquash`, this option can be\n-used to override and disable this setting.\n+In the rebase todo list, commits marked for squashing are moved right after\n+the commits they modify, and their action is changed from `pick` to `squash`,\n+`fixup` or `fixup -C`, depending on the squash marker.  The `--interactive`\n+option can be used to review and edit the todo list before proceeding.\n++\n+The recommended way to create commits with squash markers is by using the\n+`--squash`, `--fixup`, `--fixup=amend:` or `--fixup=reword:` options of\n+linkgit:git-commit[1], which take the target commit as an argument and\n+automatically fill in the subject line of the new commit from that.\n++\n+The configuration variable `rebase.autoSquash` can be used to enable\n+`--autosquash` by default.  See the CONFIGURATION section below for details.\n+The `--no-autosquash` option overrides that setting.\n +\n See also INCOMPATIBLE OPTIONS below.\n \n-- \n2.43.0-rc0\n\n"},{"id":"484441","messageId":"20231105000808.10171-1-andy.koppe@gmail.com","threadId":"60469","inReplyTo":"20231104220330.14577-1-andy.koppe@gmail.com","subject":"[PATCH v3 1/2] rebase: support non-interactive autosquash","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-11-05T00:08:07Z","receivedAt":"2023-11-05T00:08:44Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"So far, the rebase --autosquash option and rebase.autoSquash=true\nconfig setting are quietly ignored when used without --interactive,\nexcept that they prevent fast-forward and that they trigger conflicts\nwith --apply and relatives, which is less than helpful particularly for\nthe config setting.\n\nSince the \"merge\" backend used for interactive rebase also is the\ndefault for non-interactive rebase, there doesn't appear to be a\nreason not to do --autosquash without --interactive, so support that.\n\nTurn rebase.autoSquash into a comma-separated list of flags, with\n\"interactive\" or \"i\" enabling auto-squashing with --interactive, and\n\"no-interactive\" or \"no-i\" enabling it without. Make boolean true mean\n\"interactive\" for backward compatibility.\n\nDon't prevent fast-forwards or report conflicts with --apply options\nwhen auto-squashing is not active.\n\nChange the git-rebase and config/rebase documentation accordingly, and\nextend t3415-rebase-autosquash.sh to test the new rebase.autosquash\nvalues and combinations with and without --interactive.\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n Documentation/config/rebase.txt        | 11 +++-\n Documentation/git-rebase.txt           |  2 +-\n builtin/rebase.c                       | 66 +++++++++++++++-----\n t/t3415-rebase-autosquash.sh           | 83 +++++++++++++++++++++-----\n t/t3422-rebase-incompatible-options.sh |  2 +-\n 5 files changed, 132 insertions(+), 32 deletions(-)\n\ndiff --git a/Documentation/config/rebase.txt b/Documentation/config/rebase.txt\nindex 9c248accec..68191e5673 100644\n--- a/Documentation/config/rebase.txt\n+++ b/Documentation/config/rebase.txt\n@@ -9,7 +9,16 @@ rebase.stat::\n \trebase. False by default.\n \n rebase.autoSquash::\n-\tIf set to true enable `--autosquash` option by default.\n+\tA comma-separated list of flags for when to enable auto-squashing.\n+\tSpecifying `interactive` or `i` enables auto-squashing for rebasing with\n+\t`--interactive`, whereas `no-interactive` or `no-i` enables it for\n+\trebasing without that option. For example, setting this to `i,no-i`\n+\tenables auto-squashing for both types. Setting it to true is equivalent\n+\tto setting it to `interactive`.\n+\n+\tThe `--autosquash` and `--no-autosquash` options of\n+\tlinkgit:git-rebase[1] override the setting here.\n+\tAuto-squashing is disabled by default.\n \n rebase.autoStash::\n \tWhen set to true, automatically create a temporary stash entry\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex e7b39ad244..102ff91493 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -592,7 +592,7 @@ See also INCOMPATIBLE OPTIONS below.\n \tWhen the commit log message begins with \"squash! ...\" or \"fixup! ...\"\n \tor \"amend! ...\", and there is already a commit in the todo list that\n \tmatches the same `...`, automatically modify the todo list of\n-\t`rebase -i`, so that the commit marked for squashing comes right after\n+\t`rebase`, so that the commit marked for squashing comes right after\n \tthe commit to be modified, and change the action of the moved commit\n \tfrom `pick` to `squash` or `fixup` or `fixup -C` respectively. A commit\n \tmatches the `...` if the commit subject matches, or if the `...` refers\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 261a9a61fc..26c3e5dcb4 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -131,7 +131,10 @@ struct rebase_options {\n \tint reapply_cherry_picks;\n \tint fork_point;\n \tint update_refs;\n-\tint config_autosquash;\n+\tenum {\n+\t\tAUTOSQUASH_INTERACTIVE = 1 << 0,\n+\t\tAUTOSQUASH_NO_INTERACTIVE = 1 << 1,\n+\t} config_autosquash;\n \tint config_rebase_merges;\n \tint config_update_refs;\n };\n@@ -149,7 +152,6 @@ struct rebase_options {\n \t\t.reapply_cherry_picks = -1,             \\\n \t\t.allow_empty_message = 1,               \\\n \t\t.autosquash = -1,                       \\\n-\t\t.config_autosquash = -1,                \\\n \t\t.rebase_merges = -1,                    \\\n \t\t.config_rebase_merges = -1,             \\\n \t\t.update_refs = -1,                      \\\n@@ -711,10 +713,8 @@ static int run_specific_rebase(struct rebase_options *opts)\n \tif (opts->type == REBASE_MERGE) {\n \t\t/* Run sequencer-based rebase */\n \t\tsetenv(\"GIT_CHERRY_PICK_HELP\", resolvemsg, 1);\n-\t\tif (!(opts->flags & REBASE_INTERACTIVE_EXPLICIT)) {\n+\t\tif (!(opts->flags & REBASE_INTERACTIVE_EXPLICIT))\n \t\t\tsetenv(\"GIT_SEQUENCE_EDITOR\", \":\", 1);\n-\t\t\topts->autosquash = 0;\n-\t\t}\n \t\tif (opts->gpg_sign_opt) {\n \t\t\t/* remove the leading \"-S\" */\n \t\t\tchar *tmp = xstrdup(opts->gpg_sign_opt + 2);\n@@ -748,6 +748,30 @@ static int run_specific_rebase(struct rebase_options *opts)\n \treturn status ? -1 : 0;\n }\n \n+static void parse_rebase_autosquash_value(struct rebase_options *opts,\n+\t\t\t\t\t  const char *var, const char *value)\n+{\n+\tstruct string_list tokens = STRING_LIST_INIT_NODUP;\n+\tchar *buf = xstrdup(value);\n+\n+\topts->config_autosquash = 0;\n+\tstring_list_split_in_place(&tokens, buf, \",\", -1);\n+\n+\tfor (int i = 0; i < tokens.nr; i++) {\n+\t\tconst char *s = tokens.items[i].string;\n+\n+\t\tif (!strcmp(s, \"i\") || !strcmp(s, \"interactive\"))\n+\t\t\topts->config_autosquash |= AUTOSQUASH_INTERACTIVE;\n+\t\telse if (!strcmp(s, \"no-i\") || !strcmp(s, \"no-interactive\"))\n+\t\t\topts->config_autosquash |= AUTOSQUASH_NO_INTERACTIVE;\n+\t\telse\n+\t\t\tdie(_(\"invalid value for '%s': '%s'\"), var, s);\n+\t}\n+\n+\tstring_list_clear(&tokens, 0);\n+\tfree(buf);\n+}\n+\n static void parse_rebase_merges_value(struct rebase_options *options, const char *value)\n {\n \tif (!strcmp(\"no-rebase-cousins\", value))\n@@ -772,8 +796,14 @@ static int rebase_config(const char *var, const char *value,\n \t}\n \n \tif (!strcmp(var, \"rebase.autosquash\")) {\n-\t\topts->config_autosquash = git_config_bool(var, value);\n-\t\treturn 0;\n+\t\tint b = git_parse_maybe_bool(value);\n+\n+\t\tif (b < 0)\n+\t\t\tparse_rebase_autosquash_value(opts, var, value);\n+\t\telse if (b)\n+\t\t\topts->config_autosquash = AUTOSQUASH_INTERACTIVE;\n+\t\telse\n+\t\t\topts->config_autosquash = 0;\n \t}\n \n \tif (!strcmp(var, \"commit.gpgsign\")) {\n@@ -1402,13 +1432,23 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t    state_dir_base, cmd_live_rebase, buf.buf);\n \t}\n \n+\tif (options.autosquash == 1) {\n+\t\timply_merge(&options, \"--autosquash\");\n+\t} else if (options.autosquash == -1) {\n+\t\tint conf = options.config_autosquash;\n+\t\toptions.autosquash =\n+\t\t\t(options.flags & REBASE_INTERACTIVE_EXPLICIT)\n+\t\t\t? !!(conf & AUTOSQUASH_INTERACTIVE)\n+\t\t\t: !!(conf & AUTOSQUASH_NO_INTERACTIVE);\n+\t}\n+\n \tif ((options.flags & REBASE_INTERACTIVE_EXPLICIT) ||\n \t    (options.action != ACTION_NONE) ||\n \t    (options.exec.nr > 0) ||\n-\t    (options.autosquash == -1 && options.config_autosquash == 1) ||\n-\t    options.autosquash == 1) {\n+\t    options.autosquash) {\n \t\tallow_preemptive_ff = 0;\n \t}\n+\n \tif (options.committer_date_is_author_date || options.ignore_date)\n \t\toptions.flags |= REBASE_FORCE;\n \n@@ -1508,7 +1548,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\tif (is_merge(&options))\n \t\t\t\tdie(_(\"apply options and merge options \"\n \t\t\t\t\t  \"cannot be used together\"));\n-\t\t\telse if (options.autosquash == -1 && options.config_autosquash == 1)\n+\t\t\telse if (options.autosquash && options.config_autosquash)\n \t\t\t\tdie(_(\"apply options are incompatible with rebase.autoSquash.  Consider adding --no-autosquash\"));\n \t\t\telse if (options.rebase_merges == -1 && options.config_rebase_merges == 1)\n \t\t\t\tdie(_(\"apply options are incompatible with rebase.rebaseMerges.  Consider adding --no-rebase-merges\"));\n@@ -1529,11 +1569,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \toptions.rebase_merges = (options.rebase_merges >= 0) ? options.rebase_merges :\n \t\t\t\t((options.config_rebase_merges >= 0) ? options.config_rebase_merges : 0);\n \n-\tif (options.autosquash == 1)\n-\t\timply_merge(&options, \"--autosquash\");\n-\toptions.autosquash = (options.autosquash >= 0) ? options.autosquash :\n-\t\t\t     ((options.config_autosquash >= 0) ? options.config_autosquash : 0);\n-\n \tif (options.type == REBASE_UNSPECIFIED) {\n \t\tif (!strcmp(options.default_backend, \"merge\"))\n \t\t\toptions.type = REBASE_MERGE;\n@@ -1858,3 +1893,4 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tfree(keep_base_onto_name);\n \treturn !!ret;\n }\n+\ndiff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh\nindex a364530d76..1386eb6394 100755\n--- a/t/t3415-rebase-autosquash.sh\n+++ b/t/t3415-rebase-autosquash.sh\n@@ -43,7 +43,7 @@ test_auto_fixup () {\n \n \tgit tag $1 &&\n \ttest_tick &&\n-\tgit rebase $2 -i HEAD^^^ &&\n+\tgit rebase $2 HEAD^^^ &&\n \tgit log --oneline >actual &&\n \tif test -n \"$no_squash\"\n \tthen\n@@ -61,15 +61,43 @@ test_auto_fixup () {\n }\n \n test_expect_success 'auto fixup (option)' '\n-\ttest_auto_fixup final-fixup-option --autosquash\n+\ttest_auto_fixup fixup-option --autosquash &&\n+\ttest_auto_fixup fixup-option-i \"-i --autosquash\"\n '\n \n-test_expect_success 'auto fixup (config)' '\n-\tgit config rebase.autosquash true &&\n-\ttest_auto_fixup final-fixup-config-true &&\n-\ttest_auto_fixup ! fixup-config-true-no --no-autosquash &&\n+test_expect_success 'auto fixup (config false)' '\n \tgit config rebase.autosquash false &&\n-\ttest_auto_fixup ! final-fixup-config-false\n+\ttest_auto_fixup ! fixup-config-false &&\n+\ttest_auto_fixup ! fixup-config-false-i -i\n+'\n+\n+test_expect_success 'auto fixup (config true)' '\n+\tgit config rebase.autosquash true &&\n+\ttest_auto_fixup ! fixup-config-true &&\n+\ttest_auto_fixup fixup-config-true-i -i &&\n+\ttest_auto_fixup ! fixup-config-true-i-no \"-i --no-autosquash\"\n+'\n+\n+test_expect_success 'auto fixup (config interactive)' '\n+\tgit config rebase.autosquash interactive &&\n+\ttest_auto_fixup ! fixup-config-interactive &&\n+\ttest_auto_fixup fixup-config-interactive-i -i &&\n+\ttest_auto_fixup ! fixup-config-interactive-i-no \"-i --no-autosquash\"\n+'\n+\n+test_expect_success 'auto fixup (config no-interactive)' '\n+\tgit config rebase.autosquash no-interactive &&\n+\ttest_auto_fixup fixup-config-no-interactive &&\n+\ttest_auto_fixup ! fixup-config-no-interactive-i -i &&\n+\ttest_auto_fixup ! fixup-config-no-interactive-no \"--no-autosquash\"\n+'\n+\n+test_expect_success 'auto fixup (config always)' '\n+\tgit config rebase.autosquash i,no-i &&\n+\ttest_auto_fixup fixup-config-always &&\n+\ttest_auto_fixup fixup-config-always-i -i &&\n+\ttest_auto_fixup ! fixup-config-always-no --no-autosquash &&\n+\ttest_auto_fixup ! fixup-config-always-i-no \"-i --no-autosquash\"\n '\n \n test_auto_squash () {\n@@ -87,7 +115,7 @@ test_auto_squash () {\n \tgit commit -m \"squash! first\" -m \"extra para for first\" &&\n \tgit tag $1 &&\n \ttest_tick &&\n-\tgit rebase $2 -i HEAD^^^ &&\n+\tgit rebase $2 HEAD^^^ &&\n \tgit log --oneline >actual &&\n \tif test -n \"$no_squash\"\n \tthen\n@@ -105,15 +133,42 @@ test_auto_squash () {\n }\n \n test_expect_success 'auto squash (option)' '\n-\ttest_auto_squash final-squash --autosquash\n+\ttest_auto_squash squash-option --autosquash &&\n+\ttest_auto_squash squash-option-i \"-i --autosquash\"\n '\n \n-test_expect_success 'auto squash (config)' '\n-\tgit config rebase.autosquash true &&\n-\ttest_auto_squash final-squash-config-true &&\n-\ttest_auto_squash ! squash-config-true-no --no-autosquash &&\n+test_expect_success 'auto squash (config false)' '\n \tgit config rebase.autosquash false &&\n-\ttest_auto_squash ! final-squash-config-false\n+\ttest_auto_squash ! squash-config-false &&\n+\ttest_auto_squash ! squash-config-false-i -i\n+'\n+\n+test_expect_success 'auto squash (config true)' '\n+\tgit config rebase.autosquash true &&\n+\ttest_auto_squash ! squash-config-true &&\n+\ttest_auto_squash squash-config-true-i -i &&\n+\ttest_auto_squash ! squash-config-true-i-no \"-i --no-autosquash\"\n+'\n+\n+test_expect_success 'auto squash (config interactive)' '\n+\tgit config rebase.autosquash i &&\n+\ttest_auto_squash ! squash-config-interactive &&\n+\ttest_auto_squash squash-config-interactive-i -i &&\n+\ttest_auto_squash ! squash-config-interactive-i-no \"-i --no-autosquash\"\n+'\n+\n+test_expect_success 'auto squash (config no-interactive)' '\n+\tgit config rebase.autosquash no-i &&\n+\ttest_auto_squash squash-config-no-interactive &&\n+\ttest_auto_squash ! squash-config-no-interactive-i -i &&\n+\ttest_auto_squash ! squash-config-no-interactive-no \"--no-autosquash\"\n+'\n+test_expect_success 'auto squash (config always)' '\n+\tgit config rebase.autosquash interactive,no-interactive &&\n+\ttest_auto_squash squash-config-always &&\n+\ttest_auto_squash squash-config-always-i -i &&\n+\ttest_auto_squash ! squash-config-always-no --no-autosquash &&\n+\ttest_auto_squash ! squash-config-always-i-no \"-i --no-autosquash\"\n '\n \n test_expect_success 'misspelled auto squash' '\ndiff --git a/t/t3422-rebase-incompatible-options.sh b/t/t3422-rebase-incompatible-options.sh\nindex 2eba00bdf5..e5119e7371 100755\n--- a/t/t3422-rebase-incompatible-options.sh\n+++ b/t/t3422-rebase-incompatible-options.sh\n@@ -102,7 +102,7 @@ test_rebase_am_only () {\n \n \ttest_expect_success \"$opt incompatible with rebase.autosquash\" \"\n \t\tgit checkout B^0 &&\n-\t\ttest_must_fail git -c rebase.autosquash=true rebase $opt A 2>err &&\n+\t\ttest_must_fail git -c rebase.autosquash=no-i rebase $opt A 2>err &&\n \t\tgrep -e --no-autosquash err\n \t\"\n \n-- \n2.43.0-rc0\n\n"},{"id":"484446","messageId":"xmqqcywng0wu.fsf@gitster.g","threadId":"60469","inReplyTo":"20231104220330.14577-1-andy.koppe@gmail.com","subject":"Re: [PATCH v2 1/2] rebase: support non-interactive autosquash","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-11-06T00:50:41Z","receivedAt":"2023-11-06T00:50:48Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Andy Koppe <andy.koppe@gmail.com> writes:\n\n> So far, the rebase --autosquash option and rebase.autoSquash=true\n> config setting are quietly ignored when used without --interactive,\n> except that they prevent fast-forward and that they trigger conflicts\n> with --apply and relatives, which is less than helpful particularly for\n> the config setting.\n\nOK.  You do not explicitly say \"So far,\" by the way.  Our log\nmessage convention is to first describe what happens in the system\nin the present tense to illustrate why it is suboptimal, to prepare\nreaders' minds to anticipate the solution, which is described next.\n\n> Since the \"merge\" backend used for interactive rebase also is the\n> default for non-interactive rebase, there doesn't appear to be a\n> reason not to do --autosquash without --interactive, so support that.\n\nNice.\n\n> Turn rebase.autoSquash into a comma-separated list of flags, with\n> \"interactive\" or \"i\" enabling auto-squashing with --interactive, and\n> \"no-interactive\" or \"no-i\" enabling it without. Make boolean true mean\n> \"interactive\" for backward compatibility.\n\n\"i\" and \"no-i\" are questionable (will talk about them later), but\notherwise, nicely explained.\n\n> Don't prevent fast-forwards or report conflicts with --apply options\n> when auto-squashing is not active.\n>\n> Change the git-rebase and config/rebase documentation accordingly, and\n> extend t3415-rebase-autosquash.sh to test the new rebase.autosquash\n> values and combinations with and without --interactive.\n>\n> Signed-off-by: Andy Koppe <andy.koppe@gmail.com>\n> ---\n\nWhen asking reviews on a new iteration [PATCH v(N+1)], please\nsummarize the differences relative to [PATCH vN].  For explaining\nsuch incremental changes for individual patches, here between the\nthree-dash line and the diffstat is the place to do so.  When you\nhave a cover letter [PATCH 0/X], it can be done in that messaage.\nEither way is OK.  Doing both is also helpful as long as the\nexplanation done in two places do not contradict with each other.\n\n>  Documentation/config/rebase.txt        | 11 +++-\n>  Documentation/git-rebase.txt           |  2 +-\n>  builtin/rebase.c                       | 63 ++++++++++++++-----\n>  t/t3415-rebase-autosquash.sh           | 83 +++++++++++++++++++++-----\n>  t/t3422-rebase-incompatible-options.sh |  2 +-\n>  5 files changed, 129 insertions(+), 32 deletions(-)\n>\n> diff --git a/Documentation/config/rebase.txt b/Documentation/config/rebase.txt\n> index 9c248accec..68191e5673 100644\n> --- a/Documentation/config/rebase.txt\n> +++ b/Documentation/config/rebase.txt\n> @@ -9,7 +9,16 @@ rebase.stat::\n>  \trebase. False by default.\n>  \n>  rebase.autoSquash::\n> -\tIf set to true enable `--autosquash` option by default.\n> +\tA comma-separated list of flags for when to enable auto-squashing.\n> +\tSpecifying `interactive` or `i` enables auto-squashing for rebasing with\n> +\t`--interactive`, whereas `no-interactive` or `no-i` enables it for\n> +\trebasing without that option. For example, setting this to `i,no-i`\n> +\tenables auto-squashing for both types. Setting it to true is equivalent\n> +\tto setting it to `interactive`.\n> +\n> +\tThe `--autosquash` and `--no-autosquash` options of\n> +\tlinkgit:git-rebase[1] override the setting here.\n> +\tAuto-squashing is disabled by default.\n\nIf you trid to format the documentation before sending this patch,\nyou'd have seen the second paragraph formatted as if it were a code\nsnippet.  Dedent the second paragraph (and later ones if you had\nmore than one extra paragraphs), and turn the blank line between the\nparagraphs into a line with \"+\" (and nothing else) on it.  See the\ndescription of `--autosquash` option in Documentation/git-rebase.txt\nfor an example.\n\n> diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\n> index e7b39ad244..102ff91493 100644\n> --- a/Documentation/git-rebase.txt\n> +++ b/Documentation/git-rebase.txt\n> @@ -592,7 +592,7 @@ See also INCOMPATIBLE OPTIONS below.\n>  \tWhen the commit log message begins with \"squash! ...\" or \"fixup! ...\"\n>  \tor \"amend! ...\", and there is already a commit in the todo list that\n>  \tmatches the same `...`, automatically modify the todo list of\n> -\t`rebase -i`, so that the commit marked for squashing comes right after\n> +\t`rebase`, so that the commit marked for squashing comes right after\n>  \tthe commit to be modified, and change the action of the moved commit\n>  \tfrom `pick` to `squash` or `fixup` or `fixup -C` respectively. A commit\n>  \tmatches the `...` if the commit subject matches, or if the `...` refers\n> diff --git a/builtin/rebase.c b/builtin/rebase.c\n> index 261a9a61fc..0403c7415c 100644\n> --- a/builtin/rebase.c\n> +++ b/builtin/rebase.c\n> @@ -131,7 +131,10 @@ struct rebase_options {\n>  \tint reapply_cherry_picks;\n>  \tint fork_point;\n>  \tint update_refs;\n> -\tint config_autosquash;\n> +\tenum {\n> +\t\tAUTOSQUASH_INTERACTIVE = 1 << 0,\n> +\t\tAUTOSQUASH_NO_INTERACTIVE = 1 << 1,\n> +\t} config_autosquash;\n>  \tint config_rebase_merges;\n>  \tint config_update_refs;\n>  };\n> @@ -149,7 +152,6 @@ struct rebase_options {\n>  \t\t.reapply_cherry_picks = -1,             \\\n>  \t\t.allow_empty_message = 1,               \\\n>  \t\t.autosquash = -1,                       \\\n> -\t\t.config_autosquash = -1,                \\\n>  \t\t.rebase_merges = -1,                    \\\n>  \t\t.config_rebase_merges = -1,             \\\n>  \t\t.update_refs = -1,                      \\\n> @@ -711,10 +713,8 @@ static int run_specific_rebase(struct rebase_options *opts)\n>  \tif (opts->type == REBASE_MERGE) {\n>  \t\t/* Run sequencer-based rebase */\n>  \t\tsetenv(\"GIT_CHERRY_PICK_HELP\", resolvemsg, 1);\n> -\t\tif (!(opts->flags & REBASE_INTERACTIVE_EXPLICIT)) {\n> +\t\tif (!(opts->flags & REBASE_INTERACTIVE_EXPLICIT))\n>  \t\t\tsetenv(\"GIT_SEQUENCE_EDITOR\", \":\", 1);\n> -\t\t\topts->autosquash = 0;\n> -\t\t}\n>  \t\tif (opts->gpg_sign_opt) {\n>  \t\t\t/* remove the leading \"-S\" */\n>  \t\t\tchar *tmp = xstrdup(opts->gpg_sign_opt + 2);\n> @@ -748,6 +748,27 @@ static int run_specific_rebase(struct rebase_options *opts)\n>  \treturn status ? -1 : 0;\n>  }\n>  \n> +static void parse_rebase_autosquash_value(struct rebase_options *opts,\n> +\t\t\t\t\t  const char *var, const char *value)\n> +{\n> +\tstruct string_list tokens = STRING_LIST_INIT_NODUP;\n> +\tchar *buf = xstrdup(value);\n> +\n> +\topts->config_autosquash = 0;\n> +\tstring_list_split_in_place(&tokens, buf, \",\", -1);\n> +\n> +\tfor (int i = 0; i < tokens.nr; i++) {\n> +\t\tconst char *s = tokens.items[i].string;\n> +\n> +\t\tif (!strcmp(s, \"i\") || !strcmp(s, \"interactive\"))\n> +\t\t\topts->config_autosquash |= AUTOSQUASH_INTERACTIVE;\n> +\t\telse if (!strcmp(s, \"no-i\") || !strcmp(s, \"no-interactive\"))\n> +\t\t\topts->config_autosquash |= AUTOSQUASH_NO_INTERACTIVE;\n> +\t\telse\n> +\t\t\tdie(_(\"invalid value for '%s': '%s'\"), var, s);\n> +\t}\n> +}\n\nOK, by clearing opts->config_autosquash in this function, you keep\nthe rebase.autosquash to be \"the last one wins\" as a whole.  If a\nconfiguration file with lower precedence (e.g., /etc/gitconfig) says\n\"[rebase] autosquash\" to set it to \"interactive,no-interactive\", a\nseparate setting in your ~/.gitconfig \"[rebase] autosquash = false\"\nwould override both bits.\n\nA more involved design may let the users override these bits\nindependently by allowing something like \"!no-i\" (take whatever the\nlower precedence configuration file says for the interactive case,\nbut disable autosquash when running a non-interactive rebase) as the\nvalue, but I think the approach taken by this patch to allow replacing\nas a whole is OK.  It is simpler to explain.\n\nGiving short-hands for often used command line options is one thing,\nbut I do not think a short-hand is warranted here, especially when\nthe other one needs to be a less-than-half legible \"no-i\" that does\nnot allow \"no-int\" and friends, for configuration variable values.\nI'd strongly suggest dropping them.\n\nThanks.\n"},{"id":"484457","messageId":"8c2bb219-127c-4128-99ed-158bc64b1dab@gmail.com","threadId":"60469","inReplyTo":"20231105000808.10171-1-andy.koppe@gmail.com","subject":"Re: [PATCH v3 1/2] rebase: support non-interactive autosquash","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2023-11-06T11:06:03Z","receivedAt":"2023-11-06T11:06:10Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Andy\n\nOn 05/11/2023 00:08, Andy Koppe wrote:\n> So far, the rebase --autosquash option and rebase.autoSquash=true\n> config setting are quietly ignored when used without --interactive,\n\nThanks for working on this, I agree that \"--autosquash\" being ignored \nwithout \"--interactive\" is something that we should address. I think \nthere are several possible solutions\n\n1 - make \"--autosquash\" imply \"--interactive\". This has the advantage\n     that the user gets to check the commits are going to be reordered as\n     they expect when they edit the todo list. It is hard to see how to\n     accommodate the config setting though - I don't think we want\n     \"rebase.autosquash=true\" to imply \"--interactive\".\n\n2 - make \"--autosquash\" without \"--interactive\" an error. This would\n     prevent the user being surprised that their commits are not squashed\n     by a non-interactive rebase. Users who have set\n     \"rebase.autosquash=true\" would have to pass \"--no-autosquash\" to\n     perform any form of non-interactive rebase. This is similar to the\n     current behavior where the user has to pass \"--no-autosquash\" if\n     they want to use the apply backend with \"rebase.autosquash=true\".\n\n3 - make \"--autosquash\" rearrange and squash commits without\n     \"--interactive\". This is convenient but there is a risk in that the\n     user does not get a chance to check the todo list before the commits\n     are reordered and squashed. I think that risk is fairly small with\n     an explicit \"--autosquash\" on the commandline. This is the approach\n     taken by this patch. I do have some concerns about extending the\n     config setting to non-interactive rebases though. If the user has\n     commits that look like\n\n\tfixup! foo (HEAD)\n\tfoo bar\n\tfoo\n\n     and runs \"git -c rebase.autosquash=non-interactive rebase HEAD~2\"\n     then we'll silently squash the fixup into the wrong commit due to a\n     prefix subject match.\n\n> except that they prevent fast-forward and that they trigger conflicts\n> with --apply and relatives, which is less than helpful particularly for\n> the config setting.\n\nThe behavior to make the config setting incompatible with the apply \nbackend was implemented to avoid users being surprised that their \ncommits are not squashed by that backend even when they have set \n\"rebase.autosquash=true\"[1]. I think one could consider \"--autosquash\" \nbeing silently ignored without \"--interactive\" to be an oversight in \n796abac7e1 (rebase: add coverage of other incompatible options, \n2023-01-25) that introduced that change.\n\n[1] \nhttps://lore.kernel.org/git/pull.1466.v5.git.1674619434.gitgitgadget@gmail.com/\n\n> Since the \"merge\" backend used for interactive rebase also is the\n> default for non-interactive rebase, there doesn't appear to be a\n> reason not to do --autosquash without --interactive, so support that.\n\nI think making \"--autosquash\" on the commandline work for \nnon-interactive rebases is reasonable but I would be open to the \nargument that it would be better to make it an error and require \n\"--interactive\" to allow the user to check that the commits are going to \nbe reordered as they expect.\n\n> Turn rebase.autoSquash into a comma-separated list of flags, with\n> \"interactive\" or \"i\" enabling auto-squashing with --interactive, and\n> \"no-interactive\" or \"no-i\" enabling it without. Make boolean true mean\n> \"interactive\" for backward compatibility.\n\nPlease, please, please don't introduce abbreviated config settings, it \njust makes the interface more complicated. The user only has to set this \nonce so I think the short names just add confusion. I also think \n\"non-interactive\" would be a better name for the config setting \ncorresponding to non-interactive rebases. Does this mean the user can \nrequest that commits are only rearranged when the do not pass \n\"--interactive\"?\n\nAs I said above I do have some concerns that the \n\"rebase.autosquash=non-interactive\" setting will catch people out. \nHaving said that ignoring \"rebase.autosquash=true\" without \n\"--interactive\" as we do now is inconsistent with the behavior of \n\"rebase.autosquash=true\" with \"--apply\". One possibility would be to \nintroduce \"rebase.autosquash=interactive\" which would not cause an error \nwith \"--apply\" and always require an explicit \"--autosquash\" on the \ncommandline to squash fixups without \"--interactive\"\n\n> Don't prevent fast-forwards or report conflicts with --apply options\n> when auto-squashing is not active.\n\nI think this change deserves to be in a separate commit (which probably \nmeans separating out the config changes into that commit) as it is not \ndirectly related to fixing \"--autosquash\" without \"--interactive\" on the \ncommandline. It would revert 796abac7e1 (rebase: add coverage of other \nincompatible options, 2023-01-25) and part of eddfcd8ece (rebase: \nprovide better error message for apply options vs. merge config, \n2023-01-25) and so the commit message would need to explain why that is \ndesirable (and why it is desirable to revert only the changes related to \n\"rebase.autosquash\" and not those related to \"rebase.updateRefs\")\n\n> Change the git-rebase and config/rebase documentation accordingly, and\n> extend t3415-rebase-autosquash.sh to test the new rebase.autosquash\n> values and combinations with and without --interactive.\n\nThanks for adding tests for the new behavior.\n\nIn summary I like \"--autosquash\" working without \"--interactive\" but I'm \nunsure about the config changes.\n\nBest Wishes\n\nPhillip\n\n> Signed-off-by: Andy Koppe <andy.koppe@gmail.com>\n> ---\n>   Documentation/config/rebase.txt        | 11 +++-\n>   Documentation/git-rebase.txt           |  2 +-\n>   builtin/rebase.c                       | 66 +++++++++++++++-----\n>   t/t3415-rebase-autosquash.sh           | 83 +++++++++++++++++++++-----\n>   t/t3422-rebase-incompatible-options.sh |  2 +-\n>   5 files changed, 132 insertions(+), 32 deletions(-)\n> \n> diff --git a/Documentation/config/rebase.txt b/Documentation/config/rebase.txt\n> index 9c248accec..68191e5673 100644\n> --- a/Documentation/config/rebase.txt\n> +++ b/Documentation/config/rebase.txt\n> @@ -9,7 +9,16 @@ rebase.stat::\n>   \trebase. False by default.\n>   \n>   rebase.autoSquash::\n> -\tIf set to true enable `--autosquash` option by default.\n> +\tA comma-separated list of flags for when to enable auto-squashing.\n> +\tSpecifying `interactive` or `i` enables auto-squashing for rebasing with\n> +\t`--interactive`, whereas `no-interactive` or `no-i` enables it for\n> +\trebasing without that option. For example, setting this to `i,no-i`\n> +\tenables auto-squashing for both types. Setting it to true is equivalent\n> +\tto setting it to `interactive`.\n> +\n> +\tThe `--autosquash` and `--no-autosquash` options of\n> +\tlinkgit:git-rebase[1] override the setting here.\n> +\tAuto-squashing is disabled by default.\n>   \n>   rebase.autoStash::\n>   \tWhen set to true, automatically create a temporary stash entry\n> diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\n> index e7b39ad244..102ff91493 100644\n> --- a/Documentation/git-rebase.txt\n> +++ b/Documentation/git-rebase.txt\n> @@ -592,7 +592,7 @@ See also INCOMPATIBLE OPTIONS below.\n>   \tWhen the commit log message begins with \"squash! ...\" or \"fixup! ...\"\n>   \tor \"amend! ...\", and there is already a commit in the todo list that\n>   \tmatches the same `...`, automatically modify the todo list of\n> -\t`rebase -i`, so that the commit marked for squashing comes right after\n> +\t`rebase`, so that the commit marked for squashing comes right after\n>   \tthe commit to be modified, and change the action of the moved commit\n>   \tfrom `pick` to `squash` or `fixup` or `fixup -C` respectively. A commit\n>   \tmatches the `...` if the commit subject matches, or if the `...` refers\n> diff --git a/builtin/rebase.c b/builtin/rebase.c\n> index 261a9a61fc..26c3e5dcb4 100644\n> --- a/builtin/rebase.c\n> +++ b/builtin/rebase.c\n> @@ -131,7 +131,10 @@ struct rebase_options {\n>   \tint reapply_cherry_picks;\n>   \tint fork_point;\n>   \tint update_refs;\n> -\tint config_autosquash;\n> +\tenum {\n> +\t\tAUTOSQUASH_INTERACTIVE = 1 << 0,\n> +\t\tAUTOSQUASH_NO_INTERACTIVE = 1 << 1,\n> +\t} config_autosquash;\n>   \tint config_rebase_merges;\n>   \tint config_update_refs;\n>   };\n> @@ -149,7 +152,6 @@ struct rebase_options {\n>   \t\t.reapply_cherry_picks = -1,             \\\n>   \t\t.allow_empty_message = 1,               \\\n>   \t\t.autosquash = -1,                       \\\n> -\t\t.config_autosquash = -1,                \\\n>   \t\t.rebase_merges = -1,                    \\\n>   \t\t.config_rebase_merges = -1,             \\\n>   \t\t.update_refs = -1,                      \\\n> @@ -711,10 +713,8 @@ static int run_specific_rebase(struct rebase_options *opts)\n>   \tif (opts->type == REBASE_MERGE) {\n>   \t\t/* Run sequencer-based rebase */\n>   \t\tsetenv(\"GIT_CHERRY_PICK_HELP\", resolvemsg, 1);\n> -\t\tif (!(opts->flags & REBASE_INTERACTIVE_EXPLICIT)) {\n> +\t\tif (!(opts->flags & REBASE_INTERACTIVE_EXPLICIT))\n>   \t\t\tsetenv(\"GIT_SEQUENCE_EDITOR\", \":\", 1);\n> -\t\t\topts->autosquash = 0;\n> -\t\t}\n>   \t\tif (opts->gpg_sign_opt) {\n>   \t\t\t/* remove the leading \"-S\" */\n>   \t\t\tchar *tmp = xstrdup(opts->gpg_sign_opt + 2);\n> @@ -748,6 +748,30 @@ static int run_specific_rebase(struct rebase_options *opts)\n>   \treturn status ? -1 : 0;\n>   }\n>   \n> +static void parse_rebase_autosquash_value(struct rebase_options *opts,\n> +\t\t\t\t\t  const char *var, const char *value)\n> +{\n> +\tstruct string_list tokens = STRING_LIST_INIT_NODUP;\n> +\tchar *buf = xstrdup(value);\n> +\n> +\topts->config_autosquash = 0;\n> +\tstring_list_split_in_place(&tokens, buf, \",\", -1);\n> +\n> +\tfor (int i = 0; i < tokens.nr; i++) {\n> +\t\tconst char *s = tokens.items[i].string;\n> +\n> +\t\tif (!strcmp(s, \"i\") || !strcmp(s, \"interactive\"))\n> +\t\t\topts->config_autosquash |= AUTOSQUASH_INTERACTIVE;\n> +\t\telse if (!strcmp(s, \"no-i\") || !strcmp(s, \"no-interactive\"))\n> +\t\t\topts->config_autosquash |= AUTOSQUASH_NO_INTERACTIVE;\n> +\t\telse\n> +\t\t\tdie(_(\"invalid value for '%s': '%s'\"), var, s);\n> +\t}\n> +\n> +\tstring_list_clear(&tokens, 0);\n> +\tfree(buf);\n> +}\n> +\n>   static void parse_rebase_merges_value(struct rebase_options *options, const char *value)\n>   {\n>   \tif (!strcmp(\"no-rebase-cousins\", value))\n> @@ -772,8 +796,14 @@ static int rebase_config(const char *var, const char *value,\n>   \t}\n>   \n>   \tif (!strcmp(var, \"rebase.autosquash\")) {\n> -\t\topts->config_autosquash = git_config_bool(var, value);\n> -\t\treturn 0;\n> +\t\tint b = git_parse_maybe_bool(value);\n> +\n> +\t\tif (b < 0)\n> +\t\t\tparse_rebase_autosquash_value(opts, var, value);\n> +\t\telse if (b)\n> +\t\t\topts->config_autosquash = AUTOSQUASH_INTERACTIVE;\n> +\t\telse\n> +\t\t\topts->config_autosquash = 0;\n>   \t}\n>   \n>   \tif (!strcmp(var, \"commit.gpgsign\")) {\n> @@ -1402,13 +1432,23 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n>   \t\t    state_dir_base, cmd_live_rebase, buf.buf);\n>   \t}\n>   \n> +\tif (options.autosquash == 1) {\n> +\t\timply_merge(&options, \"--autosquash\");\n> +\t} else if (options.autosquash == -1) {\n> +\t\tint conf = options.config_autosquash;\n> +\t\toptions.autosquash =\n> +\t\t\t(options.flags & REBASE_INTERACTIVE_EXPLICIT)\n> +\t\t\t? !!(conf & AUTOSQUASH_INTERACTIVE)\n> +\t\t\t: !!(conf & AUTOSQUASH_NO_INTERACTIVE);\n> +\t}\n> +\n>   \tif ((options.flags & REBASE_INTERACTIVE_EXPLICIT) ||\n>   \t    (options.action != ACTION_NONE) ||\n>   \t    (options.exec.nr > 0) ||\n> -\t    (options.autosquash == -1 && options.config_autosquash == 1) ||\n> -\t    options.autosquash == 1) {\n> +\t    options.autosquash) {\n>   \t\tallow_preemptive_ff = 0;\n>   \t}\n> +\n>   \tif (options.committer_date_is_author_date || options.ignore_date)\n>   \t\toptions.flags |= REBASE_FORCE;\n>   \n> @@ -1508,7 +1548,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n>   \t\t\tif (is_merge(&options))\n>   \t\t\t\tdie(_(\"apply options and merge options \"\n>   \t\t\t\t\t  \"cannot be used together\"));\n> -\t\t\telse if (options.autosquash == -1 && options.config_autosquash == 1)\n> +\t\t\telse if (options.autosquash && options.config_autosquash)\n>   \t\t\t\tdie(_(\"apply options are incompatible with rebase.autoSquash.  Consider adding --no-autosquash\"));\n>   \t\t\telse if (options.rebase_merges == -1 && options.config_rebase_merges == 1)\n>   \t\t\t\tdie(_(\"apply options are incompatible with rebase.rebaseMerges.  Consider adding --no-rebase-merges\"));\n> @@ -1529,11 +1569,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n>   \toptions.rebase_merges = (options.rebase_merges >= 0) ? options.rebase_merges :\n>   \t\t\t\t((options.config_rebase_merges >= 0) ? options.config_rebase_merges : 0);\n>   \n> -\tif (options.autosquash == 1)\n> -\t\timply_merge(&options, \"--autosquash\");\n> -\toptions.autosquash = (options.autosquash >= 0) ? options.autosquash :\n> -\t\t\t     ((options.config_autosquash >= 0) ? options.config_autosquash : 0);\n> -\n>   \tif (options.type == REBASE_UNSPECIFIED) {\n>   \t\tif (!strcmp(options.default_backend, \"merge\"))\n>   \t\t\toptions.type = REBASE_MERGE;\n> @@ -1858,3 +1893,4 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n>   \tfree(keep_base_onto_name);\n>   \treturn !!ret;\n>   }\n> +\n> diff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh\n> index a364530d76..1386eb6394 100755\n> --- a/t/t3415-rebase-autosquash.sh\n> +++ b/t/t3415-rebase-autosquash.sh\n> @@ -43,7 +43,7 @@ test_auto_fixup () {\n>   \n>   \tgit tag $1 &&\n>   \ttest_tick &&\n> -\tgit rebase $2 -i HEAD^^^ &&\n> +\tgit rebase $2 HEAD^^^ &&\n>   \tgit log --oneline >actual &&\n>   \tif test -n \"$no_squash\"\n>   \tthen\n> @@ -61,15 +61,43 @@ test_auto_fixup () {\n>   }\n>   \n>   test_expect_success 'auto fixup (option)' '\n> -\ttest_auto_fixup final-fixup-option --autosquash\n> +\ttest_auto_fixup fixup-option --autosquash &&\n> +\ttest_auto_fixup fixup-option-i \"-i --autosquash\"\n>   '\n>   \n> -test_expect_success 'auto fixup (config)' '\n> -\tgit config rebase.autosquash true &&\n> -\ttest_auto_fixup final-fixup-config-true &&\n> -\ttest_auto_fixup ! fixup-config-true-no --no-autosquash &&\n> +test_expect_success 'auto fixup (config false)' '\n>   \tgit config rebase.autosquash false &&\n> -\ttest_auto_fixup ! final-fixup-config-false\n> +\ttest_auto_fixup ! fixup-config-false &&\n> +\ttest_auto_fixup ! fixup-config-false-i -i\n> +'\n> +\n> +test_expect_success 'auto fixup (config true)' '\n> +\tgit config rebase.autosquash true &&\n> +\ttest_auto_fixup ! fixup-config-true &&\n> +\ttest_auto_fixup fixup-config-true-i -i &&\n> +\ttest_auto_fixup ! fixup-config-true-i-no \"-i --no-autosquash\"\n> +'\n> +\n> +test_expect_success 'auto fixup (config interactive)' '\n> +\tgit config rebase.autosquash interactive &&\n> +\ttest_auto_fixup ! fixup-config-interactive &&\n> +\ttest_auto_fixup fixup-config-interactive-i -i &&\n> +\ttest_auto_fixup ! fixup-config-interactive-i-no \"-i --no-autosquash\"\n> +'\n> +\n> +test_expect_success 'auto fixup (config no-interactive)' '\n> +\tgit config rebase.autosquash no-interactive &&\n> +\ttest_auto_fixup fixup-config-no-interactive &&\n> +\ttest_auto_fixup ! fixup-config-no-interactive-i -i &&\n> +\ttest_auto_fixup ! fixup-config-no-interactive-no \"--no-autosquash\"\n> +'\n> +\n> +test_expect_success 'auto fixup (config always)' '\n> +\tgit config rebase.autosquash i,no-i &&\n> +\ttest_auto_fixup fixup-config-always &&\n> +\ttest_auto_fixup fixup-config-always-i -i &&\n> +\ttest_auto_fixup ! fixup-config-always-no --no-autosquash &&\n> +\ttest_auto_fixup ! fixup-config-always-i-no \"-i --no-autosquash\"\n>   '\n>   \n>   test_auto_squash () {\n> @@ -87,7 +115,7 @@ test_auto_squash () {\n>   \tgit commit -m \"squash! first\" -m \"extra para for first\" &&\n>   \tgit tag $1 &&\n>   \ttest_tick &&\n> -\tgit rebase $2 -i HEAD^^^ &&\n> +\tgit rebase $2 HEAD^^^ &&\n>   \tgit log --oneline >actual &&\n>   \tif test -n \"$no_squash\"\n>   \tthen\n> @@ -105,15 +133,42 @@ test_auto_squash () {\n>   }\n>   \n>   test_expect_success 'auto squash (option)' '\n> -\ttest_auto_squash final-squash --autosquash\n> +\ttest_auto_squash squash-option --autosquash &&\n> +\ttest_auto_squash squash-option-i \"-i --autosquash\"\n>   '\n>   \n> -test_expect_success 'auto squash (config)' '\n> -\tgit config rebase.autosquash true &&\n> -\ttest_auto_squash final-squash-config-true &&\n> -\ttest_auto_squash ! squash-config-true-no --no-autosquash &&\n> +test_expect_success 'auto squash (config false)' '\n>   \tgit config rebase.autosquash false &&\n> -\ttest_auto_squash ! final-squash-config-false\n> +\ttest_auto_squash ! squash-config-false &&\n> +\ttest_auto_squash ! squash-config-false-i -i\n> +'\n> +\n> +test_expect_success 'auto squash (config true)' '\n> +\tgit config rebase.autosquash true &&\n> +\ttest_auto_squash ! squash-config-true &&\n> +\ttest_auto_squash squash-config-true-i -i &&\n> +\ttest_auto_squash ! squash-config-true-i-no \"-i --no-autosquash\"\n> +'\n> +\n> +test_expect_success 'auto squash (config interactive)' '\n> +\tgit config rebase.autosquash i &&\n> +\ttest_auto_squash ! squash-config-interactive &&\n> +\ttest_auto_squash squash-config-interactive-i -i &&\n> +\ttest_auto_squash ! squash-config-interactive-i-no \"-i --no-autosquash\"\n> +'\n> +\n> +test_expect_success 'auto squash (config no-interactive)' '\n> +\tgit config rebase.autosquash no-i &&\n> +\ttest_auto_squash squash-config-no-interactive &&\n> +\ttest_auto_squash ! squash-config-no-interactive-i -i &&\n> +\ttest_auto_squash ! squash-config-no-interactive-no \"--no-autosquash\"\n> +'\n> +test_expect_success 'auto squash (config always)' '\n> +\tgit config rebase.autosquash interactive,no-interactive &&\n> +\ttest_auto_squash squash-config-always &&\n> +\ttest_auto_squash squash-config-always-i -i &&\n> +\ttest_auto_squash ! squash-config-always-no --no-autosquash &&\n> +\ttest_auto_squash ! squash-config-always-i-no \"-i --no-autosquash\"\n>   '\n>   \n>   test_expect_success 'misspelled auto squash' '\n> diff --git a/t/t3422-rebase-incompatible-options.sh b/t/t3422-rebase-incompatible-options.sh\n> index 2eba00bdf5..e5119e7371 100755\n> --- a/t/t3422-rebase-incompatible-options.sh\n> +++ b/t/t3422-rebase-incompatible-options.sh\n> @@ -102,7 +102,7 @@ test_rebase_am_only () {\n>   \n>   \ttest_expect_success \"$opt incompatible with rebase.autosquash\" \"\n>   \t\tgit checkout B^0 &&\n> -\t\ttest_must_fail git -c rebase.autosquash=true rebase $opt A 2>err &&\n> +\t\ttest_must_fail git -c rebase.autosquash=no-i rebase $opt A 2>err &&\n>   \t\tgrep -e --no-autosquash err\n>   \t\"\n>   \n"},{"id":"484458","messageId":"a4679ee0-b36f-441f-9350-b4c9c02f6e2d@gmail.com","threadId":"60469","inReplyTo":"20231105000808.10171-2-andy.koppe@gmail.com","subject":"Re: [PATCH v3 2/2] docs: rewrite rebase --(no-)autosquash description","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2023-11-06T11:07:16Z","receivedAt":"2023-11-06T11:07:28Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Andy\n\nOn 05/11/2023 00:08, Andy Koppe wrote:\n> Rewrite the description of the rebase --(no-)autosquash options to try\n> to make it a bit clearer. Don't use \"the '...'\" to refer to part of a\n> commit message,\n\nThanks for doing that, it is a definite improvement, I'm a bit concerned \nabout the loss of detail in other areas though - see below.\n\n> mention how --interactive can be used to review the\n> todo list, and add a bit more detail on commit --squash/amend.\n> \n> Signed-off-by: Andy Koppe <andy.koppe@gmail.com>\n> ---\n>   Documentation/git-rebase.txt | 32 ++++++++++++++++++--------------\n>   1 file changed, 18 insertions(+), 14 deletions(-)\n> \n> diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\n> index 102ff91493..594158fcbc 100644\n> --- a/Documentation/git-rebase.txt\n> +++ b/Documentation/git-rebase.txt\n> @@ -589,21 +589,25 @@ See also INCOMPATIBLE OPTIONS below.\n>   \n>   --autosquash::\n>   --no-autosquash::\n> -\tWhen the commit log message begins with \"squash! ...\" or \"fixup! ...\"\n> -\tor \"amend! ...\", and there is already a commit in the todo list that\n> -\tmatches the same `...`, automatically modify the todo list of\n> -\t`rebase`, so that the commit marked for squashing comes right after\n> -\tthe commit to be modified, and change the action of the moved commit\n> -\tfrom `pick` to `squash` or `fixup` or `fixup -C` respectively. A commit\n> -\tmatches the `...` if the commit subject matches, or if the `...` refers\n> -\tto the commit's hash. As a fall-back, partial matches of the commit\n> -\tsubject work, too. The recommended way to create fixup/amend/squash\n> -\tcommits is by using the `--fixup`, `--fixup=amend:` or `--fixup=reword:`\n> -\tand `--squash` options respectively of linkgit:git-commit[1].\n> +\tAutomatically squash commits with specially formatted messages into\n> +\tprevious commits.  If a commit message starts with \"squash! \",\n> +\t\"fixup! \" or \"amend! \", the remainder of the subject line is taken\n> +\tas a commit specifier,\n\nI like this change as I think saying \"remainder of the subject line\" is \nclearer than using `...`\n\n> which matches a previous commit if it matches\n> +\tthe start of the subject line or the hash of that commit.\n\nThis simplification glosses over some details, in particular it is no \nlonger clear we prefer an exact subject match to a prefix match so that\n\n\tpick 123 foo\n\tpick 456 foo bar\n\tpick 789 fixup! foo\n\nwill be re-arranged to\n\t\n\tpick 123 foo\n\tfixup 789 fixup! foo\n\tpick 456 foo bar\n\nand not\n\n\tpick 123 foo\n\tpick 456 foo bar\n\tfixup 789 fixup! foo\n\n>   +\n> -If the `--autosquash` option is enabled by default using the\n> -configuration variable `rebase.autoSquash`, this option can be\n> -used to override and disable this setting.\n> +In the rebase todo list, commits marked for squashing are moved right after\n> +the commits they modify, and their action is changed from `pick` to `squash`,\n> +`fixup` or `fixup -C`, depending on the squash marker.\n\nHere we have lost the documentation that told users which marker \ncorresponds to which action which is unfortunate.\n\nBest Wishes\n\nPhillip\n\n>  The `--interactive`\n> +option can be used to review and edit the todo list before proceeding.\n> ++\n> +The recommended way to create commits with squash markers is by using the\n> +`--squash`, `--fixup`, `--fixup=amend:` or `--fixup=reword:` options of\n> +linkgit:git-commit[1], which take the target commit as an argument and\n> +automatically fill in the subject line of the new commit from that.\n> ++\n> +The configuration variable `rebase.autoSquash` can be used to enable\n> +`--autosquash` by default.  See the CONFIGURATION section below for details.\n> +The `--no-autosquash` option overrides that setting.\n>   +\n>   See also INCOMPATIBLE OPTIONS below.\n>   \n"},{"id":"484752","messageId":"20231111132720.78877-1-andy.koppe@gmail.com","threadId":"60469","inReplyTo":"20231105000808.10171-1-andy.koppe@gmail.com","subject":"[PATCH v4 0/4] rebase: support --autosquash without -i","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-11-11T13:27:14Z","receivedAt":"2023-11-11T13:27:53Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"Make rebase --autosquash work without --interactive, but limit\nrebase.autoSquash's effects to interactive mode, and improve testing\nand documentation.\n\nChanges from v3:\n- Separate commits for rebase.autoSquash, --autosquash and testing.\n- Go back to interpreting rebase.autoSquash as a boolean, but document\n  it as only affecting interactive mode.\n- In the --autosquash documentation, bring back partial matching as a\n  fallback and show what todo list command each squash marker\n  corresponds to.\n\nThanks very much to Junio and Phillip for their reviews. I made plenty\nof use of non-interactive autosquash in preparing this version. :)\n\nAndy Koppe (4):\n  rebase: fully ignore rebase.autoSquash without -i\n  rebase: support --autosquash without -i\n  rebase: test autosquash with and without -i\n  rebase: rewrite --(no-)autosquash documentation\n\n Documentation/config/rebase.txt        |  4 ++-\n Documentation/git-rebase.txt           | 34 +++++++++++++----------\n builtin/rebase.c                       | 17 +++++-------\n t/t3415-rebase-autosquash.sh           | 38 +++++++++++++++++++-------\n t/t3422-rebase-incompatible-options.sh | 12 --------\n 5 files changed, 58 insertions(+), 47 deletions(-)\n\n-- \n2.43.0-rc1\n\n"},{"id":"484753","messageId":"20231111132720.78877-3-andy.koppe@gmail.com","threadId":"60469","inReplyTo":"20231111132720.78877-1-andy.koppe@gmail.com","subject":"[PATCH v4 2/4] rebase: support --autosquash without -i","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-11-11T13:27:16Z","receivedAt":"2023-11-11T13:27:54Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"The --autosquash option prevents preemptive fast-forwarding and triggers\nconflicts with amend backend options, yet it only actually performs\nauto-squashing when combined with the --interactive (or -i) option.\n\nRemove the latter restriction and tweak the --autosquash description\naccordingly.\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n Documentation/git-rebase.txt | 2 +-\n builtin/rebase.c             | 4 +---\n 2 files changed, 2 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex b4526ca246..10548e715c 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -592,7 +592,7 @@ See also INCOMPATIBLE OPTIONS below.\n \tWhen the commit log message begins with \"squash! ...\" or \"fixup! ...\"\n \tor \"amend! ...\", and there is already a commit in the todo list that\n \tmatches the same `...`, automatically modify the todo list of\n-\t`rebase -i`, so that the commit marked for squashing comes right after\n+\t`rebase`, so that the commit marked for squashing comes right after\n \tthe commit to be modified, and change the action of the moved commit\n \tfrom `pick` to `squash` or `fixup` or `fixup -C` respectively. A commit\n \tmatches the `...` if the commit subject matches, or if the `...` refers\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex a73de7892b..9f8192e0a5 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -710,10 +710,8 @@ static int run_specific_rebase(struct rebase_options *opts)\n \tif (opts->type == REBASE_MERGE) {\n \t\t/* Run sequencer-based rebase */\n \t\tsetenv(\"GIT_CHERRY_PICK_HELP\", resolvemsg, 1);\n-\t\tif (!(opts->flags & REBASE_INTERACTIVE_EXPLICIT)) {\n+\t\tif (!(opts->flags & REBASE_INTERACTIVE_EXPLICIT))\n \t\t\tsetenv(\"GIT_SEQUENCE_EDITOR\", \":\", 1);\n-\t\t\topts->autosquash = 0;\n-\t\t}\n \t\tif (opts->gpg_sign_opt) {\n \t\t\t/* remove the leading \"-S\" */\n \t\t\tchar *tmp = xstrdup(opts->gpg_sign_opt + 2);\n-- \n2.43.0-rc1\n\n"},{"id":"484754","messageId":"20231111132720.78877-2-andy.koppe@gmail.com","threadId":"60469","inReplyTo":"20231111132720.78877-1-andy.koppe@gmail.com","subject":"[PATCH v4 1/4] rebase: fully ignore rebase.autoSquash without -i","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-11-11T13:27:15Z","receivedAt":"2023-11-11T13:27:54Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"Setting the rebase.autoSquash config variable to true implies a couple\nof restrictions: it prevents preemptive fast-forwarding and it triggers\nconflicts with amend backend options. However, it only actually results\nin auto-squashing when combined with the --interactive (or -i) option,\ndue to code in run_specific_rebase() that disables auto-squashing unless\nthe REBASE_INTERACTIVE_EXPLICIT flag is set.\n\nDoing autosquashing for rebase.autoSquash without --interactive would be\nproblematic in terms of backward compatibility, but conversely, there is\nno need for the aforementioned restrictions without --interactive.\n\nSo drop the options.config_autosquash check from the conditions for\nclearing allow_preemptive_ff, as the case where it is combined with\n--interactive is already covered by the REBASE_INTERACTIVE_EXPLICIT\nflag check above it.\n\nAlso drop the \"apply options are incompatible with rebase.autoSquash\"\nerror, because it is unreachable if it is restricted to --interactive,\nas apply options already cause an error when used with --interactive.\nDrop the tests for the error from t3422-rebase-incompatible-options.sh,\nwhich has separate tests for the conflicts of --interactive with apply\noptions.\n\nWhen neither --autosquash nor --no-autosquash are given, only set\noptions.autosquash to true if rebase.autosquash is combined with\n--interactive.\n\nDon't initialize options.config_autosquash to -1, as there is no need to\ndistinguish between rebase.autoSquash being unset or explicitly set to\nfalse.\n\nFinally, amend the rebase.autoSquash documentation to say it only\naffects interactive mode.\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n Documentation/config/rebase.txt        |  4 +++-\n builtin/rebase.c                       | 13 ++++++-------\n t/t3422-rebase-incompatible-options.sh | 12 ------------\n 3 files changed, 9 insertions(+), 20 deletions(-)\n\ndiff --git a/Documentation/config/rebase.txt b/Documentation/config/rebase.txt\nindex 9c248accec..d59576dbb2 100644\n--- a/Documentation/config/rebase.txt\n+++ b/Documentation/config/rebase.txt\n@@ -9,7 +9,9 @@ rebase.stat::\n \trebase. False by default.\n \n rebase.autoSquash::\n-\tIf set to true enable `--autosquash` option by default.\n+\tIf set to true, enable the `--autosquash` option of\n+\tlinkgit:git-rebase[1] by default for interactive mode.\n+\tThis can be overridden with the `--no-autosquash` option.\n \n rebase.autoStash::\n \tWhen set to true, automatically create a temporary stash entry\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 043c65dccd..a73de7892b 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -149,7 +149,6 @@ struct rebase_options {\n \t\t.reapply_cherry_picks = -1,             \\\n \t\t.allow_empty_message = 1,               \\\n \t\t.autosquash = -1,                       \\\n-\t\t.config_autosquash = -1,                \\\n \t\t.rebase_merges = -1,                    \\\n \t\t.config_rebase_merges = -1,             \\\n \t\t.update_refs = -1,                      \\\n@@ -1405,7 +1404,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tif ((options.flags & REBASE_INTERACTIVE_EXPLICIT) ||\n \t    (options.action != ACTION_NONE) ||\n \t    (options.exec.nr > 0) ||\n-\t    (options.autosquash == -1 && options.config_autosquash == 1) ||\n \t    options.autosquash == 1) {\n \t\tallow_preemptive_ff = 0;\n \t}\n@@ -1508,8 +1506,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\tif (is_merge(&options))\n \t\t\t\tdie(_(\"apply options and merge options \"\n \t\t\t\t\t  \"cannot be used together\"));\n-\t\t\telse if (options.autosquash == -1 && options.config_autosquash == 1)\n-\t\t\t\tdie(_(\"apply options are incompatible with rebase.autoSquash.  Consider adding --no-autosquash\"));\n \t\t\telse if (options.rebase_merges == -1 && options.config_rebase_merges == 1)\n \t\t\t\tdie(_(\"apply options are incompatible with rebase.rebaseMerges.  Consider adding --no-rebase-merges\"));\n \t\t\telse if (options.update_refs == -1 && options.config_update_refs == 1)\n@@ -1529,10 +1525,13 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \toptions.rebase_merges = (options.rebase_merges >= 0) ? options.rebase_merges :\n \t\t\t\t((options.config_rebase_merges >= 0) ? options.config_rebase_merges : 0);\n \n-\tif (options.autosquash == 1)\n+\tif (options.autosquash == 1) {\n \t\timply_merge(&options, \"--autosquash\");\n-\toptions.autosquash = (options.autosquash >= 0) ? options.autosquash :\n-\t\t\t     ((options.config_autosquash >= 0) ? options.config_autosquash : 0);\n+\t} else if (options.autosquash == -1) {\n+\t\toptions.autosquash =\n+\t\t\toptions.config_autosquash &&\n+\t\t\t(options.flags & REBASE_INTERACTIVE_EXPLICIT);\n+\t}\n \n \tif (options.type == REBASE_UNSPECIFIED) {\n \t\tif (!strcmp(options.default_backend, \"merge\"))\ndiff --git a/t/t3422-rebase-incompatible-options.sh b/t/t3422-rebase-incompatible-options.sh\nindex 2eba00bdf5..b40f26250b 100755\n--- a/t/t3422-rebase-incompatible-options.sh\n+++ b/t/t3422-rebase-incompatible-options.sh\n@@ -100,12 +100,6 @@ test_rebase_am_only () {\n \t\ttest_must_fail git rebase $opt --root A\n \t\"\n \n-\ttest_expect_success \"$opt incompatible with rebase.autosquash\" \"\n-\t\tgit checkout B^0 &&\n-\t\ttest_must_fail git -c rebase.autosquash=true rebase $opt A 2>err &&\n-\t\tgrep -e --no-autosquash err\n-\t\"\n-\n \ttest_expect_success \"$opt incompatible with rebase.rebaseMerges\" \"\n \t\tgit checkout B^0 &&\n \t\ttest_must_fail git -c rebase.rebaseMerges=true rebase $opt A 2>err &&\n@@ -118,12 +112,6 @@ test_rebase_am_only () {\n \t\tgrep -e --no-update-refs err\n \t\"\n \n-\ttest_expect_success \"$opt okay with overridden rebase.autosquash\" \"\n-\t\ttest_when_finished \\\"git reset --hard B^0\\\" &&\n-\t\tgit checkout B^0 &&\n-\t\tgit -c rebase.autosquash=true rebase --no-autosquash $opt A\n-\t\"\n-\n \ttest_expect_success \"$opt okay with overridden rebase.rebaseMerges\" \"\n \t\ttest_when_finished \\\"git reset --hard B^0\\\" &&\n \t\tgit checkout B^0 &&\n-- \n2.43.0-rc1\n\n"},{"id":"484755","messageId":"20231111132720.78877-5-andy.koppe@gmail.com","threadId":"60469","inReplyTo":"20231111132720.78877-1-andy.koppe@gmail.com","subject":"[PATCH v4 4/4] docs: rewrite rebase --(no-)autosquash description","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-11-11T13:27:18Z","receivedAt":"2023-11-11T13:27:55Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"Rewrite the description of the rebase --(no-)autosquash options to try\nto make it a bit clearer. Don't use \"the '...'\" to refer to part of a\ncommit message, mention how --interactive can be used to review the\ntodo list, and add a bit more detail on commit --squash/amend.\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n Documentation/git-rebase.txt | 34 ++++++++++++++++++++--------------\n 1 file changed, 20 insertions(+), 14 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex 10548e715c..1dd6555f66 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -589,21 +589,27 @@ See also INCOMPATIBLE OPTIONS below.\n \n --autosquash::\n --no-autosquash::\n-\tWhen the commit log message begins with \"squash! ...\" or \"fixup! ...\"\n-\tor \"amend! ...\", and there is already a commit in the todo list that\n-\tmatches the same `...`, automatically modify the todo list of\n-\t`rebase`, so that the commit marked for squashing comes right after\n-\tthe commit to be modified, and change the action of the moved commit\n-\tfrom `pick` to `squash` or `fixup` or `fixup -C` respectively. A commit\n-\tmatches the `...` if the commit subject matches, or if the `...` refers\n-\tto the commit's hash. As a fall-back, partial matches of the commit\n-\tsubject work, too. The recommended way to create fixup/amend/squash\n-\tcommits is by using the `--fixup`, `--fixup=amend:` or `--fixup=reword:`\n-\tand `--squash` options respectively of linkgit:git-commit[1].\n+\tAutomatically squash commits with specially formatted messages into\n+\tprevious commits being rebased.  If a commit message starts with\n+\t\"squash! \", \"fixup! \" or \"amend! \", the remainder of the subject line\n+\tis taken as a commit specifier, which matches a previous commit if it\n+\tmatches the subject line or the hash of that commit.  If no commit\n+\tmatches fully, matches of the specifier with the start of commit\n+\tsubjects are considered.\n +\n-If the `--autosquash` option is enabled by default using the\n-configuration variable `rebase.autoSquash`, this option can be\n-used to override and disable this setting.\n+In the rebase todo list, the actions of squash, fixup and amend commits are\n+changed from `pick` to `squash`, `fixup` or `fixup -C`, respectively, and they\n+are moved right after the commit they modify.  The `--interactive` option can\n+be used to review and edit the todo list before proceeding.\n++\n+The recommended way to create commits with squash markers is by using the\n+`--squash`, `--fixup`, `--fixup=amend:` or `--fixup=reword:` options of\n+linkgit:git-commit[1], which take the target commit as an argument and\n+automatically fill in the subject line of the new commit from that.\n++\n+Settting configuration variable `rebase.autoSquash` to true enables\n+auto-squashing by default for interactive rebase.  The `--no-autosquash`\n+option can be used to override that setting.\n +\n See also INCOMPATIBLE OPTIONS below.\n \n-- \n2.43.0-rc1\n\n"},{"id":"484756","messageId":"20231111132720.78877-4-andy.koppe@gmail.com","threadId":"60469","inReplyTo":"20231111132720.78877-1-andy.koppe@gmail.com","subject":"[PATCH v4 3/4] rebase: test autosquash with and without -i","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-11-11T13:27:17Z","receivedAt":"2023-11-11T13:27:55Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"Amend t3415-rebase-autosquash.sh to test the --autosquash option and\nrebase.autoSquash config with and without -i.\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n t/t3415-rebase-autosquash.sh | 38 ++++++++++++++++++++++++++----------\n 1 file changed, 28 insertions(+), 10 deletions(-)\n\ndiff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh\nindex a364530d76..fcc40d6fe1 100755\n--- a/t/t3415-rebase-autosquash.sh\n+++ b/t/t3415-rebase-autosquash.sh\n@@ -43,7 +43,7 @@ test_auto_fixup () {\n \n \tgit tag $1 &&\n \ttest_tick &&\n-\tgit rebase $2 -i HEAD^^^ &&\n+\tgit rebase $2 HEAD^^^ &&\n \tgit log --oneline >actual &&\n \tif test -n \"$no_squash\"\n \tthen\n@@ -61,15 +61,24 @@ test_auto_fixup () {\n }\n \n test_expect_success 'auto fixup (option)' '\n-\ttest_auto_fixup final-fixup-option --autosquash\n+\ttest_auto_fixup fixup-option --autosquash &&\n+\ttest_auto_fixup fixup-option-i \"--autosquash -i\"\n '\n \n-test_expect_success 'auto fixup (config)' '\n+test_expect_success 'auto fixup (config true)' '\n \tgit config rebase.autosquash true &&\n-\ttest_auto_fixup final-fixup-config-true &&\n+\ttest_auto_fixup ! fixup-config-true &&\n+\ttest_auto_fixup fixup-config-true-i -i &&\n \ttest_auto_fixup ! fixup-config-true-no --no-autosquash &&\n+\ttest_auto_fixup ! fixup-config-true-i-no \"-i --no-autosquash\"\n+'\n+\n+test_expect_success 'auto fixup (config false)' '\n \tgit config rebase.autosquash false &&\n-\ttest_auto_fixup ! final-fixup-config-false\n+\ttest_auto_fixup ! fixup-config-false &&\n+\ttest_auto_fixup ! fixup-config-false-i -i &&\n+\ttest_auto_fixup fixup-config-false-yes --autosquash &&\n+\ttest_auto_fixup fixup-config-false-i-yes \"-i --autosquash\"\n '\n \n test_auto_squash () {\n@@ -87,7 +96,7 @@ test_auto_squash () {\n \tgit commit -m \"squash! first\" -m \"extra para for first\" &&\n \tgit tag $1 &&\n \ttest_tick &&\n-\tgit rebase $2 -i HEAD^^^ &&\n+\tgit rebase $2 HEAD^^^ &&\n \tgit log --oneline >actual &&\n \tif test -n \"$no_squash\"\n \tthen\n@@ -105,15 +114,24 @@ test_auto_squash () {\n }\n \n test_expect_success 'auto squash (option)' '\n-\ttest_auto_squash final-squash --autosquash\n+\ttest_auto_squash squash-option --autosquash &&\n+\ttest_auto_squash squash-option-i \"--autosquash -i\"\n '\n \n-test_expect_success 'auto squash (config)' '\n+test_expect_success 'auto squash (config true)' '\n \tgit config rebase.autosquash true &&\n-\ttest_auto_squash final-squash-config-true &&\n+\ttest_auto_squash ! squash-config-true &&\n+\ttest_auto_squash squash-config-true-i -i &&\n \ttest_auto_squash ! squash-config-true-no --no-autosquash &&\n+\ttest_auto_squash ! squash-config-true-i-no \"-i --no-autosquash\"\n+'\n+\n+test_expect_success 'auto squash (config false)' '\n \tgit config rebase.autosquash false &&\n-\ttest_auto_squash ! final-squash-config-false\n+\ttest_auto_squash ! squash-config-false &&\n+\ttest_auto_squash ! squash-config-false-i -i &&\n+\ttest_auto_squash squash-config-false-yes --autosquash &&\n+\ttest_auto_squash squash-config-false-i-yes \"-i --autosquash\"\n '\n \n test_expect_success 'misspelled auto squash' '\n-- \n2.43.0-rc1\n\n"},{"id":"484757","messageId":"20231111132720.78877-6-andy.koppe@gmail.com","threadId":"60469","inReplyTo":"20231111132720.78877-1-andy.koppe@gmail.com","subject":"[PATCH v4 4/4] rebase: rewrite --(no-)autosquash documentation","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-11-11T13:27:19Z","receivedAt":"2023-11-11T13:28:01Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"Rewrite the description of the rebase --(no-)autosquash options to try\nto make it a bit clearer. Don't use \"the '...'\" to refer to part of a\ncommit message, mention how --interactive can be used to review the\ntodo list, and add a bit more detail on commit --squash/amend.\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n Documentation/git-rebase.txt | 34 ++++++++++++++++++++--------------\n 1 file changed, 20 insertions(+), 14 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex 10548e715c..1dd6555f66 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -589,21 +589,27 @@ See also INCOMPATIBLE OPTIONS below.\n \n --autosquash::\n --no-autosquash::\n-\tWhen the commit log message begins with \"squash! ...\" or \"fixup! ...\"\n-\tor \"amend! ...\", and there is already a commit in the todo list that\n-\tmatches the same `...`, automatically modify the todo list of\n-\t`rebase`, so that the commit marked for squashing comes right after\n-\tthe commit to be modified, and change the action of the moved commit\n-\tfrom `pick` to `squash` or `fixup` or `fixup -C` respectively. A commit\n-\tmatches the `...` if the commit subject matches, or if the `...` refers\n-\tto the commit's hash. As a fall-back, partial matches of the commit\n-\tsubject work, too. The recommended way to create fixup/amend/squash\n-\tcommits is by using the `--fixup`, `--fixup=amend:` or `--fixup=reword:`\n-\tand `--squash` options respectively of linkgit:git-commit[1].\n+\tAutomatically squash commits with specially formatted messages into\n+\tprevious commits being rebased.  If a commit message starts with\n+\t\"squash! \", \"fixup! \" or \"amend! \", the remainder of the subject line\n+\tis taken as a commit specifier, which matches a previous commit if it\n+\tmatches the subject line or the hash of that commit.  If no commit\n+\tmatches fully, matches of the specifier with the start of commit\n+\tsubjects are considered.\n +\n-If the `--autosquash` option is enabled by default using the\n-configuration variable `rebase.autoSquash`, this option can be\n-used to override and disable this setting.\n+In the rebase todo list, the actions of squash, fixup and amend commits are\n+changed from `pick` to `squash`, `fixup` or `fixup -C`, respectively, and they\n+are moved right after the commit they modify.  The `--interactive` option can\n+be used to review and edit the todo list before proceeding.\n++\n+The recommended way to create commits with squash markers is by using the\n+`--squash`, `--fixup`, `--fixup=amend:` or `--fixup=reword:` options of\n+linkgit:git-commit[1], which take the target commit as an argument and\n+automatically fill in the subject line of the new commit from that.\n++\n+Settting configuration variable `rebase.autoSquash` to true enables\n+auto-squashing by default for interactive rebase.  The `--no-autosquash`\n+option can be used to override that setting.\n +\n See also INCOMPATIBLE OPTIONS below.\n \n-- \n2.43.0-rc1\n\n"},{"id":"484758","messageId":"1a05cc48-041a-4c1d-a980-8140d762eade@gmail.com","threadId":"60469","inReplyTo":"20231111132720.78877-5-andy.koppe@gmail.com","subject":"Re: [PATCH v4 4/4] docs: rewrite rebase --(no-)autosquash description","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-11-11T13:33:56Z","receivedAt":"2023-11-11T13:34:02Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"Disregard this one in favour of the other patch 4/4 please:\n\"[PATCH v4 4/4] rebase: rewrite --(no-)autosquash documentation\"\n\nSorry I failed to notice that I still had this lying around from the \nprevious iteration.\n\nOn 11/11/2023 13:27, Andy Koppe wrote:\n> Rewrite the description of the rebase --(no-)autosquash options to try\n> to make it a bit clearer. Don't use \"the '...'\" to refer to part of a\n> commit message, mention how --interactive can be used to review the\n> todo list, and add a bit more detail on commit --squash/amend.\n> \n> Signed-off-by: Andy Koppe <andy.koppe@gmail.com>\n> ---\n>   Documentation/git-rebase.txt | 34 ++++++++++++++++++++--------------\n>   1 file changed, 20 insertions(+), 14 deletions(-)\n> \n> diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\n> index 10548e715c..1dd6555f66 100644\n> --- a/Documentation/git-rebase.txt\n> +++ b/Documentation/git-rebase.txt\n> @@ -589,21 +589,27 @@ See also INCOMPATIBLE OPTIONS below.\n>   \n>   --autosquash::\n>   --no-autosquash::\n> -\tWhen the commit log message begins with \"squash! ...\" or \"fixup! ...\"\n> -\tor \"amend! ...\", and there is already a commit in the todo list that\n> -\tmatches the same `...`, automatically modify the todo list of\n> -\t`rebase`, so that the commit marked for squashing comes right after\n> -\tthe commit to be modified, and change the action of the moved commit\n> -\tfrom `pick` to `squash` or `fixup` or `fixup -C` respectively. A commit\n> -\tmatches the `...` if the commit subject matches, or if the `...` refers\n> -\tto the commit's hash. As a fall-back, partial matches of the commit\n> -\tsubject work, too. The recommended way to create fixup/amend/squash\n> -\tcommits is by using the `--fixup`, `--fixup=amend:` or `--fixup=reword:`\n> -\tand `--squash` options respectively of linkgit:git-commit[1].\n> +\tAutomatically squash commits with specially formatted messages into\n> +\tprevious commits being rebased.  If a commit message starts with\n> +\t\"squash! \", \"fixup! \" or \"amend! \", the remainder of the subject line\n> +\tis taken as a commit specifier, which matches a previous commit if it\n> +\tmatches the subject line or the hash of that commit.  If no commit\n> +\tmatches fully, matches of the specifier with the start of commit\n> +\tsubjects are considered.\n>   +\n> -If the `--autosquash` option is enabled by default using the\n> -configuration variable `rebase.autoSquash`, this option can be\n> -used to override and disable this setting.\n> +In the rebase todo list, the actions of squash, fixup and amend commits are\n> +changed from `pick` to `squash`, `fixup` or `fixup -C`, respectively, and they\n> +are moved right after the commit they modify.  The `--interactive` option can\n> +be used to review and edit the todo list before proceeding.\n> ++\n> +The recommended way to create commits with squash markers is by using the\n> +`--squash`, `--fixup`, `--fixup=amend:` or `--fixup=reword:` options of\n> +linkgit:git-commit[1], which take the target commit as an argument and\n> +automatically fill in the subject line of the new commit from that.\n> ++\n> +Settting configuration variable `rebase.autoSquash` to true enables\n> +auto-squashing by default for interactive rebase.  The `--no-autosquash`\n> +option can be used to override that setting.\n>   +\n>   See also INCOMPATIBLE OPTIONS below.\n>   \n"},{"id":"484759","messageId":"8dba0a09-d5bf-46b8-835b-9855f4f4326a@gmail.com","threadId":"60469","inReplyTo":"8c2bb219-127c-4128-99ed-158bc64b1dab@gmail.com","subject":"Re: [PATCH v3 1/2] rebase: support non-interactive autosquash","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-11-11T14:08:05Z","receivedAt":"2023-11-11T14:08:11Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"On 06/11/2023 11:06, Phillip Wood wrote:\n> On 05/11/2023 00:08, Andy Koppe wrote:\n>> So far, the rebase --autosquash option and rebase.autoSquash=true\n>> config setting are quietly ignored when used without --interactive,\n> \n> Thanks for working on this, I agree that \"--autosquash\" being ignored \n> without \"--interactive\" is something that we should address. I think \n> there are several possible solutions\n> \n> 1 - make \"--autosquash\" imply \"--interactive\". This has the advantage\n>      that the user gets to check the commits are going to be reordered as\n>      they expect when they edit the todo list. It is hard to see how to\n>      accommodate the config setting though - I don't think we want\n>      \"rebase.autosquash=true\" to imply \"--interactive\".\n> \n> 2 - make \"--autosquash\" without \"--interactive\" an error. This would\n>      prevent the user being surprised that their commits are not squashed\n>      by a non-interactive rebase. Users who have set\n>      \"rebase.autosquash=true\" would have to pass \"--no-autosquash\" to\n>      perform any form of non-interactive rebase. This is similar to the\n>      current behavior where the user has to pass \"--no-autosquash\" if\n>      they want to use the apply backend with \"rebase.autosquash=true\".\n> \n> 3 - make \"--autosquash\" rearrange and squash commits without\n>      \"--interactive\". This is convenient but there is a risk in that the\n>      user does not get a chance to check the todo list before the commits\n>      are reordered and squashed. I think that risk is fairly small with\n>      an explicit \"--autosquash\" on the commandline. This is the approach\n>      taken by this patch. I do have some concerns about extending the\n>      config setting to non-interactive rebases though. If the user has\n>      commits that look like\n> \n>      fixup! foo (HEAD)\n>      foo bar\n>      foo\n> \n>      and runs \"git -c rebase.autosquash=non-interactive rebase HEAD~2\"\n>      then we'll silently squash the fixup into the wrong commit due to a\n>      prefix subject match.\n\nGood analysis. My order of preference is 3 (obviously), 1, 2.\n\n>> except that they prevent fast-forward and that they trigger conflicts\n>> with --apply and relatives, which is less than helpful particularly for\n>> the config setting.\n> \n> The behavior to make the config setting incompatible with the apply \n> backend was implemented to avoid users being surprised that their \n> commits are not squashed by that backend even when they have set \n> \"rebase.autosquash=true\"[1]. I think one could consider \"--autosquash\" \n> being silently ignored without \"--interactive\" to be an oversight in \n> 796abac7e1 (rebase: add coverage of other incompatible options, \n> 2023-01-25) that introduced that change.\n> \n> [1] \n> https://lore.kernel.org/git/pull.1466.v5.git.1674619434.gitgitgadget@gmail.com/\n> \n>> Since the \"merge\" backend used for interactive rebase also is the\n>> default for non-interactive rebase, there doesn't appear to be a\n>> reason not to do --autosquash without --interactive, so support that.\n> \n> I think making \"--autosquash\" on the commandline work for \n> non-interactive rebases is reasonable but I would be open to the \n> argument that it would be better to make it an error and require \n> \"--interactive\" to allow the user to check that the commits are going to \n> be reordered as they expect.\n\nI found that once I got used to and started trusting the feature, \nparticularly in connection with the corresponding git-commit support, I \nno longer felt the need to check the todo list as I'd inspect the log \nafterwards anyway. And of course there's always resetting to ORIG_HEAD \nwhen things do go wrong.\n\nSo I think users should be trusted with this, especially as it's not a \nparticularly dangerous feature, given it requires the squash markers to \nbe present in the first place to do anything.\n\n>> Turn rebase.autoSquash into a comma-separated list of flags, with\n>> \"interactive\" or \"i\" enabling auto-squashing with --interactive, and\n>> \"no-interactive\" or \"no-i\" enabling it without. Make boolean true mean\n>> \"interactive\" for backward compatibility.\n> \n> Please, please, please don't introduce abbreviated config settings, it \n> just makes the interface more complicated. The user only has to set this \n> once so I think the short names just add confusion.\n\nDuly noted.\n\n> I also think \n> \"non-interactive\" would be a better name for the config setting \n> corresponding to non-interactive rebases. Does this mean the user can \n> request that commits are only rearranged when they do not pass \n> \"--interactive\"?\n\nYes. That doesn't seem useful.\n\n> As I said above I do have some concerns that the \n> \"rebase.autosquash=non-interactive\" setting will catch people out. \n\nI think you're right, so I've gone back to interpreting it as a boolean,\nbut officially make it affect interactive mode only.\n\n> Having said that ignoring \"rebase.autosquash=true\" without \n> \"--interactive\" as we do now is inconsistent with the behavior of \n> \"rebase.autosquash=true\" with \"--apply\". One possibility would be to \n> introduce \"rebase.autosquash=interactive\" which would not cause an error \n> with \"--apply\" and always require an explicit \"--autosquash\" on the \n> commandline to squash fixups without \"--interactive\"\n\nI don't think different error behaviour is worth a separate setting, as \nwe can't change rebase.autosquash=true to do auto-squashing without \n--interactive without surprising people.\n\n>> Don't prevent fast-forwards or report conflicts with --apply options\n>> when auto-squashing is not active.\n> \n> I think this change deserves to be in a separate commit (which probably \n> means separating out the config changes into that commit) as it is not \n> directly related to fixing \"--autosquash\" without \"--interactive\" on the \n> commandline.\n\nDone in v4.\n\n> In summary I like \"--autosquash\" working without \"--interactive\" but I'm \n> unsure about the config changes.\n\nThanks very much for the thoughtful review!\n\nRegards,\nAndy\n"},{"id":"484760","messageId":"307994aa-6a3d-41b8-86cb-c891abc13e52@gmail.com","threadId":"60469","inReplyTo":"xmqqcywng0wu.fsf@gitster.g","subject":"Re: [PATCH v2 1/2] rebase: support non-interactive autosquash","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-11-11T14:26:52Z","receivedAt":"2023-11-11T14:26:57Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"On 06/11/2023 00:50, Junio C Hamano wrote:\n> Andy Koppe <andy.koppe@gmail.com> writes:\n> Our log\n> message convention is to first describe what happens in the system\n> in the present tense to illustrate why it is suboptimal, to prepare\n> readers' minds to anticipate the solution, which is described next.\n> \n> When asking reviews on a new iteration [PATCH v(N+1)], please\n> summarize the differences relative to [PATCH vN].  For explaining\n> such incremental changes for individual patches, here between the\n> three-dash line and the diffstat is the place to do so.  When you\n> have a cover letter [PATCH 0/X], it can be done in that messaage.\n> Either way is OK.  Doing both is also helpful as long as the\n> explanation done in two places do not contradict with each other.\n\n> If you tried to format the documentation before sending this patch,\n> you'd have seen the second paragraph formatted as if it were a code\n> snippet.  Dedent the second paragraph (and later ones if you had\n> more than one extra paragraphs), and turn the blank line between the\n> paragraphs into a line with \"+\" (and nothing else) on it.  See the\n> description of `--autosquash` option in Documentation/git-rebase.txt\n> for an example.\n\nSad thing is that I knew most of that from reading the contribution \nguidelines and previous experience, but obviously I don't always \nremember. So thanks for you patience in re-explaining that.\n\n> OK, by clearing opts->config_autosquash in this function, you keep\n> the rebase.autosquash to be \"the last one wins\" as a whole.  If a\n> configuration file with lower precedence (e.g., /etc/gitconfig) says\n> \"[rebase] autosquash\" to set it to \"interactive,no-interactive\", a\n> separate setting in your ~/.gitconfig \"[rebase] autosquash = false\"\n> would override both bits.\n> \n> A more involved design may let the users override these bits\n> independently by allowing something like \"!no-i\" (take whatever the\n> lower precedence configuration file says for the interactive case,\n> but disable autosquash when running a non-interactive rebase) as the\n> value, but I think the approach taken by this patch to allow replacing\n> as a whole is OK.  It is simpler to explain.\n> \n> Giving short-hands for often used command line options is one thing,\n> but I do not think a short-hand is warranted here, especially when\n> the other one needs to be a less-than-half legible \"no-i\" that does\n> not allow \"no-int\" and friends, for configuration variable values.\n> I'd strongly suggest dropping them.\n\nDropped in v4, along with the attempt to expand rebase.autoSquash, \nfollowing Phillip's review.\n\nRegards,\nAndy\n"},{"id":"484780","messageId":"xmqqzfzila9n.fsf@gitster.g","threadId":"60469","inReplyTo":"20231111132720.78877-4-andy.koppe@gmail.com","subject":"Re: [PATCH v4 3/4] rebase: test autosquash with and without -i","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-11-13T01:20:04Z","receivedAt":"2023-11-13T01:20:09Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Andy Koppe <andy.koppe@gmail.com> writes:\n\n> Amend t3415-rebase-autosquash.sh to test the --autosquash option and\n> rebase.autoSquash config with and without -i.\n>\n> Signed-off-by: Andy Koppe <andy.koppe@gmail.com>\n> ---\n>  t/t3415-rebase-autosquash.sh | 38 ++++++++++++++++++++++++++----------\n>  1 file changed, 28 insertions(+), 10 deletions(-)\n>\n> diff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh\n> index a364530d76..fcc40d6fe1 100755\n> --- a/t/t3415-rebase-autosquash.sh\n> +++ b/t/t3415-rebase-autosquash.sh\n> @@ -43,7 +43,7 @@ test_auto_fixup () {\n>  \n>  \tgit tag $1 &&\n>  \ttest_tick &&\n> -\tgit rebase $2 -i HEAD^^^ &&\n> +\tgit rebase $2 HEAD^^^ &&\n>  \tgit log --oneline >actual &&\n>  \tif test -n \"$no_squash\"\n>  \tthen\n> @@ -61,15 +61,24 @@ test_auto_fixup () {\n>  }\n>  \n>  test_expect_success 'auto fixup (option)' '\n> -\ttest_auto_fixup final-fixup-option --autosquash\n> +\ttest_auto_fixup fixup-option --autosquash &&\n> +\ttest_auto_fixup fixup-option-i \"--autosquash -i\"\n>  '\n\nNice.  As test_auto_fixup (and test_auto_squash we see later) clears\nthe slate with \"git reset --hard base\" before it starts its work, it\nis easy to rerun them with and without \"-i\".\n"},{"id":"484781","messageId":"xmqqv8a6la6j.fsf@gitster.g","threadId":"60469","inReplyTo":"20231111132720.78877-6-andy.koppe@gmail.com","subject":"Re: [PATCH v4 4/4] rebase: rewrite --(no-)autosquash documentation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-11-13T01:21:56Z","receivedAt":"2023-11-13T01:21:59Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Andy Koppe <andy.koppe@gmail.com> writes:\n\n> +In the rebase todo list, the actions of squash, fixup and amend commits are\n> +changed from `pick` to `squash`, `fixup` or `fixup -C`, respectively, and they\n> +are moved right after the commit they modify.  The `--interactive` option can\n> +be used to review and edit the todo list before proceeding.\n\nOK, this is good---exactly what I was looking for while reviewing\nthe \"lose -i from the description\" step earlier in the series.\n\nNicely done.\n"},{"id":"484805","messageId":"7b2e35ee-716b-45c1-9570-643d2cfeeafd@gmail.com","threadId":"60469","inReplyTo":"20231111132720.78877-2-andy.koppe@gmail.com","subject":"Re: [PATCH v4 1/4] rebase: fully ignore rebase.autoSquash without -i","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2023-11-13T17:01:06Z","receivedAt":"2023-11-13T17:01:10Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Andy\n\nOn 11/11/2023 13:27, Andy Koppe wrote:\n> Setting the rebase.autoSquash config variable to true implies a couple\n> of restrictions: it prevents preemptive fast-forwarding and it triggers\n> conflicts with amend backend options. However, it only actually results\n> in auto-squashing when combined with the --interactive (or -i) option,\n> due to code in run_specific_rebase() that disables auto-squashing unless\n> the REBASE_INTERACTIVE_EXPLICIT flag is set.\n> \n> Doing autosquashing for rebase.autoSquash without --interactive would be\n> problematic in terms of backward compatibility, but conversely, there is\n> no need for the aforementioned restrictions without --interactive.\n> \n> So drop the options.config_autosquash check from the conditions for\n> clearing allow_preemptive_ff, as the case where it is combined with\n> --interactive is already covered by the REBASE_INTERACTIVE_EXPLICIT\n> flag check above it.\n> \n> Also drop the \"apply options are incompatible with rebase.autoSquash\"\n> error, because it is unreachable if it is restricted to --interactive,\n> as apply options already cause an error when used with --interactive.\n> Drop the tests for the error from t3422-rebase-incompatible-options.sh,\n> which has separate tests for the conflicts of --interactive with apply\n> options.\n> \n> When neither --autosquash nor --no-autosquash are given, only set\n> options.autosquash to true if rebase.autosquash is combined with\n> --interactive.\n> \n> Don't initialize options.config_autosquash to -1, as there is no need to\n> distinguish between rebase.autoSquash being unset or explicitly set to\n> false.\n> \n> Finally, amend the rebase.autoSquash documentation to say it only\n> affects interactive mode.\n\nThanks for the well reasoned explanation of the changes. I think \ndocumenting rebase.autosquash as only applying to interactive rebases is \na good way forward. The code changes all look sensible to me.\n\nBest Wishes\n\nPhillip\n\n> Signed-off-by: Andy Koppe <andy.koppe@gmail.com>\n> ---\n>   Documentation/config/rebase.txt        |  4 +++-\n>   builtin/rebase.c                       | 13 ++++++-------\n>   t/t3422-rebase-incompatible-options.sh | 12 ------------\n>   3 files changed, 9 insertions(+), 20 deletions(-)\n> \n> diff --git a/Documentation/config/rebase.txt b/Documentation/config/rebase.txt\n> index 9c248accec..d59576dbb2 100644\n> --- a/Documentation/config/rebase.txt\n> +++ b/Documentation/config/rebase.txt\n> @@ -9,7 +9,9 @@ rebase.stat::\n>   \trebase. False by default.\n>   \n>   rebase.autoSquash::\n> -\tIf set to true enable `--autosquash` option by default.\n> +\tIf set to true, enable the `--autosquash` option of\n> +\tlinkgit:git-rebase[1] by default for interactive mode.\n> +\tThis can be overridden with the `--no-autosquash` option.\n>   \n>   rebase.autoStash::\n>   \tWhen set to true, automatically create a temporary stash entry\n> diff --git a/builtin/rebase.c b/builtin/rebase.c\n> index 043c65dccd..a73de7892b 100644\n> --- a/builtin/rebase.c\n> +++ b/builtin/rebase.c\n> @@ -149,7 +149,6 @@ struct rebase_options {\n>   \t\t.reapply_cherry_picks = -1,             \\\n>   \t\t.allow_empty_message = 1,               \\\n>   \t\t.autosquash = -1,                       \\\n> -\t\t.config_autosquash = -1,                \\\n>   \t\t.rebase_merges = -1,                    \\\n>   \t\t.config_rebase_merges = -1,             \\\n>   \t\t.update_refs = -1,                      \\\n> @@ -1405,7 +1404,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n>   \tif ((options.flags & REBASE_INTERACTIVE_EXPLICIT) ||\n>   \t    (options.action != ACTION_NONE) ||\n>   \t    (options.exec.nr > 0) ||\n> -\t    (options.autosquash == -1 && options.config_autosquash == 1) ||\n>   \t    options.autosquash == 1) {\n>   \t\tallow_preemptive_ff = 0;\n>   \t}\n> @@ -1508,8 +1506,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n>   \t\t\tif (is_merge(&options))\n>   \t\t\t\tdie(_(\"apply options and merge options \"\n>   \t\t\t\t\t  \"cannot be used together\"));\n> -\t\t\telse if (options.autosquash == -1 && options.config_autosquash == 1)\n> -\t\t\t\tdie(_(\"apply options are incompatible with rebase.autoSquash.  Consider adding --no-autosquash\"));\n>   \t\t\telse if (options.rebase_merges == -1 && options.config_rebase_merges == 1)\n>   \t\t\t\tdie(_(\"apply options are incompatible with rebase.rebaseMerges.  Consider adding --no-rebase-merges\"));\n>   \t\t\telse if (options.update_refs == -1 && options.config_update_refs == 1)\n> @@ -1529,10 +1525,13 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n>   \toptions.rebase_merges = (options.rebase_merges >= 0) ? options.rebase_merges :\n>   \t\t\t\t((options.config_rebase_merges >= 0) ? options.config_rebase_merges : 0);\n>   \n> -\tif (options.autosquash == 1)\n> +\tif (options.autosquash == 1) {\n>   \t\timply_merge(&options, \"--autosquash\");\n> -\toptions.autosquash = (options.autosquash >= 0) ? options.autosquash :\n> -\t\t\t     ((options.config_autosquash >= 0) ? options.config_autosquash : 0);\n> +\t} else if (options.autosquash == -1) {\n> +\t\toptions.autosquash =\n> +\t\t\toptions.config_autosquash &&\n> +\t\t\t(options.flags & REBASE_INTERACTIVE_EXPLICIT);\n> +\t}\n>   \n>   \tif (options.type == REBASE_UNSPECIFIED) {\n>   \t\tif (!strcmp(options.default_backend, \"merge\"))\n> diff --git a/t/t3422-rebase-incompatible-options.sh b/t/t3422-rebase-incompatible-options.sh\n> index 2eba00bdf5..b40f26250b 100755\n> --- a/t/t3422-rebase-incompatible-options.sh\n> +++ b/t/t3422-rebase-incompatible-options.sh\n> @@ -100,12 +100,6 @@ test_rebase_am_only () {\n>   \t\ttest_must_fail git rebase $opt --root A\n>   \t\"\n>   \n> -\ttest_expect_success \"$opt incompatible with rebase.autosquash\" \"\n> -\t\tgit checkout B^0 &&\n> -\t\ttest_must_fail git -c rebase.autosquash=true rebase $opt A 2>err &&\n> -\t\tgrep -e --no-autosquash err\n> -\t\"\n> -\n>   \ttest_expect_success \"$opt incompatible with rebase.rebaseMerges\" \"\n>   \t\tgit checkout B^0 &&\n>   \t\ttest_must_fail git -c rebase.rebaseMerges=true rebase $opt A 2>err &&\n> @@ -118,12 +112,6 @@ test_rebase_am_only () {\n>   \t\tgrep -e --no-update-refs err\n>   \t\"\n>   \n> -\ttest_expect_success \"$opt okay with overridden rebase.autosquash\" \"\n> -\t\ttest_when_finished \\\"git reset --hard B^0\\\" &&\n> -\t\tgit checkout B^0 &&\n> -\t\tgit -c rebase.autosquash=true rebase --no-autosquash $opt A\n> -\t\"\n> -\n>   \ttest_expect_success \"$opt okay with overridden rebase.rebaseMerges\" \"\n>   \t\ttest_when_finished \\\"git reset --hard B^0\\\" &&\n>   \t\tgit checkout B^0 &&\n\n"},{"id":"484806","messageId":"058eb5d9-35d9-4452-8d33-d9cfebb94347@gmail.com","threadId":"60469","inReplyTo":"20231111132720.78877-3-andy.koppe@gmail.com","subject":"Re: [PATCH v4 2/4] rebase: support --autosquash without -i","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2023-11-13T17:01:16Z","receivedAt":"2023-11-13T17:01:20Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Andy\n\nOn 11/11/2023 13:27, Andy Koppe wrote:\n> The --autosquash option prevents preemptive fast-forwarding and triggers\n> conflicts with amend backend options,\n\n\"amend\" should be \"apply\". While this sentence is true I'm not quite \nsure how it relates to the change in this commit.\n\n> yet it only actually performs\n> auto-squashing when combined with the --interactive (or -i) option.\n> \n> Remove the latter restriction and tweak the --autosquash description\n> accordingly.\n\nThis seems like a reasonable change to me, thanks for working on it.\n\nBest Wishes\n\nPhillip\n\n> Signed-off-by: Andy Koppe <andy.koppe@gmail.com>\n> ---\n>   Documentation/git-rebase.txt | 2 +-\n>   builtin/rebase.c             | 4 +---\n>   2 files changed, 2 insertions(+), 4 deletions(-)\n> \n> diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\n> index b4526ca246..10548e715c 100644\n> --- a/Documentation/git-rebase.txt\n> +++ b/Documentation/git-rebase.txt\n> @@ -592,7 +592,7 @@ See also INCOMPATIBLE OPTIONS below.\n>   \tWhen the commit log message begins with \"squash! ...\" or \"fixup! ...\"\n>   \tor \"amend! ...\", and there is already a commit in the todo list that\n>   \tmatches the same `...`, automatically modify the todo list of\n> -\t`rebase -i`, so that the commit marked for squashing comes right after\n> +\t`rebase`, so that the commit marked for squashing comes right after\n>   \tthe commit to be modified, and change the action of the moved commit\n>   \tfrom `pick` to `squash` or `fixup` or `fixup -C` respectively. A commit\n>   \tmatches the `...` if the commit subject matches, or if the `...` refers\n> diff --git a/builtin/rebase.c b/builtin/rebase.c\n> index a73de7892b..9f8192e0a5 100644\n> --- a/builtin/rebase.c\n> +++ b/builtin/rebase.c\n> @@ -710,10 +710,8 @@ static int run_specific_rebase(struct rebase_options *opts)\n>   \tif (opts->type == REBASE_MERGE) {\n>   \t\t/* Run sequencer-based rebase */\n>   \t\tsetenv(\"GIT_CHERRY_PICK_HELP\", resolvemsg, 1);\n> -\t\tif (!(opts->flags & REBASE_INTERACTIVE_EXPLICIT)) {\n> +\t\tif (!(opts->flags & REBASE_INTERACTIVE_EXPLICIT))\n>   \t\t\tsetenv(\"GIT_SEQUENCE_EDITOR\", \":\", 1);\n> -\t\t\topts->autosquash = 0;\n> -\t\t}\n>   \t\tif (opts->gpg_sign_opt) {\n>   \t\t\t/* remove the leading \"-S\" */\n>   \t\t\tchar *tmp = xstrdup(opts->gpg_sign_opt + 2);\n\n"},{"id":"484807","messageId":"93f5b051-1449-475e-8b7a-a145485eee4f@gmail.com","threadId":"60469","inReplyTo":"20231111132720.78877-4-andy.koppe@gmail.com","subject":"Re: [PATCH v4 3/4] rebase: test autosquash with and without -i","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2023-11-13T17:02:13Z","receivedAt":"2023-11-13T17:02:20Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 11/11/2023 13:27, Andy Koppe wrote:\n> Amend t3415-rebase-autosquash.sh to test the --autosquash option and\n> rebase.autoSquash config with and without -i.\n\nThanks for adding these tests. I'd be happy to see this squashed into \nthe previous commit, though that is probably not worth a re-roll on its own.\n\nBest Wishes\n\nPhillip\n\n> Signed-off-by: Andy Koppe <andy.koppe@gmail.com>\n> ---\n>   t/t3415-rebase-autosquash.sh | 38 ++++++++++++++++++++++++++----------\n>   1 file changed, 28 insertions(+), 10 deletions(-)\n> \n> diff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh\n> index a364530d76..fcc40d6fe1 100755\n> --- a/t/t3415-rebase-autosquash.sh\n> +++ b/t/t3415-rebase-autosquash.sh\n> @@ -43,7 +43,7 @@ test_auto_fixup () {\n>   \n>   \tgit tag $1 &&\n>   \ttest_tick &&\n> -\tgit rebase $2 -i HEAD^^^ &&\n> +\tgit rebase $2 HEAD^^^ &&\n>   \tgit log --oneline >actual &&\n>   \tif test -n \"$no_squash\"\n>   \tthen\n> @@ -61,15 +61,24 @@ test_auto_fixup () {\n>   }\n>   \n>   test_expect_success 'auto fixup (option)' '\n> -\ttest_auto_fixup final-fixup-option --autosquash\n> +\ttest_auto_fixup fixup-option --autosquash &&\n> +\ttest_auto_fixup fixup-option-i \"--autosquash -i\"\n>   '\n>   \n> -test_expect_success 'auto fixup (config)' '\n> +test_expect_success 'auto fixup (config true)' '\n>   \tgit config rebase.autosquash true &&\n> -\ttest_auto_fixup final-fixup-config-true &&\n> +\ttest_auto_fixup ! fixup-config-true &&\n> +\ttest_auto_fixup fixup-config-true-i -i &&\n>   \ttest_auto_fixup ! fixup-config-true-no --no-autosquash &&\n> +\ttest_auto_fixup ! fixup-config-true-i-no \"-i --no-autosquash\"\n> +'\n> +\n> +test_expect_success 'auto fixup (config false)' '\n>   \tgit config rebase.autosquash false &&\n> -\ttest_auto_fixup ! final-fixup-config-false\n> +\ttest_auto_fixup ! fixup-config-false &&\n> +\ttest_auto_fixup ! fixup-config-false-i -i &&\n> +\ttest_auto_fixup fixup-config-false-yes --autosquash &&\n> +\ttest_auto_fixup fixup-config-false-i-yes \"-i --autosquash\"\n>   '\n>   \n>   test_auto_squash () {\n> @@ -87,7 +96,7 @@ test_auto_squash () {\n>   \tgit commit -m \"squash! first\" -m \"extra para for first\" &&\n>   \tgit tag $1 &&\n>   \ttest_tick &&\n> -\tgit rebase $2 -i HEAD^^^ &&\n> +\tgit rebase $2 HEAD^^^ &&\n>   \tgit log --oneline >actual &&\n>   \tif test -n \"$no_squash\"\n>   \tthen\n> @@ -105,15 +114,24 @@ test_auto_squash () {\n>   }\n>   \n>   test_expect_success 'auto squash (option)' '\n> -\ttest_auto_squash final-squash --autosquash\n> +\ttest_auto_squash squash-option --autosquash &&\n> +\ttest_auto_squash squash-option-i \"--autosquash -i\"\n>   '\n>   \n> -test_expect_success 'auto squash (config)' '\n> +test_expect_success 'auto squash (config true)' '\n>   \tgit config rebase.autosquash true &&\n> -\ttest_auto_squash final-squash-config-true &&\n> +\ttest_auto_squash ! squash-config-true &&\n> +\ttest_auto_squash squash-config-true-i -i &&\n>   \ttest_auto_squash ! squash-config-true-no --no-autosquash &&\n> +\ttest_auto_squash ! squash-config-true-i-no \"-i --no-autosquash\"\n> +'\n> +\n> +test_expect_success 'auto squash (config false)' '\n>   \tgit config rebase.autosquash false &&\n> -\ttest_auto_squash ! final-squash-config-false\n> +\ttest_auto_squash ! squash-config-false &&\n> +\ttest_auto_squash ! squash-config-false-i -i &&\n> +\ttest_auto_squash squash-config-false-yes --autosquash &&\n> +\ttest_auto_squash squash-config-false-i-yes \"-i --autosquash\"\n>   '\n>   \n>   test_expect_success 'misspelled auto squash' '\n\n"},{"id":"484808","messageId":"dac6405e-9b8d-40f5-9dda-b248a3548a42@gmail.com","threadId":"60469","inReplyTo":"20231111132720.78877-6-andy.koppe@gmail.com","subject":"Re: [PATCH v4 4/4] rebase: rewrite --(no-)autosquash documentation","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2023-11-13T17:02:20Z","receivedAt":"2023-11-13T17:02:24Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Andy\n\nOn 11/11/2023 13:27, Andy Koppe wrote:\n> Rewrite the description of the rebase --(no-)autosquash options to try\n> to make it a bit clearer. Don't use \"the '...'\" to refer to part of a\n> commit message, mention how --interactive can be used to review the\n> todo list, and add a bit more detail on commit --squash/amend.\n\nThis version looks good to me, thanks for working on it\n\nBest Wishes\n\nPhillip\n\n> Signed-off-by: Andy Koppe <andy.koppe@gmail.com>\n> ---\n>   Documentation/git-rebase.txt | 34 ++++++++++++++++++++--------------\n>   1 file changed, 20 insertions(+), 14 deletions(-)\n> \n> diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\n> index 10548e715c..1dd6555f66 100644\n> --- a/Documentation/git-rebase.txt\n> +++ b/Documentation/git-rebase.txt\n> @@ -589,21 +589,27 @@ See also INCOMPATIBLE OPTIONS below.\n>   \n>   --autosquash::\n>   --no-autosquash::\n> -\tWhen the commit log message begins with \"squash! ...\" or \"fixup! ...\"\n> -\tor \"amend! ...\", and there is already a commit in the todo list that\n> -\tmatches the same `...`, automatically modify the todo list of\n> -\t`rebase`, so that the commit marked for squashing comes right after\n> -\tthe commit to be modified, and change the action of the moved commit\n> -\tfrom `pick` to `squash` or `fixup` or `fixup -C` respectively. A commit\n> -\tmatches the `...` if the commit subject matches, or if the `...` refers\n> -\tto the commit's hash. As a fall-back, partial matches of the commit\n> -\tsubject work, too. The recommended way to create fixup/amend/squash\n> -\tcommits is by using the `--fixup`, `--fixup=amend:` or `--fixup=reword:`\n> -\tand `--squash` options respectively of linkgit:git-commit[1].\n> +\tAutomatically squash commits with specially formatted messages into\n> +\tprevious commits being rebased.  If a commit message starts with\n> +\t\"squash! \", \"fixup! \" or \"amend! \", the remainder of the subject line\n> +\tis taken as a commit specifier, which matches a previous commit if it\n> +\tmatches the subject line or the hash of that commit.  If no commit\n> +\tmatches fully, matches of the specifier with the start of commit\n> +\tsubjects are considered.\n>   +\n> -If the `--autosquash` option is enabled by default using the\n> -configuration variable `rebase.autoSquash`, this option can be\n> -used to override and disable this setting.\n> +In the rebase todo list, the actions of squash, fixup and amend commits are\n> +changed from `pick` to `squash`, `fixup` or `fixup -C`, respectively, and they\n> +are moved right after the commit they modify.  The `--interactive` option can\n> +be used to review and edit the todo list before proceeding.\n> ++\n> +The recommended way to create commits with squash markers is by using the\n> +`--squash`, `--fixup`, `--fixup=amend:` or `--fixup=reword:` options of\n> +linkgit:git-commit[1], which take the target commit as an argument and\n> +automatically fill in the subject line of the new commit from that.\n> ++\n> +Settting configuration variable `rebase.autoSquash` to true enables\n> +auto-squashing by default for interactive rebase.  The `--no-autosquash`\n> +option can be used to override that setting.\n>   +\n>   See also INCOMPATIBLE OPTIONS below.\n>   \n\n"},{"id":"484890","messageId":"20231114214339.10925-1-andy.koppe@gmail.com","threadId":"60469","inReplyTo":"20231111132720.78877-1-andy.koppe@gmail.com","subject":"[PATCH v5 0/3] rebase: support --autosquash without -i","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-11-14T21:43:36Z","receivedAt":"2023-11-14T21:44:26Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"Make rebase --autosquash work without --interactive, but limit\nrebase.autoSquash's effects to interactive mode, and improve testing\nand documentation.\n\nChanges from v4:\n- Fix amend vs apply backend thinko in commit messages.\n- Squash patch 3 for testing into patch 2 and improve the commit\n  message.\n- No source changes.\n\nThanks again to Junio and Phillip for their reviews.\n\nAndy Koppe (3):\n  rebase: fully ignore rebase.autoSquash without -i\n  rebase: support --autosquash without -i\n  rebase: rewrite --(no-)autosquash documentation\n\n Documentation/config/rebase.txt        |  4 ++-\n Documentation/git-rebase.txt           | 34 +++++++++++++----------\n builtin/rebase.c                       | 17 +++++-------\n t/t3415-rebase-autosquash.sh           | 38 +++++++++++++++++++-------\n t/t3422-rebase-incompatible-options.sh | 12 --------\n 5 files changed, 58 insertions(+), 47 deletions(-)\n\n-- \n2.43.0-rc2\n\n"},{"id":"484891","messageId":"20231114214339.10925-2-andy.koppe@gmail.com","threadId":"60469","inReplyTo":"20231114214339.10925-1-andy.koppe@gmail.com","subject":"[PATCH v5 1/3] rebase: fully ignore rebase.autoSquash without -i","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-11-14T21:43:37Z","receivedAt":"2023-11-14T21:44:30Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"Setting the rebase.autoSquash config variable to true implies a couple\nof restrictions: it prevents preemptive fast-forwarding and it triggers\nconflicts with apply backend options. However, it only actually results\nin auto-squashing when combined with the --interactive (or -i) option,\ndue to code in run_specific_rebase() that disables auto-squashing unless\nthe REBASE_INTERACTIVE_EXPLICIT flag is set.\n\nDoing autosquashing for rebase.autoSquash without --interactive would be\nproblematic in terms of backward compatibility, but conversely, there is\nno need for the aforementioned restrictions without --interactive.\n\nSo drop the options.config_autosquash check from the conditions for\nclearing allow_preemptive_ff, as the case where it is combined with\n--interactive is already covered by the REBASE_INTERACTIVE_EXPLICIT\nflag check above it.\n\nAlso drop the \"apply options are incompatible with rebase.autoSquash\"\nerror, because it is unreachable if it is restricted to --interactive,\nas apply options already cause an error when used with --interactive.\nDrop the tests for the error from t3422-rebase-incompatible-options.sh,\nwhich has separate tests for the conflicts of --interactive with apply\noptions.\n\nWhen neither --autosquash nor --no-autosquash are given, only set\noptions.autosquash to true if rebase.autosquash is combined with\n--interactive.\n\nDon't initialize options.config_autosquash to -1, as there is no need to\ndistinguish between rebase.autoSquash being unset or explicitly set to\nfalse.\n\nFinally, amend the rebase.autoSquash documentation to say it only\naffects interactive mode.\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n Documentation/config/rebase.txt        |  4 +++-\n builtin/rebase.c                       | 13 ++++++-------\n t/t3422-rebase-incompatible-options.sh | 12 ------------\n 3 files changed, 9 insertions(+), 20 deletions(-)\n\ndiff --git a/Documentation/config/rebase.txt b/Documentation/config/rebase.txt\nindex 9c248accec..d59576dbb2 100644\n--- a/Documentation/config/rebase.txt\n+++ b/Documentation/config/rebase.txt\n@@ -9,7 +9,9 @@ rebase.stat::\n \trebase. False by default.\n \n rebase.autoSquash::\n-\tIf set to true enable `--autosquash` option by default.\n+\tIf set to true, enable the `--autosquash` option of\n+\tlinkgit:git-rebase[1] by default for interactive mode.\n+\tThis can be overridden with the `--no-autosquash` option.\n \n rebase.autoStash::\n \tWhen set to true, automatically create a temporary stash entry\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 043c65dccd..a73de7892b 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -149,7 +149,6 @@ struct rebase_options {\n \t\t.reapply_cherry_picks = -1,             \\\n \t\t.allow_empty_message = 1,               \\\n \t\t.autosquash = -1,                       \\\n-\t\t.config_autosquash = -1,                \\\n \t\t.rebase_merges = -1,                    \\\n \t\t.config_rebase_merges = -1,             \\\n \t\t.update_refs = -1,                      \\\n@@ -1405,7 +1404,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tif ((options.flags & REBASE_INTERACTIVE_EXPLICIT) ||\n \t    (options.action != ACTION_NONE) ||\n \t    (options.exec.nr > 0) ||\n-\t    (options.autosquash == -1 && options.config_autosquash == 1) ||\n \t    options.autosquash == 1) {\n \t\tallow_preemptive_ff = 0;\n \t}\n@@ -1508,8 +1506,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\tif (is_merge(&options))\n \t\t\t\tdie(_(\"apply options and merge options \"\n \t\t\t\t\t  \"cannot be used together\"));\n-\t\t\telse if (options.autosquash == -1 && options.config_autosquash == 1)\n-\t\t\t\tdie(_(\"apply options are incompatible with rebase.autoSquash.  Consider adding --no-autosquash\"));\n \t\t\telse if (options.rebase_merges == -1 && options.config_rebase_merges == 1)\n \t\t\t\tdie(_(\"apply options are incompatible with rebase.rebaseMerges.  Consider adding --no-rebase-merges\"));\n \t\t\telse if (options.update_refs == -1 && options.config_update_refs == 1)\n@@ -1529,10 +1525,13 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \toptions.rebase_merges = (options.rebase_merges >= 0) ? options.rebase_merges :\n \t\t\t\t((options.config_rebase_merges >= 0) ? options.config_rebase_merges : 0);\n \n-\tif (options.autosquash == 1)\n+\tif (options.autosquash == 1) {\n \t\timply_merge(&options, \"--autosquash\");\n-\toptions.autosquash = (options.autosquash >= 0) ? options.autosquash :\n-\t\t\t     ((options.config_autosquash >= 0) ? options.config_autosquash : 0);\n+\t} else if (options.autosquash == -1) {\n+\t\toptions.autosquash =\n+\t\t\toptions.config_autosquash &&\n+\t\t\t(options.flags & REBASE_INTERACTIVE_EXPLICIT);\n+\t}\n \n \tif (options.type == REBASE_UNSPECIFIED) {\n \t\tif (!strcmp(options.default_backend, \"merge\"))\ndiff --git a/t/t3422-rebase-incompatible-options.sh b/t/t3422-rebase-incompatible-options.sh\nindex 2eba00bdf5..b40f26250b 100755\n--- a/t/t3422-rebase-incompatible-options.sh\n+++ b/t/t3422-rebase-incompatible-options.sh\n@@ -100,12 +100,6 @@ test_rebase_am_only () {\n \t\ttest_must_fail git rebase $opt --root A\n \t\"\n \n-\ttest_expect_success \"$opt incompatible with rebase.autosquash\" \"\n-\t\tgit checkout B^0 &&\n-\t\ttest_must_fail git -c rebase.autosquash=true rebase $opt A 2>err &&\n-\t\tgrep -e --no-autosquash err\n-\t\"\n-\n \ttest_expect_success \"$opt incompatible with rebase.rebaseMerges\" \"\n \t\tgit checkout B^0 &&\n \t\ttest_must_fail git -c rebase.rebaseMerges=true rebase $opt A 2>err &&\n@@ -118,12 +112,6 @@ test_rebase_am_only () {\n \t\tgrep -e --no-update-refs err\n \t\"\n \n-\ttest_expect_success \"$opt okay with overridden rebase.autosquash\" \"\n-\t\ttest_when_finished \\\"git reset --hard B^0\\\" &&\n-\t\tgit checkout B^0 &&\n-\t\tgit -c rebase.autosquash=true rebase --no-autosquash $opt A\n-\t\"\n-\n \ttest_expect_success \"$opt okay with overridden rebase.rebaseMerges\" \"\n \t\ttest_when_finished \\\"git reset --hard B^0\\\" &&\n \t\tgit checkout B^0 &&\n-- \n2.43.0-rc2\n\n"},{"id":"484892","messageId":"20231114214339.10925-3-andy.koppe@gmail.com","threadId":"60469","inReplyTo":"20231114214339.10925-1-andy.koppe@gmail.com","subject":"[PATCH v5 2/3] rebase: support --autosquash without -i","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-11-14T21:43:38Z","receivedAt":"2023-11-14T21:44:31Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"The rebase --autosquash option is quietly ignored when used without\n--interactive (apart from preventing preemptive fast-forwarding and\ntriggering conflicts with apply backend options).\n\nChange that to support --autosquash without --interactive, by dropping\nits restriction to REBASE_INTERACTIVE_EXCPLICIT mode. When used this\nway, auto-squashing is done without opening the todo list editor.\n\nDrop the -i requirement from the --autosquash description, and amend\nt3415-rebase-autosquash.sh to test the option and the rebase.autoSquash\nconfig variable with and without -i.\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n Documentation/git-rebase.txt |  2 +-\n builtin/rebase.c             |  4 +---\n t/t3415-rebase-autosquash.sh | 38 ++++++++++++++++++++++++++----------\n 3 files changed, 30 insertions(+), 14 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex b4526ca246..10548e715c 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -592,7 +592,7 @@ See also INCOMPATIBLE OPTIONS below.\n \tWhen the commit log message begins with \"squash! ...\" or \"fixup! ...\"\n \tor \"amend! ...\", and there is already a commit in the todo list that\n \tmatches the same `...`, automatically modify the todo list of\n-\t`rebase -i`, so that the commit marked for squashing comes right after\n+\t`rebase`, so that the commit marked for squashing comes right after\n \tthe commit to be modified, and change the action of the moved commit\n \tfrom `pick` to `squash` or `fixup` or `fixup -C` respectively. A commit\n \tmatches the `...` if the commit subject matches, or if the `...` refers\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex a73de7892b..9f8192e0a5 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -710,10 +710,8 @@ static int run_specific_rebase(struct rebase_options *opts)\n \tif (opts->type == REBASE_MERGE) {\n \t\t/* Run sequencer-based rebase */\n \t\tsetenv(\"GIT_CHERRY_PICK_HELP\", resolvemsg, 1);\n-\t\tif (!(opts->flags & REBASE_INTERACTIVE_EXPLICIT)) {\n+\t\tif (!(opts->flags & REBASE_INTERACTIVE_EXPLICIT))\n \t\t\tsetenv(\"GIT_SEQUENCE_EDITOR\", \":\", 1);\n-\t\t\topts->autosquash = 0;\n-\t\t}\n \t\tif (opts->gpg_sign_opt) {\n \t\t\t/* remove the leading \"-S\" */\n \t\t\tchar *tmp = xstrdup(opts->gpg_sign_opt + 2);\ndiff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh\nindex a364530d76..fcc40d6fe1 100755\n--- a/t/t3415-rebase-autosquash.sh\n+++ b/t/t3415-rebase-autosquash.sh\n@@ -43,7 +43,7 @@ test_auto_fixup () {\n \n \tgit tag $1 &&\n \ttest_tick &&\n-\tgit rebase $2 -i HEAD^^^ &&\n+\tgit rebase $2 HEAD^^^ &&\n \tgit log --oneline >actual &&\n \tif test -n \"$no_squash\"\n \tthen\n@@ -61,15 +61,24 @@ test_auto_fixup () {\n }\n \n test_expect_success 'auto fixup (option)' '\n-\ttest_auto_fixup final-fixup-option --autosquash\n+\ttest_auto_fixup fixup-option --autosquash &&\n+\ttest_auto_fixup fixup-option-i \"--autosquash -i\"\n '\n \n-test_expect_success 'auto fixup (config)' '\n+test_expect_success 'auto fixup (config true)' '\n \tgit config rebase.autosquash true &&\n-\ttest_auto_fixup final-fixup-config-true &&\n+\ttest_auto_fixup ! fixup-config-true &&\n+\ttest_auto_fixup fixup-config-true-i -i &&\n \ttest_auto_fixup ! fixup-config-true-no --no-autosquash &&\n+\ttest_auto_fixup ! fixup-config-true-i-no \"-i --no-autosquash\"\n+'\n+\n+test_expect_success 'auto fixup (config false)' '\n \tgit config rebase.autosquash false &&\n-\ttest_auto_fixup ! final-fixup-config-false\n+\ttest_auto_fixup ! fixup-config-false &&\n+\ttest_auto_fixup ! fixup-config-false-i -i &&\n+\ttest_auto_fixup fixup-config-false-yes --autosquash &&\n+\ttest_auto_fixup fixup-config-false-i-yes \"-i --autosquash\"\n '\n \n test_auto_squash () {\n@@ -87,7 +96,7 @@ test_auto_squash () {\n \tgit commit -m \"squash! first\" -m \"extra para for first\" &&\n \tgit tag $1 &&\n \ttest_tick &&\n-\tgit rebase $2 -i HEAD^^^ &&\n+\tgit rebase $2 HEAD^^^ &&\n \tgit log --oneline >actual &&\n \tif test -n \"$no_squash\"\n \tthen\n@@ -105,15 +114,24 @@ test_auto_squash () {\n }\n \n test_expect_success 'auto squash (option)' '\n-\ttest_auto_squash final-squash --autosquash\n+\ttest_auto_squash squash-option --autosquash &&\n+\ttest_auto_squash squash-option-i \"--autosquash -i\"\n '\n \n-test_expect_success 'auto squash (config)' '\n+test_expect_success 'auto squash (config true)' '\n \tgit config rebase.autosquash true &&\n-\ttest_auto_squash final-squash-config-true &&\n+\ttest_auto_squash ! squash-config-true &&\n+\ttest_auto_squash squash-config-true-i -i &&\n \ttest_auto_squash ! squash-config-true-no --no-autosquash &&\n+\ttest_auto_squash ! squash-config-true-i-no \"-i --no-autosquash\"\n+'\n+\n+test_expect_success 'auto squash (config false)' '\n \tgit config rebase.autosquash false &&\n-\ttest_auto_squash ! final-squash-config-false\n+\ttest_auto_squash ! squash-config-false &&\n+\ttest_auto_squash ! squash-config-false-i -i &&\n+\ttest_auto_squash squash-config-false-yes --autosquash &&\n+\ttest_auto_squash squash-config-false-i-yes \"-i --autosquash\"\n '\n \n test_expect_success 'misspelled auto squash' '\n-- \n2.43.0-rc2\n\n"},{"id":"484893","messageId":"20231114214339.10925-4-andy.koppe@gmail.com","threadId":"60469","inReplyTo":"20231114214339.10925-1-andy.koppe@gmail.com","subject":"[PATCH v5 3/3] rebase: rewrite --(no-)autosquash documentation","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-11-14T21:43:39Z","receivedAt":"2023-11-14T21:44:31Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"Rewrite the description of the rebase --(no-)autosquash options to try\nto make it a bit clearer. Don't use \"the '...'\" to refer to part of a\ncommit message, mention how --interactive can be used to review the\ntodo list, and add a bit more detail on commit --squash/amend.\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n Documentation/git-rebase.txt | 34 ++++++++++++++++++++--------------\n 1 file changed, 20 insertions(+), 14 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex 10548e715c..1dd6555f66 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -589,21 +589,27 @@ See also INCOMPATIBLE OPTIONS below.\n \n --autosquash::\n --no-autosquash::\n-\tWhen the commit log message begins with \"squash! ...\" or \"fixup! ...\"\n-\tor \"amend! ...\", and there is already a commit in the todo list that\n-\tmatches the same `...`, automatically modify the todo list of\n-\t`rebase`, so that the commit marked for squashing comes right after\n-\tthe commit to be modified, and change the action of the moved commit\n-\tfrom `pick` to `squash` or `fixup` or `fixup -C` respectively. A commit\n-\tmatches the `...` if the commit subject matches, or if the `...` refers\n-\tto the commit's hash. As a fall-back, partial matches of the commit\n-\tsubject work, too. The recommended way to create fixup/amend/squash\n-\tcommits is by using the `--fixup`, `--fixup=amend:` or `--fixup=reword:`\n-\tand `--squash` options respectively of linkgit:git-commit[1].\n+\tAutomatically squash commits with specially formatted messages into\n+\tprevious commits being rebased.  If a commit message starts with\n+\t\"squash! \", \"fixup! \" or \"amend! \", the remainder of the subject line\n+\tis taken as a commit specifier, which matches a previous commit if it\n+\tmatches the subject line or the hash of that commit.  If no commit\n+\tmatches fully, matches of the specifier with the start of commit\n+\tsubjects are considered.\n +\n-If the `--autosquash` option is enabled by default using the\n-configuration variable `rebase.autoSquash`, this option can be\n-used to override and disable this setting.\n+In the rebase todo list, the actions of squash, fixup and amend commits are\n+changed from `pick` to `squash`, `fixup` or `fixup -C`, respectively, and they\n+are moved right after the commit they modify.  The `--interactive` option can\n+be used to review and edit the todo list before proceeding.\n++\n+The recommended way to create commits with squash markers is by using the\n+`--squash`, `--fixup`, `--fixup=amend:` or `--fixup=reword:` options of\n+linkgit:git-commit[1], which take the target commit as an argument and\n+automatically fill in the subject line of the new commit from that.\n++\n+Settting configuration variable `rebase.autoSquash` to true enables\n+auto-squashing by default for interactive rebase.  The `--no-autosquash`\n+option can be used to override that setting.\n +\n See also INCOMPATIBLE OPTIONS below.\n \n-- \n2.43.0-rc2\n\n"},{"id":"484937","messageId":"eb62435f-08ca-494d-bcc7-2568df2bd7fd@gmail.com","threadId":"60469","inReplyTo":"20231114214339.10925-1-andy.koppe@gmail.com","subject":"Re: [PATCH v5 0/3] rebase: support --autosquash without -i","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2023-11-15T15:09:12Z","receivedAt":"2023-11-15T15:09:16Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Andy\n\nOn 14/11/2023 21:43, Andy Koppe wrote:\n> Make rebase --autosquash work without --interactive, but limit\n> rebase.autoSquash's effects to interactive mode, and improve testing\n> and documentation.\n> \n> Changes from v4:\n> - Fix amend vs apply backend thinko in commit messages.\n> - Squash patch 3 for testing into patch 2 and improve the commit\n>    message.\n> - No source changes.\n> \n> Thanks again to Junio and Phillip for their reviews.\n\nThanks for the re-roll this version looks good to me\n\nBest Wishes\n\nPhillip\n\n> \n> Andy Koppe (3):\n>    rebase: fully ignore rebase.autoSquash without -i\n>    rebase: support --autosquash without -i\n>    rebase: rewrite --(no-)autosquash documentation\n> \n>   Documentation/config/rebase.txt        |  4 ++-\n>   Documentation/git-rebase.txt           | 34 +++++++++++++----------\n>   builtin/rebase.c                       | 17 +++++-------\n>   t/t3415-rebase-autosquash.sh           | 38 +++++++++++++++++++-------\n>   t/t3422-rebase-incompatible-options.sh | 12 --------\n>   5 files changed, 58 insertions(+), 47 deletions(-)\n> \n"},{"id":"484955","messageId":"xmqqcywawni8.fsf@gitster.g","threadId":"60469","inReplyTo":"eb62435f-08ca-494d-bcc7-2568df2bd7fd@gmail.com","subject":"Re: [PATCH v5 0/3] rebase: support --autosquash without -i","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-11-16T00:27:43Z","receivedAt":"2023-11-16T00:27:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Phillip Wood <phillip.wood123@gmail.com> writes:\n\n> Hi Andy\n> ...\n> Thanks for the re-roll this version looks good to me\n>\n> Best Wishes\n>\n> Phillip\n\nYup, looks good.  Thanks, both.\n\nQueued.\n\n\n>\n>> Andy Koppe (3):\n>>    rebase: fully ignore rebase.autoSquash without -i\n>>    rebase: support --autosquash without -i\n>>    rebase: rewrite --(no-)autosquash documentation\n>>   Documentation/config/rebase.txt        |  4 ++-\n>>   Documentation/git-rebase.txt           | 34 +++++++++++++----------\n>>   builtin/rebase.c                       | 17 +++++-------\n>>   t/t3415-rebase-autosquash.sh           | 38 +++++++++++++++++++-------\n>>   t/t3422-rebase-incompatible-options.sh | 12 --------\n>>   5 files changed, 58 insertions(+), 47 deletions(-)\n>> \n"}]}