git

Форк
0
/
advice.c 
315 строк · 9.5 Кб
1
#include "git-compat-util.h"
2
#include "advice.h"
3
#include "config.h"
4
#include "color.h"
5
#include "environment.h"
6
#include "gettext.h"
7
#include "help.h"
8
#include "string-list.h"
9

10
static int advice_use_color = -1;
11
static char advice_colors[][COLOR_MAXLEN] = {
12
	GIT_COLOR_RESET,
13
	GIT_COLOR_YELLOW,	/* HINT */
14
};
15

16
enum color_advice {
17
	ADVICE_COLOR_RESET = 0,
18
	ADVICE_COLOR_HINT = 1,
19
};
20

21
static 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

30
static 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

37
enum advice_level {
38
	ADVICE_LEVEL_NONE = 0,
39
	ADVICE_LEVEL_DISABLED,
40
	ADVICE_LEVEL_ENABLED,
41
};
42

43
static struct {
44
	const char *key;
45
	enum advice_level level;
46
} advice_setting[] = {
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" },
61
	[ADVICE_MERGE_CONFLICT]				= { "mergeConflict" },
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 */
73
	[ADVICE_REBASE_TODO_ERROR]			= { "rebaseTodoError" },
74
	[ADVICE_REF_SYNTAX]				= { "refSyntax" },
75
	[ADVICE_RESET_NO_REFRESH_WARNING]		= { "resetNoRefresh" },
76
	[ADVICE_RESOLVE_CONFLICT]			= { "resolveConflict" },
77
	[ADVICE_RM_HINTS]				= { "rmHints" },
78
	[ADVICE_SEQUENCER_IN_USE]			= { "sequencerInUse" },
79
	[ADVICE_SET_UPSTREAM_FAILURE]			= { "setUpstreamFailure" },
80
	[ADVICE_SKIPPED_CHERRY_PICKS]			= { "skippedCherryPicks" },
81
	[ADVICE_SPARSE_INDEX_EXPANDED]			= { "sparseIndexExpanded" },
82
	[ADVICE_STATUS_AHEAD_BEHIND_WARNING]		= { "statusAheadBehindWarning" },
83
	[ADVICE_STATUS_HINTS]				= { "statusHints" },
84
	[ADVICE_STATUS_U_OPTION]			= { "statusUoption" },
85
	[ADVICE_SUBMODULES_NOT_UPDATED] 		= { "submodulesNotUpdated" },
86
	[ADVICE_SUBMODULE_ALTERNATE_ERROR_STRATEGY_DIE] = { "submoduleAlternateErrorStrategyDie" },
87
	[ADVICE_SUBMODULE_MERGE_CONFLICT]               = { "submoduleMergeConflict" },
88
	[ADVICE_SUGGEST_DETACHING_HEAD]			= { "suggestDetachingHead" },
89
	[ADVICE_UPDATE_SPARSE_PATH]			= { "updateSparsePath" },
90
	[ADVICE_WAITING_FOR_EDITOR]			= { "waitingForEditor" },
91
	[ADVICE_WORKTREE_ADD_ORPHAN]			= { "worktreeAddOrphan" },
92
};
93

94
static const char turn_off_instructions[] =
95
N_("\n"
96
   "Disable this message with \"git config advice.%s false\"");
97

98
static void vadvise(const char *advice, int display_instructions,
99
		    const char *key, va_list params)
100
{
101
	struct strbuf buf = STRBUF_INIT;
102
	const char *cp, *np;
103

104
	strbuf_vaddf(&buf, advice, params);
105

106
	if (display_instructions)
107
		strbuf_addf(&buf, turn_off_instructions, key);
108

109
	for (cp = buf.buf; *cp; cp = np) {
110
		np = strchrnul(cp, '\n');
111
		fprintf(stderr,	_("%shint:%s%.*s%s\n"),
112
			advise_get_color(ADVICE_COLOR_HINT),
113
			(np == cp) ? "" : " ",
114
			(int)(np - cp), cp,
115
			advise_get_color(ADVICE_COLOR_RESET));
116
		if (*np)
117
			np++;
118
	}
119
	strbuf_release(&buf);
120
}
121

122
void advise(const char *advice, ...)
123
{
124
	va_list params;
125
	va_start(params, advice);
126
	vadvise(advice, 0, "", params);
127
	va_end(params);
128
}
129

130
int advice_enabled(enum advice_type type)
131
{
132
	int enabled = advice_setting[type].level != ADVICE_LEVEL_DISABLED;
133
	static int globally_enabled = -1;
134

135
	if (globally_enabled < 0)
136
		globally_enabled = git_env_bool(GIT_ADVICE_ENVIRONMENT, 1);
137
	if (!globally_enabled)
138
		return 0;
139

140
	if (type == ADVICE_PUSH_UPDATE_REJECTED)
141
		return enabled &&
142
		       advice_enabled(ADVICE_PUSH_UPDATE_REJECTED_ALIAS);
143

144
	return enabled;
145
}
146

147
void advise_if_enabled(enum advice_type type, const char *advice, ...)
148
{
149
	va_list params;
150

151
	if (!advice_enabled(type))
152
		return;
153

154
	va_start(params, advice);
155
	vadvise(advice, !advice_setting[type].level, advice_setting[type].key,
156
		params);
157
	va_end(params);
158
}
159

160
int git_default_advice_config(const char *var, const char *value)
161
{
162
	const char *k, *slot_name;
163
	int i;
164

165
	if (!strcmp(var, "color.advice")) {
166
		advice_use_color = git_config_colorbool(var, value);
167
		return 0;
168
	}
169

170
	if (skip_prefix(var, "color.advice.", &slot_name)) {
171
		int slot = parse_advise_color_slot(slot_name);
172
		if (slot < 0)
173
			return 0;
174
		if (!value)
175
			return config_error_nonbool(var);
176
		return color_parse(value, advice_colors[slot]);
177
	}
178

179
	if (!skip_prefix(var, "advice.", &k))
180
		return 0;
181

182
	for (i = 0; i < ARRAY_SIZE(advice_setting); i++) {
183
		if (strcasecmp(k, advice_setting[i].key))
184
			continue;
185
		advice_setting[i].level = git_config_bool(var, value)
186
					  ? ADVICE_LEVEL_ENABLED
187
					  : ADVICE_LEVEL_DISABLED;
188
		return 0;
189
	}
190

191
	return 0;
192
}
193

194
void list_config_advices(struct string_list *list, const char *prefix)
195
{
196
	int i;
197

198
	for (i = 0; i < ARRAY_SIZE(advice_setting); i++)
199
		list_config_item(list, prefix, advice_setting[i].key);
200
}
201

202
int error_resolve_conflict(const char *me)
203
{
204
	if (!strcmp(me, "cherry-pick"))
205
		error(_("Cherry-picking is not possible because you have unmerged files."));
206
	else if (!strcmp(me, "commit"))
207
		error(_("Committing is not possible because you have unmerged files."));
208
	else if (!strcmp(me, "merge"))
209
		error(_("Merging is not possible because you have unmerged files."));
210
	else if (!strcmp(me, "pull"))
211
		error(_("Pulling is not possible because you have unmerged files."));
212
	else if (!strcmp(me, "revert"))
213
		error(_("Reverting is not possible because you have unmerged files."));
214
	else if (!strcmp(me, "rebase"))
215
		error(_("Rebasing is not possible because you have unmerged files."));
216
	else
217
		BUG("Unhandled conflict reason '%s'", me);
218

219
	if (advice_enabled(ADVICE_RESOLVE_CONFLICT))
220
		/*
221
		 * Message used both when 'git commit' fails and when
222
		 * other commands doing a merge do.
223
		 */
224
		advise(_("Fix them up in the work tree, and then use 'git add/rm <file>'\n"
225
			 "as appropriate to mark resolution and make a commit."));
226
	return -1;
227
}
228

229
void NORETURN die_resolve_conflict(const char *me)
230
{
231
	error_resolve_conflict(me);
232
	die(_("Exiting because of an unresolved conflict."));
233
}
234

235
void NORETURN die_conclude_merge(void)
236
{
237
	error(_("You have not concluded your merge (MERGE_HEAD exists)."));
238
	if (advice_enabled(ADVICE_RESOLVE_CONFLICT))
239
		advise(_("Please, commit your changes before merging."));
240
	die(_("Exiting because of unfinished merge."));
241
}
242

243
void NORETURN die_ff_impossible(void)
244
{
245
	advise_if_enabled(ADVICE_DIVERGING,
246
		_("Diverging branches can't be fast-forwarded, you need to either:\n"
247
		"\n"
248
		"\tgit merge --no-ff\n"
249
		"\n"
250
		"or:\n"
251
		"\n"
252
		"\tgit rebase\n"));
253
	die(_("Not possible to fast-forward, aborting."));
254
}
255

256
void advise_on_updating_sparse_paths(struct string_list *pathspec_list)
257
{
258
	struct string_list_item *item;
259

260
	if (!pathspec_list->nr)
261
		return;
262

263
	fprintf(stderr, _("The following paths and/or pathspecs matched paths that exist\n"
264
			  "outside of your sparse-checkout definition, so will not be\n"
265
			  "updated in the index:\n"));
266
	for_each_string_list_item(item, pathspec_list)
267
		fprintf(stderr, "%s\n", item->string);
268

269
	advise_if_enabled(ADVICE_UPDATE_SPARSE_PATH,
270
			  _("If you intend to update such entries, try one of the following:\n"
271
			    "* Use the --sparse option.\n"
272
			    "* Disable or modify the sparsity rules."));
273
}
274

275
void detach_advice(const char *new_name)
276
{
277
	const char *fmt =
278
	_("Note: switching to '%s'.\n"
279
	"\n"
280
	"You are in 'detached HEAD' state. You can look around, make experimental\n"
281
	"changes and commit them, and you can discard any commits you make in this\n"
282
	"state without impacting any branches by switching back to a branch.\n"
283
	"\n"
284
	"If you want to create a new branch to retain commits you create, you may\n"
285
	"do so (now or later) by using -c with the switch command. Example:\n"
286
	"\n"
287
	"  git switch -c <new-branch-name>\n"
288
	"\n"
289
	"Or undo this operation with:\n"
290
	"\n"
291
	"  git switch -\n"
292
	"\n"
293
	"Turn off this advice by setting config variable advice.detachedHead to false\n\n");
294

295
	fprintf(stderr, fmt, new_name);
296
}
297

298
void advise_on_moving_dirty_path(struct string_list *pathspec_list)
299
{
300
	struct string_list_item *item;
301

302
	if (!pathspec_list->nr)
303
		return;
304

305
	fprintf(stderr, _("The following paths have been moved outside the\n"
306
			  "sparse-checkout definition but are not sparse due to local\n"
307
			  "modifications.\n"));
308
	for_each_string_list_item(item, pathspec_list)
309
		fprintf(stderr, "%s\n", item->string);
310

311
	advise_if_enabled(ADVICE_UPDATE_SPARSE_PATH,
312
			  _("To correct the sparsity of these paths, do the following:\n"
313
			    "* Use \"git add --sparse <paths>\" to update the index\n"
314
			    "* Use \"git sparse-checkout reapply\" to apply the sparsity rules"));
315
}
316

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.