advice: allow disabling the automatic hint in advise_if_enabled()

Using advise_if_enabled() to display an advice will automatically include instructions on how to disable the advice, alongside the main advice: hint: use --reapply-cherry-picks to include skipped commits hint: Disable this message with "git config advice.skippedCherryPicks false" To do so, we provide a knob which can be used to disable the advice. But also to tell us the opposite: to show the advice. Let's not include the deactivation instructions for an advice if the user explicitly sets its visibility. Signed-off-by: Rubén Justo <rjusto@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Rubén Justo committed Jan 15, 2024 at 15:28 UTC d919965af116d145de40853caf0e4228c97da325
3 files changed +62 -53
Documentation/config/advice.txt
+3 -2
@@ -1,7 +1,8 @@
1 advice.*::
2 These variables control various optional help messages designed to
3 - aid new users. All 'advice.*' variables default to 'true', and you
4 - can tell Git that you do not need help by setting these to 'false':
3 + aid new users. When left unconfigured, Git will give the message
4 + alongside instructions on how to squelch it. You can tell Git
5 + that you do not need the help message by setting these to 'false':
6 +
7 --
8 addEmbeddedRepo::
advice.c
+59 -50
@@ -33,50 +33,56 @@ static const char *advise_get_color(enum color_advice ix)
33 return "";
34 }
35
36 +enum advice_level {
37 + ADVICE_LEVEL_NONE = 0,
38 + ADVICE_LEVEL_DISABLED,
39 + ADVICE_LEVEL_ENABLED,
40 +};
41 +
42 static struct {
43 const char *key;
38 - int enabled;
44 + enum advice_level level;
45 } advice_setting[] = {
40 - [ADVICE_ADD_EMBEDDED_REPO] = { "addEmbeddedRepo", 1 },
41 - [ADVICE_ADD_EMPTY_PATHSPEC] = { "addEmptyPathspec", 1 },
42 - [ADVICE_ADD_IGNORED_FILE] = { "addIgnoredFile", 1 },
43 - [ADVICE_AMBIGUOUS_FETCH_REFSPEC] = { "ambiguousFetchRefspec", 1 },
44 - [ADVICE_AM_WORK_DIR] = { "amWorkDir", 1 },
45 - [ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME] = { "checkoutAmbiguousRemoteBranchName", 1 },
46 - [ADVICE_COMMIT_BEFORE_MERGE] = { "commitBeforeMerge", 1 },
47 - [ADVICE_DETACHED_HEAD] = { "detachedHead", 1 },
48 - [ADVICE_DIVERGING] = { "diverging", 1 },
49 - [ADVICE_FETCH_SHOW_FORCED_UPDATES] = { "fetchShowForcedUpdates", 1 },
50 - [ADVICE_FORCE_DELETE_BRANCH] = { "forceDeleteBranch", 1 },
51 - [ADVICE_GRAFT_FILE_DEPRECATED] = { "graftFileDeprecated", 1 },
52 - [ADVICE_IGNORED_HOOK] = { "ignoredHook", 1 },
53 - [ADVICE_IMPLICIT_IDENTITY] = { "implicitIdentity", 1 },
54 - [ADVICE_NESTED_TAG] = { "nestedTag", 1 },
55 - [ADVICE_OBJECT_NAME_WARNING] = { "objectNameWarning", 1 },
56 - [ADVICE_PUSH_ALREADY_EXISTS] = { "pushAlreadyExists", 1 },
57 - [ADVICE_PUSH_FETCH_FIRST] = { "pushFetchFirst", 1 },
58 - [ADVICE_PUSH_NEEDS_FORCE] = { "pushNeedsForce", 1 },
59 - [ADVICE_PUSH_NON_FF_CURRENT] = { "pushNonFFCurrent", 1 },
60 - [ADVICE_PUSH_NON_FF_MATCHING] = { "pushNonFFMatching", 1 },
61 - [ADVICE_PUSH_REF_NEEDS_UPDATE] = { "pushRefNeedsUpdate", 1 },
62 - [ADVICE_PUSH_UNQUALIFIED_REF_NAME] = { "pushUnqualifiedRefName", 1 },
63 - [ADVICE_PUSH_UPDATE_REJECTED] = { "pushUpdateRejected", 1 },
64 - [ADVICE_PUSH_UPDATE_REJECTED_ALIAS] = { "pushNonFastForward", 1 }, /* backwards compatibility */
65 - [ADVICE_RESET_NO_REFRESH_WARNING] = { "resetNoRefresh", 1 },
66 - [ADVICE_RESOLVE_CONFLICT] = { "resolveConflict", 1 },
67 - [ADVICE_RM_HINTS] = { "rmHints", 1 },
68 - [ADVICE_SEQUENCER_IN_USE] = { "sequencerInUse", 1 },
69 - [ADVICE_SET_UPSTREAM_FAILURE] = { "setUpstreamFailure", 1 },
70 - [ADVICE_SKIPPED_CHERRY_PICKS] = { "skippedCherryPicks", 1 },
71 - [ADVICE_STATUS_AHEAD_BEHIND_WARNING] = { "statusAheadBehindWarning", 1 },
72 - [ADVICE_STATUS_HINTS] = { "statusHints", 1 },
73 - [ADVICE_STATUS_U_OPTION] = { "statusUoption", 1 },
74 - [ADVICE_SUBMODULES_NOT_UPDATED] = { "submodulesNotUpdated", 1 },
75 - [ADVICE_SUBMODULE_ALTERNATE_ERROR_STRATEGY_DIE] = { "submoduleAlternateErrorStrategyDie", 1 },
76 - [ADVICE_SUGGEST_DETACHING_HEAD] = { "suggestDetachingHead", 1 },
77 - [ADVICE_UPDATE_SPARSE_PATH] = { "updateSparsePath", 1 },
78 - [ADVICE_WAITING_FOR_EDITOR] = { "waitingForEditor", 1 },
79 - [ADVICE_WORKTREE_ADD_ORPHAN] = { "worktreeAddOrphan", 1 },
46 + [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" },
60 + [ADVICE_NESTED_TAG] = { "nestedTag" },
61 + [ADVICE_OBJECT_NAME_WARNING] = { "objectNameWarning" },
62 + [ADVICE_PUSH_ALREADY_EXISTS] = { "pushAlreadyExists" },
63 + [ADVICE_PUSH_FETCH_FIRST] = { "pushFetchFirst" },
64 + [ADVICE_PUSH_NEEDS_FORCE] = { "pushNeedsForce" },
65 + [ADVICE_PUSH_NON_FF_CURRENT] = { "pushNonFFCurrent" },
66 + [ADVICE_PUSH_NON_FF_MATCHING] = { "pushNonFFMatching" },
67 + [ADVICE_PUSH_REF_NEEDS_UPDATE] = { "pushRefNeedsUpdate" },
68 + [ADVICE_PUSH_UNQUALIFIED_REF_NAME] = { "pushUnqualifiedRefName" },
69 + [ADVICE_PUSH_UPDATE_REJECTED] = { "pushUpdateRejected" },
70 + [ADVICE_PUSH_UPDATE_REJECTED_ALIAS] = { "pushNonFastForward" }, /* backwards compatibility */
71 + [ADVICE_RESET_NO_REFRESH_WARNING] = { "resetNoRefresh" },
72 + [ADVICE_RESOLVE_CONFLICT] = { "resolveConflict" },
73 + [ADVICE_RM_HINTS] = { "rmHints" },
74 + [ADVICE_SEQUENCER_IN_USE] = { "sequencerInUse" },
75 + [ADVICE_SET_UPSTREAM_FAILURE] = { "setUpstreamFailure" },
76 + [ADVICE_SKIPPED_CHERRY_PICKS] = { "skippedCherryPicks" },
77 + [ADVICE_STATUS_AHEAD_BEHIND_WARNING] = { "statusAheadBehindWarning" },
78 + [ADVICE_STATUS_HINTS] = { "statusHints" },
79 + [ADVICE_STATUS_U_OPTION] = { "statusUoption" },
80 + [ADVICE_SUBMODULES_NOT_UPDATED] = { "submodulesNotUpdated" },
81 + [ADVICE_SUBMODULE_ALTERNATE_ERROR_STRATEGY_DIE] = { "submoduleAlternateErrorStrategyDie" },
82 + [ADVICE_SUGGEST_DETACHING_HEAD] = { "suggestDetachingHead" },
83 + [ADVICE_UPDATE_SPARSE_PATH] = { "updateSparsePath" },
84 + [ADVICE_WAITING_FOR_EDITOR] = { "waitingForEditor" },
85 + [ADVICE_WORKTREE_ADD_ORPHAN] = { "worktreeAddOrphan" },
86 };
87
88 static const char turn_off_instructions[] =
@@ -116,13 +122,13 @@ void advise(const char *advice, ...)
122
123 int advice_enabled(enum advice_type type)
124 {
119 - switch(type) {
120 - case ADVICE_PUSH_UPDATE_REJECTED:
121 - return advice_setting[ADVICE_PUSH_UPDATE_REJECTED].enabled &&
122 - advice_setting[ADVICE_PUSH_UPDATE_REJECTED_ALIAS].enabled;
123 - default:
124 - return advice_setting[type].enabled;
125 - }
125 + int enabled = advice_setting[type].level != ADVICE_LEVEL_DISABLED;
126 +
127 + if (type == ADVICE_PUSH_UPDATE_REJECTED)
128 + return enabled &&
129 + advice_enabled(ADVICE_PUSH_UPDATE_REJECTED_ALIAS);
130 +
131 + return enabled;
132 }
133
134 void advise_if_enabled(enum advice_type type, const char *advice, ...)
@@ -133,7 +139,8 @@ void advise_if_enabled(enum advice_type type, const char *advice, ...)
139 return;
140
141 va_start(params, advice);
136 - vadvise(advice, 1, advice_setting[type].key, params);
142 + vadvise(advice, !advice_setting[type].level, advice_setting[type].key,
143 + params);
144 va_end(params);
145 }
146
@@ -162,7 +169,9 @@ int git_default_advice_config(const char *var, const char *value)
169 for (i = 0; i < ARRAY_SIZE(advice_setting); i++) {
170 if (strcasecmp(k, advice_setting[i].key))
171 continue;
165 - advice_setting[i].enabled = git_config_bool(var, value);
172 + advice_setting[i].level = git_config_bool(var, value)
173 + ? ADVICE_LEVEL_ENABLED
174 + : ADVICE_LEVEL_DISABLED;
175 return 0;
176 }
177
t/t0018-advice.sh
-1
@@ -17,7 +17,6 @@ test_expect_success 'advice should be printed when config variable is unset' '
17 test_expect_success 'advice should be printed when config variable is set to true' '
18 cat >expect <<-\EOF &&
19 hint: This is a piece of advice
20 - hint: Disable this message with "git config advice.nestedTag false"
20 EOF
21 test_config advice.nestedTag true &&
22 test-tool advise "This is a piece of advice" 2>actual &&