Git fork

Merge branch 'pw/3.0-commentchar-auto-deprecation'

"core.commentChar=auto" that attempts to dynamically pick a
suitable comment character is non-workable, as it is too much
trouble to support for little benefit, and is marked as deprecated.

* pw/3.0-commentchar-auto-deprecation:
commit: print advice when core.commentString=auto
config: warn on core.commentString=auto
breaking-changes: deprecate support for core.commentString=auto

+423 -12
+5
Documentation/BreakingChanges.adoc
··· 239 239 + 240 240 The command will be removed. 241 241 242 + * Support for `core.commentString=auto` has been deprecated and will 243 + be removed in Git 3.0. 244 + + 245 + cf. <xmqqa59i45wc.fsf@gitster.g> 246 + 242 247 == Superseded features that will not be deprecated 243 248 244 249 Some features have gained newer replacements that aim to improve the design in
+17 -1
Documentation/config/core.adoc
··· 531 531 commented, and removes them after the editor returns 532 532 (default '#'). 533 533 + 534 - If set to "auto", `git-commit` would select a character that is not 534 + ifndef::with-breaking-changes[] 535 + If set to "auto", `git-commit` will select a character that is not 535 536 the beginning character of any line in existing commit messages. 537 + Support for this value is deprecated and will be removed in Git 3.0 538 + due to the following limitations: 536 539 + 540 + -- 541 + * It is incompatible with adding comments in a commit message 542 + template. This includes the conflicts comments added to 543 + the commit message by `cherry-pick`, `merge`, `rebase` and 544 + `revert`. 545 + * It is incompatible with adding comments to the commit message 546 + in the `prepare-commit-msg` hook. 547 + * It is incompatible with the `fixup` and `squash` commands when 548 + rebasing, 549 + * It is not respected by `git notes` 550 + -- 551 + + 552 + endif::with-breaking-changes[] 537 553 Note that these two variables are aliases of each other, and in modern 538 554 versions of Git you are free to use a string (e.g., `//` or `⁑⁕⁑`) with 539 555 `commentChar`. Versions of Git prior to v2.45.0 will ignore
+7
builtin/commit.c
··· 695 695 return author_message || force_date; 696 696 } 697 697 698 + #ifndef WITH_BREAKING_CHANGES 698 699 static void adjust_comment_line_char(const struct strbuf *sb) 699 700 { 700 701 char candidates[] = "#;@!$%^&|:"; ··· 732 733 free(comment_line_str_to_free); 733 734 comment_line_str = comment_line_str_to_free = xstrfmt("%c", *p); 734 735 } 736 + #endif /* !WITH_BREAKING_CHANGES */ 735 737 736 738 static void prepare_amend_commit(struct commit *commit, struct strbuf *sb, 737 739 struct pretty_print_context *ctx) ··· 928 930 if (fwrite(sb.buf, 1, sb.len, s->fp) < sb.len) 929 931 die_errno(_("could not write commit template")); 930 932 933 + #ifndef WITH_BREAKING_CHANGES 931 934 if (auto_comment_line_char) 932 935 adjust_comment_line_char(&sb); 936 + #endif /* !WITH_BREAKING_CHANGES */ 933 937 strbuf_release(&sb); 934 938 935 939 /* This checks if committer ident is explicitly given */ ··· 1793 1797 show_usage_with_options_if_asked(argc, argv, 1794 1798 builtin_commit_usage, builtin_commit_options); 1795 1799 1800 + #ifndef WITH_BREAKING_CHANGES 1801 + warn_on_auto_comment_char = true; 1802 + #endif /* !WITH_BREAKING_CHANGES */ 1796 1803 prepare_repo_settings(the_repository); 1797 1804 the_repository->settings.command_requires_full_index = 0; 1798 1805
+3
builtin/merge.c
··· 1379 1379 show_usage_with_options_if_asked(argc, argv, 1380 1380 builtin_merge_usage, builtin_merge_options); 1381 1381 1382 + #ifndef WITH_BREAKING_CHANGES 1383 + warn_on_auto_comment_char = true; 1384 + #endif /* !WITH_BREAKING_CHANGES */ 1382 1385 prepare_repo_settings(the_repository); 1383 1386 the_repository->settings.command_requires_full_index = 0; 1384 1387
+3
builtin/rebase.c
··· 1242 1242 builtin_rebase_usage, 1243 1243 builtin_rebase_options); 1244 1244 1245 + #ifndef WITH_BREAKING_CHANGES 1246 + warn_on_auto_comment_char = true; 1247 + #endif /* !WITH_BREAKING_CHANGES */ 1245 1248 prepare_repo_settings(the_repository); 1246 1249 the_repository->settings.command_requires_full_index = 0; 1247 1250
+7
builtin/revert.c
··· 4 4 #include "builtin.h" 5 5 #include "parse-options.h" 6 6 #include "diff.h" 7 + #include "environment.h" 7 8 #include "gettext.h" 8 9 #include "revision.h" 9 10 #include "rerere.h" ··· 285 286 struct replay_opts opts = REPLAY_OPTS_INIT; 286 287 int res; 287 288 289 + #ifndef WITH_BREAKING_CHANGES 290 + warn_on_auto_comment_char = true; 291 + #endif /* !WITH_BREAKING_CHANGES */ 288 292 opts.action = REPLAY_REVERT; 289 293 sequencer_init_config(&opts); 290 294 res = run_sequencer(argc, argv, prefix, &opts); ··· 302 306 struct replay_opts opts = REPLAY_OPTS_INIT; 303 307 int res; 304 308 309 + #ifndef WITH_BREAKING_CHANGES 310 + warn_on_auto_comment_char = true; 311 + #endif /* !WITH_BREAKING_CHANGES */ 305 312 opts.action = REPLAY_PICK; 306 313 sequencer_init_config(&opts); 307 314 res = run_sequencer(argc, argv, prefix, &opts);
+295 -2
config.c
··· 8 8 9 9 #include "git-compat-util.h" 10 10 #include "abspath.h" 11 + #include "advice.h" 11 12 #include "date.h" 12 13 #include "branch.h" 13 14 #include "config.h" 15 + #include "dir.h" 14 16 #include "parse.h" 15 17 #include "convert.h" 16 18 #include "environment.h" ··· 1948 1950 return 1; 1949 1951 } 1950 1952 1953 + struct comment_char_config { 1954 + unsigned last_key_id; 1955 + bool auto_set; 1956 + bool auto_set_in_file; 1957 + struct strintmap key_flags; 1958 + size_t alloc, nr; 1959 + struct comment_char_config_item { 1960 + unsigned key_id; 1961 + char *path; 1962 + enum config_scope scope; 1963 + } *item; 1964 + }; 1965 + 1966 + #define COMMENT_CHAR_CFG_INIT { \ 1967 + .key_flags = STRINTMAP_INIT, \ 1968 + } 1969 + 1970 + static void comment_char_config_release(struct comment_char_config *config) 1971 + { 1972 + strintmap_clear(&config->key_flags); 1973 + for (size_t i = 0; i < config->nr; i++) 1974 + free(config->item[i].path); 1975 + free(config->item); 1976 + } 1977 + 1978 + /* Used to track whether the key occurs more than once in a given file */ 1979 + #define KEY_SEEN_ONCE 1u 1980 + #define KEY_SEEN_TWICE 2u 1981 + #define COMMENT_KEY_SHIFT(id) (2 * (id)) 1982 + #define COMMENT_KEY_MASK(id) (3u << COMMENT_KEY_SHIFT(id)) 1983 + 1984 + static void set_comment_key_flags(struct comment_char_config *config, 1985 + const char *path, unsigned id, unsigned value) 1986 + { 1987 + unsigned old = strintmap_get(&config->key_flags, path); 1988 + unsigned new = (old & ~COMMENT_KEY_MASK(id)) | 1989 + value << COMMENT_KEY_SHIFT(id); 1990 + 1991 + strintmap_set(&config->key_flags, path, new); 1992 + } 1993 + 1994 + static unsigned get_comment_key_flags(struct comment_char_config *config, 1995 + const char *path, unsigned id) 1996 + { 1997 + unsigned value = strintmap_get(&config->key_flags, path); 1998 + 1999 + return (value & COMMENT_KEY_MASK(id)) >> COMMENT_KEY_SHIFT(id); 2000 + } 2001 + 2002 + static const char *comment_key_name(unsigned id) 2003 + { 2004 + static const char *name[] = { 2005 + "core.commentChar", 2006 + "core.commentString", 2007 + }; 2008 + 2009 + if (id >= ARRAY_SIZE(name)) 2010 + BUG("invalid comment key id"); 2011 + 2012 + return name[id]; 2013 + } 2014 + 2015 + static void comment_char_callback(const char *key, const char *value, 2016 + const struct config_context *ctx, void *data) 2017 + { 2018 + struct comment_char_config *config = data; 2019 + const struct key_value_info *kvi = ctx->kvi; 2020 + unsigned key_id; 2021 + 2022 + if (!strcmp(key, "core.commentchar")) 2023 + key_id = 0; 2024 + else if (!strcmp(key, "core.commentstring")) 2025 + key_id = 1; 2026 + else 2027 + return; 2028 + 2029 + config->last_key_id = key_id; 2030 + config->auto_set = value && !strcmp(value, "auto"); 2031 + if (kvi->origin_type != CONFIG_ORIGIN_FILE) { 2032 + return; 2033 + } else if (get_comment_key_flags(config, kvi->filename, key_id)) { 2034 + set_comment_key_flags(config, kvi->filename, key_id, 2035 + KEY_SEEN_TWICE); 2036 + } else { 2037 + struct comment_char_config_item *item; 2038 + 2039 + ALLOC_GROW_BY(config->item, config->nr, 1, config->alloc); 2040 + item = &config->item[config->nr - 1]; 2041 + item->key_id = key_id; 2042 + item->scope = kvi->scope; 2043 + item->path = xstrdup(kvi->filename); 2044 + set_comment_key_flags(config, kvi->filename, key_id, 2045 + KEY_SEEN_ONCE); 2046 + } 2047 + config->auto_set_in_file = config->auto_set; 2048 + } 2049 + 2050 + static void add_config_scope_arg(struct repository *repo, struct strbuf *buf, 2051 + struct comment_char_config_item *item) 2052 + { 2053 + char *global_config = git_global_config(); 2054 + char *system_config = git_system_config(); 2055 + 2056 + if (item->scope == CONFIG_SCOPE_SYSTEM && access(item->path, W_OK)) { 2057 + /* 2058 + * If the user cannot write to the system config recommend 2059 + * setting the global config instead. 2060 + */ 2061 + strbuf_addstr(buf, "--global "); 2062 + } else if (fspatheq(item->path, system_config)) { 2063 + strbuf_addstr(buf, "--system "); 2064 + } else if (fspatheq(item->path, global_config)) { 2065 + strbuf_addstr(buf, "--global "); 2066 + } else if (fspatheq(item->path, 2067 + mkpath("%s/config", 2068 + repo_get_git_dir(repo)))) { 2069 + ; /* --local is the default */ 2070 + } else if (fspatheq(item->path, 2071 + mkpath("%s/config.worktree", 2072 + repo_get_common_dir(repo)))) { 2073 + strbuf_addstr(buf, "--worktree "); 2074 + } else { 2075 + const char *path = item->path; 2076 + const char *home = getenv("HOME"); 2077 + 2078 + strbuf_addstr(buf, "--file "); 2079 + if (home && !fspathncmp(path, home, strlen(home))) { 2080 + path += strlen(home); 2081 + if (!fspathncmp(path, "/", 1)) 2082 + path++; 2083 + strbuf_addstr(buf, "~/"); 2084 + } 2085 + sq_quote_buf_pretty(buf, path); 2086 + strbuf_addch(buf, ' '); 2087 + } 2088 + 2089 + free(global_config); 2090 + free(system_config); 2091 + } 2092 + 2093 + static bool can_unset_comment_char_config(struct comment_char_config *config) 2094 + { 2095 + for (size_t i = 0; i < config->nr; i++) { 2096 + struct comment_char_config_item *item = &config->item[i]; 2097 + 2098 + if (item->scope == CONFIG_SCOPE_SYSTEM && 2099 + access(item->path, W_OK)) 2100 + return false; 2101 + } 2102 + 2103 + return true; 2104 + } 2105 + 2106 + static void add_unset_auto_comment_char_advice(struct repository *repo, 2107 + struct comment_char_config *config) 2108 + { 2109 + struct strbuf buf = STRBUF_INIT; 2110 + 2111 + if (!can_unset_comment_char_config(config)) 2112 + return; 2113 + 2114 + for (size_t i = 0; i < config->nr; i++) { 2115 + struct comment_char_config_item *item = &config->item[i]; 2116 + 2117 + strbuf_addstr(&buf, " git config unset "); 2118 + add_config_scope_arg(repo, &buf, item); 2119 + if (get_comment_key_flags(config, item->path, item->key_id) == KEY_SEEN_TWICE) 2120 + strbuf_addstr(&buf, "--all "); 2121 + strbuf_addf(&buf, "%s\n", comment_key_name(item->key_id)); 2122 + } 2123 + advise(_("\nTo use the default comment string (#) please run\n\n%s"), 2124 + buf.buf); 2125 + strbuf_release(&buf); 2126 + } 2127 + 2128 + static void add_comment_char_advice(struct repository *repo, 2129 + struct comment_char_config *config) 2130 + { 2131 + struct strbuf buf = STRBUF_INIT; 2132 + struct comment_char_config_item *item; 2133 + /* TRANSLATORS this is a place holder for the value of core.commentString */ 2134 + const char *placeholder = _("<comment string>"); 2135 + 2136 + /* 2137 + * If auto is set in the last file that we saw advise the user how to 2138 + * update their config. 2139 + */ 2140 + if (!config->auto_set_in_file) 2141 + return; 2142 + 2143 + add_unset_auto_comment_char_advice(repo, config); 2144 + item = &config->item[config->nr - 1]; 2145 + strbuf_reset(&buf); 2146 + strbuf_addstr(&buf, " git config set "); 2147 + add_config_scope_arg(repo, &buf, item); 2148 + strbuf_addf(&buf, "%s %s\n", comment_key_name(item->key_id), 2149 + placeholder); 2150 + advise(_("\nTo set a custom comment string please run\n\n" 2151 + "%s\nwhere '%s' is the string you wish to use.\n"), 2152 + buf.buf, placeholder); 2153 + strbuf_release(&buf); 2154 + } 2155 + 2156 + #undef KEY_SEEN_ONCE 2157 + #undef KEY_SEEN_TWICE 2158 + #undef COMMENT_KEY_SHIFT 2159 + #undef COMMENT_KEY_MASK 2160 + 2161 + struct repo_config { 2162 + struct repository *repo; 2163 + struct comment_char_config comment_char_config; 2164 + }; 2165 + 2166 + #define REPO_CONFIG_INIT(repo_) { \ 2167 + .comment_char_config = COMMENT_CHAR_CFG_INIT, \ 2168 + .repo = repo_, \ 2169 + }; 2170 + 2171 + static void repo_config_release(struct repo_config *config) 2172 + { 2173 + comment_char_config_release(&config->comment_char_config); 2174 + } 2175 + 2176 + #ifdef WITH_BREAKING_CHANGES 2177 + static void check_auto_comment_char_config(struct repository *repo, 2178 + struct comment_char_config *config) 2179 + { 2180 + if (!config->auto_set) 2181 + return; 2182 + 2183 + die_message(_("Support for '%s=auto' has been removed in Git 3.0"), 2184 + comment_key_name(config->last_key_id)); 2185 + add_comment_char_advice(repo, config); 2186 + die(NULL); 2187 + } 2188 + #else 2189 + static void check_auto_comment_char_config(struct repository *repo, 2190 + struct comment_char_config *config) 2191 + { 2192 + extern bool warn_on_auto_comment_char; 2193 + const char *DEPRECATED_CONFIG_ENV = 2194 + "GIT_AUTO_COMMENT_CHAR_CONFIG_WARNING_GIVEN"; 2195 + 2196 + if (!config->auto_set || !warn_on_auto_comment_char) 2197 + return; 2198 + 2199 + /* 2200 + * Use an environment variable to ensure that subprocesses do not repeat 2201 + * the warning. 2202 + */ 2203 + if (git_env_bool(DEPRECATED_CONFIG_ENV, false)) 2204 + return; 2205 + 2206 + setenv(DEPRECATED_CONFIG_ENV, "true", true); 2207 + 2208 + warning(_("Support for '%s=auto' is deprecated and will be removed in " 2209 + "Git 3.0"), comment_key_name(config->last_key_id)); 2210 + add_comment_char_advice(repo, config); 2211 + } 2212 + #endif /* WITH_BREAKING_CHANGES */ 2213 + 2214 + static void check_deprecated_config(struct repo_config *config) 2215 + { 2216 + if (!config->repo->check_deprecated_config) 2217 + return; 2218 + 2219 + check_auto_comment_char_config(config->repo, 2220 + &config->comment_char_config); 2221 + } 2222 + 2223 + static int repo_config_callback(const char *key, const char *value, 2224 + const struct config_context *ctx, void *data) 2225 + { 2226 + struct repo_config *config = data; 2227 + 2228 + comment_char_callback(key, value, ctx, &config->comment_char_config); 2229 + return config_set_callback(key, value, ctx, config->repo->config); 2230 + } 2231 + 1951 2232 /* Functions use to read configuration from a repository */ 1952 2233 static void repo_read_config(struct repository *repo) 1953 2234 { 1954 2235 struct config_options opts = { 0 }; 2236 + struct repo_config config = REPO_CONFIG_INIT(repo); 1955 2237 1956 2238 opts.respect_includes = 1; 1957 2239 opts.commondir = repo->commondir; ··· 1963 2245 git_configset_clear(repo->config); 1964 2246 1965 2247 git_configset_init(repo->config); 1966 - if (config_with_options(config_set_callback, repo->config, NULL, 1967 - repo, &opts) < 0) 2248 + if (config_with_options(repo_config_callback, &config, NULL, repo, 2249 + &opts) < 0) 1968 2250 /* 1969 2251 * config_with_options() normally returns only 1970 2252 * zero, as most errors are fatal, and ··· 1977 2259 * immediately. 1978 2260 */ 1979 2261 die(_("unknown error occurred while reading the configuration files")); 2262 + check_deprecated_config(&config); 2263 + repo_config_release(&config); 1980 2264 } 1981 2265 1982 2266 static void git_config_check_init(struct repository *repo) ··· 2664 2948 char *contents = NULL; 2665 2949 size_t contents_sz; 2666 2950 struct config_store_data store = CONFIG_STORE_INIT; 2951 + bool saved_check_deprecated_config = r->check_deprecated_config; 2952 + 2953 + /* 2954 + * Do not warn or die if there are deprecated config settings as 2955 + * we want the user to be able to change those settings by running 2956 + * "git config". 2957 + */ 2958 + r->check_deprecated_config = false; 2667 2959 2668 2960 validate_comment_string(comment); 2669 2961 ··· 2895 3187 if (in_fd >= 0) 2896 3188 close(in_fd); 2897 3189 config_store_data_clear(&store); 3190 + r->check_deprecated_config = saved_check_deprecated_config; 2898 3191 return ret; 2899 3192 2900 3193 write_err_out:
+12 -3
environment.c
··· 121 121 */ 122 122 const char *comment_line_str = "#"; 123 123 char *comment_line_str_to_free; 124 + #ifndef WITH_BREAKING_CHANGES 124 125 int auto_comment_line_char; 126 + bool warn_on_auto_comment_char; 127 + #endif /* !WITH_BREAKING_CHANGES */ 125 128 126 129 /* This is set by setup_git_directory_gently() and/or git_default_config() */ 127 130 char *git_work_tree_cfg; ··· 463 466 464 467 if (!strcmp(var, "core.commentchar") || 465 468 !strcmp(var, "core.commentstring")) { 466 - if (!value) 469 + if (!value) { 467 470 return config_error_nonbool(var); 468 - else if (!strcasecmp(value, "auto")) 471 + #ifndef WITH_BREAKING_CHANGES 472 + } else if (!strcasecmp(value, "auto")) { 469 473 auto_comment_line_char = 1; 470 - else if (value[0]) { 474 + FREE_AND_NULL(comment_line_str_to_free); 475 + comment_line_str = "#"; 476 + #endif /* !WITH_BREAKING_CHANGES */ 477 + } else if (value[0]) { 471 478 if (strchr(value, '\n')) 472 479 return error(_("%s cannot contain newline"), var); 473 480 comment_line_str = value; 474 481 FREE_AND_NULL(comment_line_str_to_free); 482 + #ifndef WITH_BREAKING_CHANGES 475 483 auto_comment_line_char = 0; 484 + #endif /* !WITH_BREAKING_CHANGES */ 476 485 } else 477 486 return error(_("%s must have at least one character"), var); 478 487 return 0;
+3
environment.h
··· 208 208 */ 209 209 extern const char *comment_line_str; 210 210 extern char *comment_line_str_to_free; 211 + #ifndef WITH_BREAKING_CHANGES 211 212 extern int auto_comment_line_char; 213 + extern bool warn_on_auto_comment_char; 214 + #endif /* !WITH_BREAKING_CHANGES */ 212 215 213 216 # endif /* USE_THE_REPOSITORY_VARIABLE */ 214 217 #endif /* ENVIRONMENT_H */
+1
repository.c
··· 57 57 repo->parsed_objects = parsed_object_pool_new(repo); 58 58 ALLOC_ARRAY(repo->index, 1); 59 59 index_state_init(repo->index, repo); 60 + repo->check_deprecated_config = true; 60 61 61 62 /* 62 63 * When a command runs inside a repository, it learns what
+3
repository.h
··· 161 161 162 162 /* Indicate if a repository has a different 'commondir' from 'gitdir' */ 163 163 unsigned different_commondir:1; 164 + 165 + /* Should repo_config() check for deprecated settings */ 166 + bool check_deprecated_config; 164 167 }; 165 168 166 169 #ifdef USE_THE_REPOSITORY_VARIABLE
+17 -2
t/t3404-rebase-interactive.sh
··· 1176 1176 test B = $(git cat-file commit HEAD^ | sed -ne \$p) 1177 1177 ' 1178 1178 1179 - test_expect_success 'rebase -i respects core.commentchar=auto' ' 1179 + test_expect_success !WITH_BREAKING_CHANGES 'rebase -i respects core.commentchar=auto' ' 1180 1180 test_config core.commentchar auto && 1181 1181 write_script copy-edit-script.sh <<-\EOF && 1182 1182 cp "$1" edit-script ··· 1184 1184 test_when_finished "git rebase --abort || :" && 1185 1185 ( 1186 1186 test_set_editor "$(pwd)/copy-edit-script.sh" && 1187 - git rebase -i HEAD^ 1187 + git rebase -i HEAD^ 2>err 1188 1188 ) && 1189 + sed -n "s/^hint: *\$//p; s/^hint: //p; s/^warning: //p" err >actual && 1190 + cat >expect <<-EOF && 1191 + Support for ${SQ}core.commentChar=auto${SQ} is deprecated and will be removed in Git 3.0 1192 + 1193 + To use the default comment string (#) please run 1194 + 1195 + git config unset core.commentChar 1196 + 1197 + To set a custom comment string please run 1198 + 1199 + git config set core.commentChar <comment string> 1200 + 1201 + where ${SQ}<comment string>${SQ} is the string you wish to use. 1202 + EOF 1203 + test_cmp expect actual && 1189 1204 test -z "$(grep -ve "^#" -e "^\$" -e "^pick" edit-script)" 1190 1205 ' 1191 1206
+1 -1
t/t3418-rebase-continue.sh
··· 328 328 test_expect_code 129 git rebase --edit-todo --no-reschedule-failed-exec 329 329 ' 330 330 331 - test_expect_success 'no change in comment character due to conflicts markers with core.commentChar=auto' ' 331 + test_expect_success !WITH_BREAKING_CHANGES 'no change in comment character due to conflicts markers with core.commentChar=auto' ' 332 332 git checkout -b branch-a && 333 333 test_commit A F1 && 334 334 git checkout -b branch-b HEAD^ &&
+49 -3
t/t7502-commit-porcelain.sh
··· 956 956 test_grep "^; Changes to be committed:" .git/COMMIT_EDITMSG 957 957 ' 958 958 959 - test_expect_success 'switch core.commentchar' ' 959 + test_expect_success !WITH_BREAKING_CHANGES 'switch core.commentchar' ' 960 960 test_commit "#foo" foo && 961 - GIT_EDITOR=.git/FAKE_EDITOR git -c core.commentChar=auto commit --amend && 961 + cat >config-include <<-\EOF && 962 + [core] 963 + commentString=: 964 + commentString=% 965 + commentChar=auto 966 + EOF 967 + test_when_finished "rm config-include" && 968 + test_config include.path "$(pwd)/config-include" && 969 + test_config core.commentChar ! && 970 + GIT_EDITOR=.git/FAKE_EDITOR git commit --amend 2>err && 971 + sed -n "s/^hint: *\$//p; s/^hint: //p; s/^warning: //p" err >actual && 972 + cat >expect <<-EOF && 973 + Support for ${SQ}core.commentChar=auto${SQ} is deprecated and will be removed in Git 3.0 974 + 975 + To use the default comment string (#) please run 976 + 977 + git config unset core.commentChar 978 + git config unset --file ~/config-include --all core.commentString 979 + git config unset --file ~/config-include core.commentChar 980 + 981 + To set a custom comment string please run 982 + 983 + git config set --file ~/config-include core.commentChar <comment string> 984 + 985 + where ${SQ}<comment string>${SQ} is the string you wish to use. 986 + EOF 987 + test_cmp expect actual && 962 988 test_grep "^; Changes to be committed:" .git/COMMIT_EDITMSG 963 989 ' 964 990 965 - test_expect_success 'switch core.commentchar but out of options' ' 991 + test_expect_success !WITH_BREAKING_CHANGES 'switch core.commentchar but out of options' ' 966 992 cat >text <<\EOF && 967 993 # 1 968 994 ; 2 ··· 980 1006 test_set_editor .git/FAKE_EDITOR && 981 1007 test_must_fail git -c core.commentChar=auto commit --amend 982 1008 ) 1009 + ' 1010 + 1011 + test_expect_success WITH_BREAKING_CHANGES 'core.commentChar=auto is rejected' ' 1012 + test_config core.commentChar auto && 1013 + test_must_fail git rev-parse --git-dir 2>err && 1014 + sed -n "s/^hint: *\$//p; s/^hint: //p; s/^fatal: //p" err >actual && 1015 + cat >expect <<-EOF && 1016 + Support for ${SQ}core.commentChar=auto${SQ} has been removed in Git 3.0 1017 + 1018 + To use the default comment string (#) please run 1019 + 1020 + git config unset core.commentChar 1021 + 1022 + To set a custom comment string please run 1023 + 1024 + git config set core.commentChar <comment string> 1025 + 1026 + where ${SQ}<comment string>${SQ} is the string you wish to use. 1027 + EOF 1028 + test_cmp expect actual 983 1029 ' 984 1030 985 1031 test_done