]> git.ipfire.org Git - thirdparty/git.git/blame - advice.c
advice: add --no-advice global option
[thirdparty/git.git] / advice.c
CommitLineData
fc7bd51b
EN
1#include "git-compat-util.h"
2#include "advice.h"
b2141fc1 3#include "config.h"
960786e7 4#include "color.h"
b79deeb5 5#include "environment.h"
fc7bd51b 6#include "gettext.h"
3ac68a93 7#include "help.h"
a20f7047 8#include "string-list.h"
75194438 9
960786e7
RD
10static int advice_use_color = -1;
11static char advice_colors[][COLOR_MAXLEN] = {
12 GIT_COLOR_RESET,
13 GIT_COLOR_YELLOW, /* HINT */
14};
15
16enum color_advice {
17 ADVICE_COLOR_RESET = 0,
18 ADVICE_COLOR_HINT = 1,
19};
20
21static int parse_advise_color_slot(const char *slot)
22{
23 if (!strcasecmp(slot, "reset"))
24 return ADVICE_COLOR_RESET;
25 if (!strcasecmp(slot, "hint"))
26 return ADVICE_COLOR_HINT;
27 return -1;
28}
29
30static const char *advise_get_color(enum color_advice ix)
31{
32 if (want_color_stderr(advice_use_color))
33 return advice_colors[ix];
34 return "";
35}
36
d919965a
RJ
37enum advice_level {
38 ADVICE_LEVEL_NONE = 0,
39 ADVICE_LEVEL_DISABLED,
40 ADVICE_LEVEL_ENABLED,
41};
42
b3b18d16
HW
43static struct {
44 const char *key;
d919965a 45 enum advice_level level;
b3b18d16 46} advice_setting[] = {
d919965a
RJ
47 [ADVICE_ADD_EMBEDDED_REPO] = { "addEmbeddedRepo" },
48 [ADVICE_ADD_EMPTY_PATHSPEC] = { "addEmptyPathspec" },
49 [ADVICE_ADD_IGNORED_FILE] = { "addIgnoredFile" },
50 [ADVICE_AMBIGUOUS_FETCH_REFSPEC] = { "ambiguousFetchRefspec" },
51 [ADVICE_AM_WORK_DIR] = { "amWorkDir" },
52 [ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME] = { "checkoutAmbiguousRemoteBranchName" },
53 [ADVICE_COMMIT_BEFORE_MERGE] = { "commitBeforeMerge" },
54 [ADVICE_DETACHED_HEAD] = { "detachedHead" },
55 [ADVICE_DIVERGING] = { "diverging" },
56 [ADVICE_FETCH_SHOW_FORCED_UPDATES] = { "fetchShowForcedUpdates" },
57 [ADVICE_FORCE_DELETE_BRANCH] = { "forceDeleteBranch" },
58 [ADVICE_GRAFT_FILE_DEPRECATED] = { "graftFileDeprecated" },
59 [ADVICE_IGNORED_HOOK] = { "ignoredHook" },
60 [ADVICE_IMPLICIT_IDENTITY] = { "implicitIdentity" },
ec030091 61 [ADVICE_MERGE_CONFLICT] = { "mergeConflict" },
d919965a
RJ
62 [ADVICE_NESTED_TAG] = { "nestedTag" },
63 [ADVICE_OBJECT_NAME_WARNING] = { "objectNameWarning" },
64 [ADVICE_PUSH_ALREADY_EXISTS] = { "pushAlreadyExists" },
65 [ADVICE_PUSH_FETCH_FIRST] = { "pushFetchFirst" },
66 [ADVICE_PUSH_NEEDS_FORCE] = { "pushNeedsForce" },
67 [ADVICE_PUSH_NON_FF_CURRENT] = { "pushNonFFCurrent" },
68 [ADVICE_PUSH_NON_FF_MATCHING] = { "pushNonFFMatching" },
69 [ADVICE_PUSH_REF_NEEDS_UPDATE] = { "pushRefNeedsUpdate" },
70 [ADVICE_PUSH_UNQUALIFIED_REF_NAME] = { "pushUnqualifiedRefName" },
71 [ADVICE_PUSH_UPDATE_REJECTED] = { "pushUpdateRejected" },
72 [ADVICE_PUSH_UPDATE_REJECTED_ALIAS] = { "pushNonFastForward" }, /* backwards compatibility */
8fbd903e 73 [ADVICE_REF_SYNTAX] = { "refSyntax" },
d919965a
RJ
74 [ADVICE_RESET_NO_REFRESH_WARNING] = { "resetNoRefresh" },
75 [ADVICE_RESOLVE_CONFLICT] = { "resolveConflict" },
76 [ADVICE_RM_HINTS] = { "rmHints" },
77 [ADVICE_SEQUENCER_IN_USE] = { "sequencerInUse" },
78 [ADVICE_SET_UPSTREAM_FAILURE] = { "setUpstreamFailure" },
79 [ADVICE_SKIPPED_CHERRY_PICKS] = { "skippedCherryPicks" },
80 [ADVICE_STATUS_AHEAD_BEHIND_WARNING] = { "statusAheadBehindWarning" },
81 [ADVICE_STATUS_HINTS] = { "statusHints" },
82 [ADVICE_STATUS_U_OPTION] = { "statusUoption" },
83 [ADVICE_SUBMODULES_NOT_UPDATED] = { "submodulesNotUpdated" },
84 [ADVICE_SUBMODULE_ALTERNATE_ERROR_STRATEGY_DIE] = { "submoduleAlternateErrorStrategyDie" },
b9e55be7 85 [ADVICE_SUBMODULE_MERGE_CONFLICT] = { "submoduleMergeConflict" },
d919965a
RJ
86 [ADVICE_SUGGEST_DETACHING_HEAD] = { "suggestDetachingHead" },
87 [ADVICE_UPDATE_SPARSE_PATH] = { "updateSparsePath" },
88 [ADVICE_WAITING_FOR_EDITOR] = { "waitingForEditor" },
89 [ADVICE_WORKTREE_ADD_ORPHAN] = { "worktreeAddOrphan" },
b3b18d16
HW
90};
91
92static const char turn_off_instructions[] =
93N_("\n"
94 "Disable this message with \"git config advice.%s false\"");
95
96static void vadvise(const char *advice, int display_instructions,
97 const char *key, va_list params)
38ef61cf 98{
23cb5bf3 99 struct strbuf buf = STRBUF_INIT;
23cb5bf3 100 const char *cp, *np;
38ef61cf 101
447b99c8 102 strbuf_vaddf(&buf, advice, params);
23cb5bf3 103
b3b18d16
HW
104 if (display_instructions)
105 strbuf_addf(&buf, turn_off_instructions, key);
23cb5bf3
JH
106
107 for (cp = buf.buf; *cp; cp = np) {
108 np = strchrnul(cp, '\n');
2d8cf94b 109 fprintf(stderr, _("%shint:%s%.*s%s\n"),
960786e7 110 advise_get_color(ADVICE_COLOR_HINT),
2d8cf94b 111 (np == cp) ? "" : " ",
960786e7
RD
112 (int)(np - cp), cp,
113 advise_get_color(ADVICE_COLOR_RESET));
23cb5bf3
JH
114 if (*np)
115 np++;
116 }
117 strbuf_release(&buf);
38ef61cf
RR
118}
119
06ac2b3b
HW
120void advise(const char *advice, ...)
121{
122 va_list params;
123 va_start(params, advice);
b3b18d16
HW
124 vadvise(advice, 0, "", params);
125 va_end(params);
126}
127
128int advice_enabled(enum advice_type type)
129{
d919965a 130 int enabled = advice_setting[type].level != ADVICE_LEVEL_DISABLED;
b79deeb5
JL
131 static int globally_enabled = -1;
132
133 if (globally_enabled < 0)
134 globally_enabled = git_env_bool(GIT_ADVICE_ENVIRONMENT, 1);
135 if (!globally_enabled)
136 return 0;
d919965a
RJ
137
138 if (type == ADVICE_PUSH_UPDATE_REJECTED)
139 return enabled &&
140 advice_enabled(ADVICE_PUSH_UPDATE_REJECTED_ALIAS);
141
142 return enabled;
b3b18d16
HW
143}
144
145void advise_if_enabled(enum advice_type type, const char *advice, ...)
146{
147 va_list params;
148
149 if (!advice_enabled(type))
150 return;
151
152 va_start(params, advice);
d919965a
RJ
153 vadvise(advice, !advice_setting[type].level, advice_setting[type].key,
154 params);
06ac2b3b
HW
155 va_end(params);
156}
157
75194438
JK
158int git_default_advice_config(const char *var, const char *value)
159{
960786e7 160 const char *k, *slot_name;
75194438
JK
161 int i;
162
960786e7
RD
163 if (!strcmp(var, "color.advice")) {
164 advice_use_color = git_config_colorbool(var, value);
165 return 0;
166 }
167
168 if (skip_prefix(var, "color.advice.", &slot_name)) {
169 int slot = parse_advise_color_slot(slot_name);
170 if (slot < 0)
171 return 0;
172 if (!value)
173 return config_error_nonbool(var);
174 return color_parse(value, advice_colors[slot]);
175 }
176
cf4fff57
JK
177 if (!skip_prefix(var, "advice.", &k))
178 return 0;
179
b3b18d16
HW
180 for (i = 0; i < ARRAY_SIZE(advice_setting); i++) {
181 if (strcasecmp(k, advice_setting[i].key))
182 continue;
d919965a
RJ
183 advice_setting[i].level = git_config_bool(var, value)
184 ? ADVICE_LEVEL_ENABLED
185 : ADVICE_LEVEL_DISABLED;
75194438
JK
186 return 0;
187 }
188
189 return 0;
190}
d38a30df 191
3ac68a93
NTND
192void list_config_advices(struct string_list *list, const char *prefix)
193{
194 int i;
195
b3b18d16
HW
196 for (i = 0; i < ARRAY_SIZE(advice_setting); i++)
197 list_config_item(list, prefix, advice_setting[i].key);
3ac68a93
NTND
198}
199
38ef61cf 200int error_resolve_conflict(const char *me)
d38a30df 201{
8785c425
VA
202 if (!strcmp(me, "cherry-pick"))
203 error(_("Cherry-picking is not possible because you have unmerged files."));
204 else if (!strcmp(me, "commit"))
205 error(_("Committing is not possible because you have unmerged files."));
206 else if (!strcmp(me, "merge"))
207 error(_("Merging is not possible because you have unmerged files."));
208 else if (!strcmp(me, "pull"))
209 error(_("Pulling is not possible because you have unmerged files."));
210 else if (!strcmp(me, "revert"))
211 error(_("Reverting is not possible because you have unmerged files."));
ff29a61c
OB
212 else if (!strcmp(me, "rebase"))
213 error(_("Rebasing is not possible because you have unmerged files."));
8785c425 214 else
ff29a61c 215 BUG("Unhandled conflict reason '%s'", me);
8785c425 216
ed9bff08 217 if (advice_enabled(ADVICE_RESOLVE_CONFLICT))
d38a30df
MM
218 /*
219 * Message used both when 'git commit' fails and when
220 * other commands doing a merge do.
221 */
c057b242 222 advise(_("Fix them up in the work tree, and then use 'git add/rm <file>'\n"
91e70e00 223 "as appropriate to mark resolution and make a commit."));
38ef61cf
RR
224 return -1;
225}
226
227void NORETURN die_resolve_conflict(const char *me)
228{
229 error_resolve_conflict(me);
8785c425 230 die(_("Exiting because of an unresolved conflict."));
d38a30df 231}
2857093b 232
4a4cf9e8
PT
233void NORETURN die_conclude_merge(void)
234{
235 error(_("You have not concluded your merge (MERGE_HEAD exists)."));
ed9bff08 236 if (advice_enabled(ADVICE_RESOLVE_CONFLICT))
b7447679 237 advise(_("Please, commit your changes before merging."));
4a4cf9e8
PT
238 die(_("Exiting because of unfinished merge."));
239}
240
3d5fc24d
AH
241void NORETURN die_ff_impossible(void)
242{
765071a8
FC
243 advise_if_enabled(ADVICE_DIVERGING,
244 _("Diverging branches can't be fast-forwarded, you need to either:\n"
245 "\n"
246 "\tgit merge --no-ff\n"
247 "\n"
248 "or:\n"
249 "\n"
250 "\tgit rebase\n"));
3d5fc24d
AH
251 die(_("Not possible to fast-forward, aborting."));
252}
253
a20f7047
MT
254void advise_on_updating_sparse_paths(struct string_list *pathspec_list)
255{
256 struct string_list_item *item;
257
258 if (!pathspec_list->nr)
259 return;
260
6579e788
DS
261 fprintf(stderr, _("The following paths and/or pathspecs matched paths that exist\n"
262 "outside of your sparse-checkout definition, so will not be\n"
263 "updated in the index:\n"));
a20f7047
MT
264 for_each_string_list_item(item, pathspec_list)
265 fprintf(stderr, "%s\n", item->string);
266
267 advise_if_enabled(ADVICE_UPDATE_SPARSE_PATH,
6579e788
DS
268 _("If you intend to update such entries, try one of the following:\n"
269 "* Use the --sparse option.\n"
270 "* Disable or modify the sparsity rules."));
a20f7047
MT
271}
272
2857093b
NTND
273void detach_advice(const char *new_name)
274{
e9f3cec4 275 const char *fmt =
328c6cb8 276 _("Note: switching to '%s'.\n"
af9ded5b 277 "\n"
2857093b
NTND
278 "You are in 'detached HEAD' state. You can look around, make experimental\n"
279 "changes and commit them, and you can discard any commits you make in this\n"
328c6cb8 280 "state without impacting any branches by switching back to a branch.\n"
af9ded5b 281 "\n"
2857093b 282 "If you want to create a new branch to retain commits you create, you may\n"
328c6cb8 283 "do so (now or later) by using -c with the switch command. Example:\n"
af9ded5b 284 "\n"
328c6cb8 285 " git switch -c <new-branch-name>\n"
af9ded5b 286 "\n"
328c6cb8 287 "Or undo this operation with:\n"
af9ded5b 288 "\n"
328c6cb8 289 " git switch -\n"
af9ded5b
NTND
290 "\n"
291 "Turn off this advice by setting config variable advice.detachedHead to false\n\n");
2857093b
NTND
292
293 fprintf(stderr, fmt, new_name);
294}
5efd533e
SY
295
296void advise_on_moving_dirty_path(struct string_list *pathspec_list)
297{
298 struct string_list_item *item;
299
300 if (!pathspec_list->nr)
301 return;
302
303 fprintf(stderr, _("The following paths have been moved outside the\n"
304 "sparse-checkout definition but are not sparse due to local\n"
305 "modifications.\n"));
306 for_each_string_list_item(item, pathspec_list)
307 fprintf(stderr, "%s\n", item->string);
308
309 advise_if_enabled(ADVICE_UPDATE_SPARSE_PATH,
310 _("To correct the sparsity of these paths, do the following:\n"
311 "* Use \"git add --sparse <paths>\" to update the index\n"
312 "* Use \"git sparse-checkout reapply\" to apply the sparsity rules"));
313}