blob: 75111191ad586d4cbae07e806f8b2bb6f7ebe83b [file] [log] [blame]
Elijah Newrenfc7bd512023-02-24 00:09:34 +00001#include "git-compat-util.h"
2#include "advice.h"
Brandon Williamsb2141fc2017-06-14 11:07:36 -07003#include "config.h"
Ryan Dammrose960786e2018-04-21 12:10:00 +02004#include "color.h"
Elijah Newrenfc7bd512023-02-24 00:09:34 +00005#include "gettext.h"
Nguyễn Thái Ngọc Duy3ac68a92018-05-26 15:55:24 +02006#include "help.h"
Matheus Tavaresa20f7042021-04-08 17:41:27 -03007#include "string-list.h"
Jeff King75194432009-09-09 07:38:58 -04008
Ryan Dammrose960786e2018-04-21 12:10:00 +02009static int advice_use_color = -1;
10static char advice_colors[][COLOR_MAXLEN] = {
11 GIT_COLOR_RESET,
12 GIT_COLOR_YELLOW, /* HINT */
13};
14
15enum color_advice {
16 ADVICE_COLOR_RESET = 0,
17 ADVICE_COLOR_HINT = 1,
18};
19
20static int parse_advise_color_slot(const char *slot)
21{
22 if (!strcasecmp(slot, "reset"))
23 return ADVICE_COLOR_RESET;
24 if (!strcasecmp(slot, "hint"))
25 return ADVICE_COLOR_HINT;
26 return -1;
27}
28
29static const char *advise_get_color(enum color_advice ix)
30{
31 if (want_color_stderr(advice_use_color))
32 return advice_colors[ix];
33 return "";
34}
35
Rubén Justod9199652024-01-15 15:28:28 +010036enum advice_level {
37 ADVICE_LEVEL_NONE = 0,
38 ADVICE_LEVEL_DISABLED,
39 ADVICE_LEVEL_ENABLED,
40};
41
Jeff King75194432009-09-09 07:38:58 -040042static struct {
Heba Walyb3b18d12020-03-02 20:01:59 +000043 const char *key;
Rubén Justod9199652024-01-15 15:28:28 +010044 enum advice_level level;
Heba Walyb3b18d12020-03-02 20:01:59 +000045} advice_setting[] = {
Rubén Justod9199652024-01-15 15:28:28 +010046 [ADVICE_ADD_EMBEDDED_REPO] = { "addEmbeddedRepo" },
47 [ADVICE_ADD_EMPTY_PATHSPEC] = { "addEmptyPathspec" },
48 [ADVICE_ADD_IGNORED_FILE] = { "addIgnoredFile" },
49 [ADVICE_AMBIGUOUS_FETCH_REFSPEC] = { "ambiguousFetchRefspec" },
50 [ADVICE_AM_WORK_DIR] = { "amWorkDir" },
51 [ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME] = { "checkoutAmbiguousRemoteBranchName" },
52 [ADVICE_COMMIT_BEFORE_MERGE] = { "commitBeforeMerge" },
53 [ADVICE_DETACHED_HEAD] = { "detachedHead" },
54 [ADVICE_DIVERGING] = { "diverging" },
55 [ADVICE_FETCH_SHOW_FORCED_UPDATES] = { "fetchShowForcedUpdates" },
56 [ADVICE_FORCE_DELETE_BRANCH] = { "forceDeleteBranch" },
57 [ADVICE_GRAFT_FILE_DEPRECATED] = { "graftFileDeprecated" },
58 [ADVICE_IGNORED_HOOK] = { "ignoredHook" },
59 [ADVICE_IMPLICIT_IDENTITY] = { "implicitIdentity" },
Philippe Blainec030092024-03-16 21:16:29 +000060 [ADVICE_MERGE_CONFLICT] = { "mergeConflict" },
Rubén Justod9199652024-01-15 15:28:28 +010061 [ADVICE_NESTED_TAG] = { "nestedTag" },
62 [ADVICE_OBJECT_NAME_WARNING] = { "objectNameWarning" },
63 [ADVICE_PUSH_ALREADY_EXISTS] = { "pushAlreadyExists" },
64 [ADVICE_PUSH_FETCH_FIRST] = { "pushFetchFirst" },
65 [ADVICE_PUSH_NEEDS_FORCE] = { "pushNeedsForce" },
66 [ADVICE_PUSH_NON_FF_CURRENT] = { "pushNonFFCurrent" },
67 [ADVICE_PUSH_NON_FF_MATCHING] = { "pushNonFFMatching" },
68 [ADVICE_PUSH_REF_NEEDS_UPDATE] = { "pushRefNeedsUpdate" },
69 [ADVICE_PUSH_UNQUALIFIED_REF_NAME] = { "pushUnqualifiedRefName" },
70 [ADVICE_PUSH_UPDATE_REJECTED] = { "pushUpdateRejected" },
71 [ADVICE_PUSH_UPDATE_REJECTED_ALIAS] = { "pushNonFastForward" }, /* backwards compatibility */
Kristoffer Haugsbakk8fbd9032024-03-05 21:29:43 +010072 [ADVICE_REF_SYNTAX] = { "refSyntax" },
Rubén Justod9199652024-01-15 15:28:28 +010073 [ADVICE_RESET_NO_REFRESH_WARNING] = { "resetNoRefresh" },
74 [ADVICE_RESOLVE_CONFLICT] = { "resolveConflict" },
75 [ADVICE_RM_HINTS] = { "rmHints" },
76 [ADVICE_SEQUENCER_IN_USE] = { "sequencerInUse" },
77 [ADVICE_SET_UPSTREAM_FAILURE] = { "setUpstreamFailure" },
78 [ADVICE_SKIPPED_CHERRY_PICKS] = { "skippedCherryPicks" },
79 [ADVICE_STATUS_AHEAD_BEHIND_WARNING] = { "statusAheadBehindWarning" },
80 [ADVICE_STATUS_HINTS] = { "statusHints" },
81 [ADVICE_STATUS_U_OPTION] = { "statusUoption" },
82 [ADVICE_SUBMODULES_NOT_UPDATED] = { "submodulesNotUpdated" },
83 [ADVICE_SUBMODULE_ALTERNATE_ERROR_STRATEGY_DIE] = { "submoduleAlternateErrorStrategyDie" },
Philippe Blainb9e55be2024-02-26 13:27:28 +000084 [ADVICE_SUBMODULE_MERGE_CONFLICT] = { "submoduleMergeConflict" },
Rubén Justod9199652024-01-15 15:28:28 +010085 [ADVICE_SUGGEST_DETACHING_HEAD] = { "suggestDetachingHead" },
86 [ADVICE_UPDATE_SPARSE_PATH] = { "updateSparsePath" },
87 [ADVICE_WAITING_FOR_EDITOR] = { "waitingForEditor" },
88 [ADVICE_WORKTREE_ADD_ORPHAN] = { "worktreeAddOrphan" },
Heba Walyb3b18d12020-03-02 20:01:59 +000089};
90
91static const char turn_off_instructions[] =
92N_("\n"
93 "Disable this message with \"git config advice.%s false\"");
94
95static void vadvise(const char *advice, int display_instructions,
96 const char *key, va_list params)
Ramkumar Ramachandra38ef61c2011-08-04 16:08:59 +053097{
Junio C Hamano23cb5bf2011-12-22 11:21:26 -080098 struct strbuf buf = STRBUF_INIT;
Junio C Hamano23cb5bf2011-12-22 11:21:26 -080099 const char *cp, *np;
Ramkumar Ramachandra38ef61c2011-08-04 16:08:59 +0530100
Jeff King447b99c2012-07-23 14:48:57 -0400101 strbuf_vaddf(&buf, advice, params);
Junio C Hamano23cb5bf2011-12-22 11:21:26 -0800102
Heba Walyb3b18d12020-03-02 20:01:59 +0000103 if (display_instructions)
104 strbuf_addf(&buf, turn_off_instructions, key);
Junio C Hamano23cb5bf2011-12-22 11:21:26 -0800105
106 for (cp = buf.buf; *cp; cp = np) {
107 np = strchrnul(cp, '\n');
Junio C Hamano2d8cf942024-03-29 15:57:06 -0700108 fprintf(stderr, _("%shint:%s%.*s%s\n"),
Ryan Dammrose960786e2018-04-21 12:10:00 +0200109 advise_get_color(ADVICE_COLOR_HINT),
Junio C Hamano2d8cf942024-03-29 15:57:06 -0700110 (np == cp) ? "" : " ",
Ryan Dammrose960786e2018-04-21 12:10:00 +0200111 (int)(np - cp), cp,
112 advise_get_color(ADVICE_COLOR_RESET));
Junio C Hamano23cb5bf2011-12-22 11:21:26 -0800113 if (*np)
114 np++;
115 }
116 strbuf_release(&buf);
Ramkumar Ramachandra38ef61c2011-08-04 16:08:59 +0530117}
118
Heba Waly06ac2b32020-03-02 20:01:57 +0000119void advise(const char *advice, ...)
120{
121 va_list params;
122 va_start(params, advice);
Heba Walyb3b18d12020-03-02 20:01:59 +0000123 vadvise(advice, 0, "", params);
124 va_end(params);
125}
126
127int advice_enabled(enum advice_type type)
128{
Rubén Justod9199652024-01-15 15:28:28 +0100129 int enabled = advice_setting[type].level != ADVICE_LEVEL_DISABLED;
130
131 if (type == ADVICE_PUSH_UPDATE_REJECTED)
132 return enabled &&
133 advice_enabled(ADVICE_PUSH_UPDATE_REJECTED_ALIAS);
134
135 return enabled;
Heba Walyb3b18d12020-03-02 20:01:59 +0000136}
137
138void advise_if_enabled(enum advice_type type, const char *advice, ...)
139{
140 va_list params;
141
142 if (!advice_enabled(type))
143 return;
144
145 va_start(params, advice);
Rubén Justod9199652024-01-15 15:28:28 +0100146 vadvise(advice, !advice_setting[type].level, advice_setting[type].key,
147 params);
Heba Waly06ac2b32020-03-02 20:01:57 +0000148 va_end(params);
149}
150
Jeff King75194432009-09-09 07:38:58 -0400151int git_default_advice_config(const char *var, const char *value)
152{
Ryan Dammrose960786e2018-04-21 12:10:00 +0200153 const char *k, *slot_name;
Jeff King75194432009-09-09 07:38:58 -0400154 int i;
155
Ryan Dammrose960786e2018-04-21 12:10:00 +0200156 if (!strcmp(var, "color.advice")) {
157 advice_use_color = git_config_colorbool(var, value);
158 return 0;
159 }
160
161 if (skip_prefix(var, "color.advice.", &slot_name)) {
162 int slot = parse_advise_color_slot(slot_name);
163 if (slot < 0)
164 return 0;
165 if (!value)
166 return config_error_nonbool(var);
167 return color_parse(value, advice_colors[slot]);
168 }
169
Jeff Kingcf4fff52014-06-18 15:44:19 -0400170 if (!skip_prefix(var, "advice.", &k))
171 return 0;
172
Heba Walyb3b18d12020-03-02 20:01:59 +0000173 for (i = 0; i < ARRAY_SIZE(advice_setting); i++) {
174 if (strcasecmp(k, advice_setting[i].key))
175 continue;
Rubén Justod9199652024-01-15 15:28:28 +0100176 advice_setting[i].level = git_config_bool(var, value)
177 ? ADVICE_LEVEL_ENABLED
178 : ADVICE_LEVEL_DISABLED;
Jeff King75194432009-09-09 07:38:58 -0400179 return 0;
180 }
181
182 return 0;
183}
Matthieu Moyd38a30d2010-01-12 10:54:44 +0100184
Nguyễn Thái Ngọc Duy3ac68a92018-05-26 15:55:24 +0200185void list_config_advices(struct string_list *list, const char *prefix)
186{
187 int i;
188
Heba Walyb3b18d12020-03-02 20:01:59 +0000189 for (i = 0; i < ARRAY_SIZE(advice_setting); i++)
190 list_config_item(list, prefix, advice_setting[i].key);
Nguyễn Thái Ngọc Duy3ac68a92018-05-26 15:55:24 +0200191}
192
Ramkumar Ramachandra38ef61c2011-08-04 16:08:59 +0530193int error_resolve_conflict(const char *me)
Matthieu Moyd38a30d2010-01-12 10:54:44 +0100194{
Vasco Almeida8785c422016-06-17 20:20:52 +0000195 if (!strcmp(me, "cherry-pick"))
196 error(_("Cherry-picking is not possible because you have unmerged files."));
197 else if (!strcmp(me, "commit"))
198 error(_("Committing is not possible because you have unmerged files."));
199 else if (!strcmp(me, "merge"))
200 error(_("Merging is not possible because you have unmerged files."));
201 else if (!strcmp(me, "pull"))
202 error(_("Pulling is not possible because you have unmerged files."));
203 else if (!strcmp(me, "revert"))
204 error(_("Reverting is not possible because you have unmerged files."));
Oswald Buddenhagenff29a612023-08-07 19:09:35 +0200205 else if (!strcmp(me, "rebase"))
206 error(_("Rebasing is not possible because you have unmerged files."));
Vasco Almeida8785c422016-06-17 20:20:52 +0000207 else
Oswald Buddenhagenff29a612023-08-07 19:09:35 +0200208 BUG("Unhandled conflict reason '%s'", me);
Vasco Almeida8785c422016-06-17 20:20:52 +0000209
Ben Boeckeled9bff02021-08-23 12:44:00 +0200210 if (advice_enabled(ADVICE_RESOLVE_CONFLICT))
Matthieu Moyd38a30d2010-01-12 10:54:44 +0100211 /*
212 * Message used both when 'git commit' fails and when
213 * other commands doing a merge do.
214 */
Jeff Kingc057b242014-06-03 03:17:17 -0400215 advise(_("Fix them up in the work tree, and then use 'git add/rm <file>'\n"
Matthieu Moy91e70e02014-08-28 11:46:58 +0200216 "as appropriate to mark resolution and make a commit."));
Ramkumar Ramachandra38ef61c2011-08-04 16:08:59 +0530217 return -1;
218}
219
220void NORETURN die_resolve_conflict(const char *me)
221{
222 error_resolve_conflict(me);
Vasco Almeida8785c422016-06-17 20:20:52 +0000223 die(_("Exiting because of an unresolved conflict."));
Matthieu Moyd38a30d2010-01-12 10:54:44 +0100224}
Nguyễn Thái Ngọc Duy28570932012-01-16 16:46:16 +0700225
Paul Tan4a4cf9e2015-06-18 18:54:04 +0800226void NORETURN die_conclude_merge(void)
227{
228 error(_("You have not concluded your merge (MERGE_HEAD exists)."));
Ben Boeckeled9bff02021-08-23 12:44:00 +0200229 if (advice_enabled(ADVICE_RESOLVE_CONFLICT))
Alex Henrieb7447672015-10-01 22:25:33 -0600230 advise(_("Please, commit your changes before merging."));
Paul Tan4a4cf9e2015-06-18 18:54:04 +0800231 die(_("Exiting because of unfinished merge."));
232}
233
Alex Henrie3d5fc242021-07-21 01:42:19 +0000234void NORETURN die_ff_impossible(void)
235{
Felipe Contreras765071a2023-03-07 20:48:33 -0600236 advise_if_enabled(ADVICE_DIVERGING,
237 _("Diverging branches can't be fast-forwarded, you need to either:\n"
238 "\n"
239 "\tgit merge --no-ff\n"
240 "\n"
241 "or:\n"
242 "\n"
243 "\tgit rebase\n"));
Alex Henrie3d5fc242021-07-21 01:42:19 +0000244 die(_("Not possible to fast-forward, aborting."));
245}
246
Matheus Tavaresa20f7042021-04-08 17:41:27 -0300247void advise_on_updating_sparse_paths(struct string_list *pathspec_list)
248{
249 struct string_list_item *item;
250
251 if (!pathspec_list->nr)
252 return;
253
Derrick Stolee6579e782021-09-24 15:39:14 +0000254 fprintf(stderr, _("The following paths and/or pathspecs matched paths that exist\n"
255 "outside of your sparse-checkout definition, so will not be\n"
256 "updated in the index:\n"));
Matheus Tavaresa20f7042021-04-08 17:41:27 -0300257 for_each_string_list_item(item, pathspec_list)
258 fprintf(stderr, "%s\n", item->string);
259
260 advise_if_enabled(ADVICE_UPDATE_SPARSE_PATH,
Derrick Stolee6579e782021-09-24 15:39:14 +0000261 _("If you intend to update such entries, try one of the following:\n"
262 "* Use the --sparse option.\n"
263 "* Disable or modify the sparsity rules."));
Matheus Tavaresa20f7042021-04-08 17:41:27 -0300264}
265
Nguyễn Thái Ngọc Duy28570932012-01-16 16:46:16 +0700266void detach_advice(const char *new_name)
267{
Vasco Almeidae9f3cec2016-06-17 20:20:51 +0000268 const char *fmt =
Nguyễn Thái Ngọc Duy328c6cb2019-03-29 17:39:19 +0700269 _("Note: switching to '%s'.\n"
Nguyễn Thái Ngọc Duyaf9ded52019-03-29 17:38:58 +0700270 "\n"
Nguyễn Thái Ngọc Duy28570932012-01-16 16:46:16 +0700271 "You are in 'detached HEAD' state. You can look around, make experimental\n"
272 "changes and commit them, and you can discard any commits you make in this\n"
Nguyễn Thái Ngọc Duy328c6cb2019-03-29 17:39:19 +0700273 "state without impacting any branches by switching back to a branch.\n"
Nguyễn Thái Ngọc Duyaf9ded52019-03-29 17:38:58 +0700274 "\n"
Nguyễn Thái Ngọc Duy28570932012-01-16 16:46:16 +0700275 "If you want to create a new branch to retain commits you create, you may\n"
Nguyễn Thái Ngọc Duy328c6cb2019-03-29 17:39:19 +0700276 "do so (now or later) by using -c with the switch command. Example:\n"
Nguyễn Thái Ngọc Duyaf9ded52019-03-29 17:38:58 +0700277 "\n"
Nguyễn Thái Ngọc Duy328c6cb2019-03-29 17:39:19 +0700278 " git switch -c <new-branch-name>\n"
Nguyễn Thái Ngọc Duyaf9ded52019-03-29 17:38:58 +0700279 "\n"
Nguyễn Thái Ngọc Duy328c6cb2019-03-29 17:39:19 +0700280 "Or undo this operation with:\n"
Nguyễn Thái Ngọc Duyaf9ded52019-03-29 17:38:58 +0700281 "\n"
Nguyễn Thái Ngọc Duy328c6cb2019-03-29 17:39:19 +0700282 " git switch -\n"
Nguyễn Thái Ngọc Duyaf9ded52019-03-29 17:38:58 +0700283 "\n"
284 "Turn off this advice by setting config variable advice.detachedHead to false\n\n");
Nguyễn Thái Ngọc Duy28570932012-01-16 16:46:16 +0700285
286 fprintf(stderr, fmt, new_name);
287}
Shaoxuan Yuan5efd5332022-08-09 20:09:09 +0800288
289void advise_on_moving_dirty_path(struct string_list *pathspec_list)
290{
291 struct string_list_item *item;
292
293 if (!pathspec_list->nr)
294 return;
295
296 fprintf(stderr, _("The following paths have been moved outside the\n"
297 "sparse-checkout definition but are not sparse due to local\n"
298 "modifications.\n"));
299 for_each_string_list_item(item, pathspec_list)
300 fprintf(stderr, "%s\n", item->string);
301
302 advise_if_enabled(ADVICE_UPDATE_SPARSE_PATH,
303 _("To correct the sparsity of these paths, do the following:\n"
304 "* Use \"git add --sparse <paths>\" to update the index\n"
305 "* Use \"git sparse-checkout reapply\" to apply the sparsity rules"));
306}