Skip to content

Commit e4921d8

Browse files
TaoKgitster
authored andcommitted
tracking branches: add advice to ambiguous refspec error
The error "not tracking: ambiguous information for ref" is raised when we are evaluating what tracking information to set on a branch, and find that the ref to be added as tracking branch is mapped under multiple remotes' fetch refspecs. This can easily happen when a user copy-pastes a remote definition in their git config, and forgets to change the tracking path. Add advice in this situation, explicitly highlighting which remotes are involved and suggesting how to correct the situation. Also update a test to explicitly expect that advice. Signed-off-by: Tao Klerks <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent abf474a commit e4921d8

File tree

5 files changed

+78
-9
lines changed

5 files changed

+78
-9
lines changed

Documentation/config/advice.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ advice.*::
44
can tell Git that you do not need help by setting these to 'false':
55
+
66
--
7+
ambiguousFetchRefspec::
8+
Advice shown when fetch refspec for multiple remotes map to
9+
the same remote-tracking branch namespace and causes branch
10+
tracking set-up to fail.
711
fetchShowForcedUpdates::
812
Advice shown when linkgit:git-fetch[1] takes a long time
913
to calculate forced updates after ref updates, or to warn

advice.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ static struct {
3939
[ADVICE_ADD_EMPTY_PATHSPEC] = { "addEmptyPathspec", 1 },
4040
[ADVICE_ADD_IGNORED_FILE] = { "addIgnoredFile", 1 },
4141
[ADVICE_AM_WORK_DIR] = { "amWorkDir", 1 },
42+
[ADVICE_AMBIGUOUS_FETCH_REFSPEC] = { "ambiguousFetchRefspec", 1 },
4243
[ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME] = { "checkoutAmbiguousRemoteBranchName", 1 },
4344
[ADVICE_COMMIT_BEFORE_MERGE] = { "commitBeforeMerge", 1 },
4445
[ADVICE_DETACHED_HEAD] = { "detachedHead", 1 },

advice.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ struct string_list;
1717
ADVICE_ADD_EMPTY_PATHSPEC,
1818
ADVICE_ADD_IGNORED_FILE,
1919
ADVICE_AM_WORK_DIR,
20+
ADVICE_AMBIGUOUS_FETCH_REFSPEC,
2021
ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME,
2122
ADVICE_COMMIT_BEFORE_MERGE,
2223
ADVICE_DETACHED_HEAD,

branch.c

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,31 @@ struct tracking {
1818
int matches;
1919
};
2020

21+
struct find_tracked_branch_cb {
22+
struct tracking *tracking;
23+
struct string_list ambiguous_remotes;
24+
};
25+
2126
static int find_tracked_branch(struct remote *remote, void *priv)
2227
{
23-
struct tracking *tracking = priv;
28+
struct find_tracked_branch_cb *ftb = priv;
29+
struct tracking *tracking = ftb->tracking;
2430

2531
if (!remote_find_tracking(remote, &tracking->spec)) {
26-
if (++tracking->matches == 1) {
32+
switch (++tracking->matches) {
33+
case 1:
2734
string_list_append(tracking->srcs, tracking->spec.src);
2835
tracking->remote = remote->name;
29-
} else {
36+
break;
37+
case 2:
38+
/* there are at least two remotes; backfill the first one */
39+
string_list_append(&ftb->ambiguous_remotes, tracking->remote);
40+
/* fall through */
41+
default:
42+
string_list_append(&ftb->ambiguous_remotes, remote->name);
3043
free(tracking->spec.src);
3144
string_list_clear(tracking->srcs, 0);
45+
break;
3246
}
3347
tracking->spec.src = NULL;
3448
}
@@ -232,12 +246,16 @@ static void setup_tracking(const char *new_ref, const char *orig_ref,
232246
struct tracking tracking;
233247
struct string_list tracking_srcs = STRING_LIST_INIT_DUP;
234248
int config_flags = quiet ? 0 : BRANCH_CONFIG_VERBOSE;
249+
struct find_tracked_branch_cb ftb_cb = {
250+
.tracking = &tracking,
251+
.ambiguous_remotes = STRING_LIST_INIT_DUP,
252+
};
235253

236254
memset(&tracking, 0, sizeof(tracking));
237255
tracking.spec.dst = (char *)orig_ref;
238256
tracking.srcs = &tracking_srcs;
239257
if (track != BRANCH_TRACK_INHERIT)
240-
for_each_remote(find_tracked_branch, &tracking);
258+
for_each_remote(find_tracked_branch, &ftb_cb);
241259
else if (inherit_tracking(&tracking, orig_ref))
242260
goto cleanup;
243261

@@ -252,9 +270,39 @@ static void setup_tracking(const char *new_ref, const char *orig_ref,
252270
goto cleanup;
253271
}
254272

255-
if (tracking.matches > 1)
256-
die(_("not tracking: ambiguous information for ref %s"),
257-
orig_ref);
273+
if (tracking.matches > 1) {
274+
int status = die_message(_("not tracking: ambiguous information for ref '%s'"),
275+
orig_ref);
276+
if (advice_enabled(ADVICE_AMBIGUOUS_FETCH_REFSPEC)) {
277+
struct strbuf remotes_advice = STRBUF_INIT;
278+
struct string_list_item *item;
279+
280+
for_each_string_list_item(item, &ftb_cb.ambiguous_remotes)
281+
/*
282+
* TRANSLATORS: This is a line listing a remote with duplicate
283+
* refspecs in the advice message below. For RTL languages you'll
284+
* probably want to swap the "%s" and leading " " space around.
285+
*/
286+
strbuf_addf(&remotes_advice, _(" %s\n"), item->string);
287+
288+
/*
289+
* TRANSLATORS: The second argument is a \n-delimited list of
290+
* duplicate refspecs, composed above.
291+
*/
292+
advise(_("There are multiple remotes whose fetch refspecs map to the remote\n"
293+
"tracking ref '%s':\n"
294+
"%s"
295+
"\n"
296+
"This is typically a configuration error.\n"
297+
"\n"
298+
"To support setting up tracking branches, ensure that\n"
299+
"different remotes' fetch refspecs map into different\n"
300+
"tracking namespaces."), orig_ref,
301+
remotes_advice.buf);
302+
strbuf_release(&remotes_advice);
303+
}
304+
exit(status);
305+
}
258306

259307
if (tracking.srcs->nr < 1)
260308
string_list_append(tracking.srcs, orig_ref);
@@ -264,6 +312,7 @@ static void setup_tracking(const char *new_ref, const char *orig_ref,
264312

265313
cleanup:
266314
string_list_clear(&tracking_srcs, 0);
315+
string_list_clear(&ftb_cb.ambiguous_remotes, 0);
267316
}
268317

269318
int read_branch_desc(struct strbuf *buf, const char *branch_name)

t/t3200-branch.sh

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,13 +1039,27 @@ test_expect_success 'checkout -b with -l makes reflog when core.logAllRefUpdates
10391039
git rev-parse --verify gamma@{0}
10401040
'
10411041

1042-
test_expect_success 'avoid ambiguous track' '
1042+
test_expect_success 'avoid ambiguous track and advise' '
10431043
git config branch.autosetupmerge true &&
10441044
git config remote.ambi1.url lalala &&
10451045
git config remote.ambi1.fetch refs/heads/lalala:refs/heads/main &&
10461046
git config remote.ambi2.url lilili &&
10471047
git config remote.ambi2.fetch refs/heads/lilili:refs/heads/main &&
1048-
test_must_fail git branch all1 main &&
1048+
cat <<-EOF >expected &&
1049+
fatal: not tracking: ambiguous information for ref '\''refs/heads/main'\''
1050+
hint: There are multiple remotes whose fetch refspecs map to the remote
1051+
hint: tracking ref '\''refs/heads/main'\'':
1052+
hint: ambi1
1053+
hint: ambi2
1054+
hint: ''
1055+
hint: This is typically a configuration error.
1056+
hint: ''
1057+
hint: To support setting up tracking branches, ensure that
1058+
hint: different remotes'\'' fetch refspecs map into different
1059+
hint: tracking namespaces.
1060+
EOF
1061+
test_must_fail git branch all1 main 2>actual &&
1062+
test_cmp expected actual &&
10491063
test -z "$(git config branch.all1.merge)"
10501064
'
10511065

0 commit comments

Comments
 (0)