Skip to content

Commit dd8dd30

Browse files
avargitster
authored andcommitted
push: add an advice on unqualified <dst> push
Add an advice to the recently improved error message added in f8aae12 ("push: allow unqualified dest refspecs to DWIM", 2008-04-23). Now with advice.pushUnqualifiedRefName=true (on by default) we show a hint about how to proceed: $ ./git-push avar v2.19.0^{commit}:newbranch -n error: The destination you provided is not a full refname (i.e., starting with "refs/"). We tried to guess what you meant by: - Looking for a ref that matches 'newbranch' on the remote side. - Checking if the <src> being pushed ('v2.19.0^{commit}') is a ref in "refs/{heads,tags}/". If so we add a corresponding refs/{heads,tags}/ prefix on the remote side. Neither worked, so we gave up. You must fully qualify the ref. hint: The <src> part of the refspec is a commit object. hint: Did you mean to create a new branch by pushing to hint: 'v2.19.0^{commit}:refs/heads/newbranch'? error: failed to push some refs to '[email protected]:avar/git.git' When trying to push a tag, tree or a blob we suggest that perhaps the user meant to push them to refs/tags/ instead. The if/else duplication for all of OBJ_{COMMIT,TAG,TREE,BLOB} is unfortunate, but is required to correctly mark the messages for translation. See the discussion in <[email protected]> about that. Signed-off-by: Ævar Arnfjörð Bjarmason <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 04d1728 commit dd8dd30

File tree

5 files changed

+75
-0
lines changed

5 files changed

+75
-0
lines changed

Documentation/config/advice.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ advice.*::
3030
tries to overwrite a remote ref that points at an
3131
object that is not a commit-ish, or make the remote
3232
ref point at an object that is not a commit-ish.
33+
pushUnqualifiedRefname::
34+
Shown when linkgit:git-push[1] gives up trying to
35+
guess based on the source and destination refs what
36+
remote ref namespace the source belongs in, but where
37+
we can still suggest that the user push to either
38+
refs/heads/* or refs/tags/* based on the type of the
39+
source object.
3340
statusHints::
3441
Show directions on how to proceed from the current
3542
state in the output of linkgit:git-status[1], in

advice.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ int advice_push_non_ff_matching = 1;
99
int advice_push_already_exists = 1;
1010
int advice_push_fetch_first = 1;
1111
int advice_push_needs_force = 1;
12+
int advice_push_unqualified_ref_name = 1;
1213
int advice_status_hints = 1;
1314
int advice_status_u_option = 1;
1415
int advice_commit_before_merge = 1;
@@ -63,6 +64,7 @@ static struct {
6364
{ "pushAlreadyExists", &advice_push_already_exists },
6465
{ "pushFetchFirst", &advice_push_fetch_first },
6566
{ "pushNeedsForce", &advice_push_needs_force },
67+
{ "pushUnqualifiedRefName", &advice_push_unqualified_ref_name },
6668
{ "statusHints", &advice_status_hints },
6769
{ "statusUoption", &advice_status_u_option },
6870
{ "commitBeforeMerge", &advice_commit_before_merge },

advice.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ extern int advice_push_non_ff_matching;
99
extern int advice_push_already_exists;
1010
extern int advice_push_fetch_first;
1111
extern int advice_push_needs_force;
12+
extern int advice_push_unqualified_ref_name;
1213
extern int advice_status_hints;
1314
extern int advice_status_u_option;
1415
extern int advice_commit_before_merge;

remote.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "mergesort.h"
1414
#include "argv-array.h"
1515
#include "commit-reach.h"
16+
#include "advice.h"
1617

1718
enum map_direction { FROM_SRC, FROM_DST };
1819

@@ -1008,6 +1009,9 @@ static int match_explicit_lhs(struct ref *src,
10081009
static void show_push_unqualified_ref_name_error(const char *dst_value,
10091010
const char *matched_src_name)
10101011
{
1012+
struct object_id oid;
1013+
enum object_type type;
1014+
10111015
/*
10121016
* TRANSLATORS: "matches '%s'%" is the <dst> part of "git push
10131017
* <remote> <src>:<dst>" push, and "being pushed ('%s')" is
@@ -1023,6 +1027,39 @@ static void show_push_unqualified_ref_name_error(const char *dst_value,
10231027
"\n"
10241028
"Neither worked, so we gave up. You must fully qualify the ref."),
10251029
dst_value, matched_src_name);
1030+
1031+
if (!advice_push_unqualified_ref_name)
1032+
return;
1033+
1034+
if (get_oid(matched_src_name, &oid))
1035+
BUG("'%s' is not a valid object, "
1036+
"match_explicit_lhs() should catch this!",
1037+
matched_src_name);
1038+
type = oid_object_info(the_repository, &oid, NULL);
1039+
if (type == OBJ_COMMIT) {
1040+
advise(_("The <src> part of the refspec is a commit object.\n"
1041+
"Did you mean to create a new branch by pushing to\n"
1042+
"'%s:refs/heads/%s'?"),
1043+
matched_src_name, dst_value);
1044+
} else if (type == OBJ_TAG) {
1045+
advise(_("The <src> part of the refspec is a tag object.\n"
1046+
"Did you mean to create a new tag by pushing to\n"
1047+
"'%s:refs/tags/%s'?"),
1048+
matched_src_name, dst_value);
1049+
} else if (type == OBJ_TREE) {
1050+
advise(_("The <src> part of the refspec is a tree object.\n"
1051+
"Did you mean to tag a new tree by pushing to\n"
1052+
"'%s:refs/tags/%s'?"),
1053+
matched_src_name, dst_value);
1054+
} else if (type == OBJ_BLOB) {
1055+
advise(_("The <src> part of the refspec is a blob object.\n"
1056+
"Did you mean to tag a new blob by pushing to\n"
1057+
"'%s:refs/tags/%s'?"),
1058+
matched_src_name, dst_value);
1059+
} else {
1060+
BUG("'%s' should be commit/tag/tree/blob, is '%d'",
1061+
matched_src_name, type);
1062+
}
10261063
}
10271064

10281065
static int match_explicit(struct ref *src, struct ref *dst,

t/t5505-remote.sh

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1222,4 +1222,32 @@ test_expect_success 'add remote matching the "insteadOf" URL' '
12221222
git remote add backup [email protected]
12231223
'
12241224

1225+
test_expect_success 'unqualified <dst> refspec DWIM and advice' '
1226+
test_when_finished "(cd test && git tag -d some-tag)" &&
1227+
(
1228+
cd test &&
1229+
git tag -a -m "Some tag" some-tag master &&
1230+
exit_with=true &&
1231+
for type in commit tag tree blob
1232+
do
1233+
if test "$type" = "blob"
1234+
then
1235+
oid=$(git rev-parse some-tag:file)
1236+
else
1237+
oid=$(git rev-parse some-tag^{$type})
1238+
fi &&
1239+
test_must_fail git push origin $oid:dst 2>err &&
1240+
test_i18ngrep "error: The destination you" err &&
1241+
test_i18ngrep "hint: Did you mean" err &&
1242+
test_must_fail git -c advice.pushUnqualifiedRefName=false \
1243+
push origin $oid:dst 2>err &&
1244+
test_i18ngrep "error: The destination you" err &&
1245+
test_i18ngrep ! "hint: Did you mean" err ||
1246+
exit_with=false
1247+
done &&
1248+
$exit_with
1249+
)
1250+
'
1251+
1252+
12251253
test_done

0 commit comments

Comments
 (0)