summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorÆvar Arnfjörð Bjarmason <avarab@gmail.com>2018-11-13 19:52:43 +0000
committerJunio C Hamano <gitster@pobox.com>2018-11-14 15:27:55 +0900
commitdd8dd300c636bf0a1352379aed88d9434a6ac7bb (patch)
tree05b0fca0fe53403983332dcfb688a2a19f4766a3
parent04d17287a0e0161e5a0accd8ab781135bd672c98 (diff)
downloadgit-dd8dd300c636bf0a1352379aed88d9434a6ac7bb.tar.gz
git-dd8dd300c636bf0a1352379aed88d9434a6ac7bb.tar.xz
push: add an advice on unqualified <dst> push
Add an advice to the recently improved error message added in f8aae12034 ("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 'git@github.com: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 <87r2gxebsi.fsf@evledraar.gmail.com> about that. Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r--Documentation/config/advice.txt7
-rw-r--r--advice.c2
-rw-r--r--advice.h1
-rw-r--r--remote.c37
-rwxr-xr-xt/t5505-remote.sh28
5 files changed, 75 insertions, 0 deletions
diff --git a/Documentation/config/advice.txt b/Documentation/config/advice.txt
index 57fcd4c86..88620429e 100644
--- a/Documentation/config/advice.txt
+++ b/Documentation/config/advice.txt
@@ -30,6 +30,13 @@ advice.*::
tries to overwrite a remote ref that points at an
object that is not a commit-ish, or make the remote
ref point at an object that is not a commit-ish.
+ pushUnqualifiedRefname::
+ Shown when linkgit:git-push[1] gives up trying to
+ guess based on the source and destination refs what
+ remote ref namespace the source belongs in, but where
+ we can still suggest that the user push to either
+ refs/heads/* or refs/tags/* based on the type of the
+ source object.
statusHints::
Show directions on how to proceed from the current
state in the output of linkgit:git-status[1], in
diff --git a/advice.c b/advice.c
index 5f3565640..567209aa7 100644
--- a/advice.c
+++ b/advice.c
@@ -9,6 +9,7 @@ int advice_push_non_ff_matching = 1;
int advice_push_already_exists = 1;
int advice_push_fetch_first = 1;
int advice_push_needs_force = 1;
+int advice_push_unqualified_ref_name = 1;
int advice_status_hints = 1;
int advice_status_u_option = 1;
int advice_commit_before_merge = 1;
@@ -63,6 +64,7 @@ static struct {
{ "pushAlreadyExists", &advice_push_already_exists },
{ "pushFetchFirst", &advice_push_fetch_first },
{ "pushNeedsForce", &advice_push_needs_force },
+ { "pushUnqualifiedRefName", &advice_push_unqualified_ref_name },
{ "statusHints", &advice_status_hints },
{ "statusUoption", &advice_status_u_option },
{ "commitBeforeMerge", &advice_commit_before_merge },
diff --git a/advice.h b/advice.h
index 696bf0e7d..f875f8cd8 100644
--- a/advice.h
+++ b/advice.h
@@ -9,6 +9,7 @@ extern int advice_push_non_ff_matching;
extern int advice_push_already_exists;
extern int advice_push_fetch_first;
extern int advice_push_needs_force;
+extern int advice_push_unqualified_ref_name;
extern int advice_status_hints;
extern int advice_status_u_option;
extern int advice_commit_before_merge;
diff --git a/remote.c b/remote.c
index ba8abf4d3..f7477b8eb 100644
--- a/remote.c
+++ b/remote.c
@@ -13,6 +13,7 @@
#include "mergesort.h"
#include "argv-array.h"
#include "commit-reach.h"
+#include "advice.h"
enum map_direction { FROM_SRC, FROM_DST };
@@ -1008,6 +1009,9 @@ static int match_explicit_lhs(struct ref *src,
static void show_push_unqualified_ref_name_error(const char *dst_value,
const char *matched_src_name)
{
+ struct object_id oid;
+ enum object_type type;
+
/*
* TRANSLATORS: "matches '%s'%" is the <dst> part of "git push
* <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,
"\n"
"Neither worked, so we gave up. You must fully qualify the ref."),
dst_value, matched_src_name);
+
+ if (!advice_push_unqualified_ref_name)
+ return;
+
+ if (get_oid(matched_src_name, &oid))
+ BUG("'%s' is not a valid object, "
+ "match_explicit_lhs() should catch this!",
+ matched_src_name);
+ type = oid_object_info(the_repository, &oid, NULL);
+ if (type == OBJ_COMMIT) {
+ advise(_("The <src> part of the refspec is a commit object.\n"
+ "Did you mean to create a new branch by pushing to\n"
+ "'%s:refs/heads/%s'?"),
+ matched_src_name, dst_value);
+ } else if (type == OBJ_TAG) {
+ advise(_("The <src> part of the refspec is a tag object.\n"
+ "Did you mean to create a new tag by pushing to\n"
+ "'%s:refs/tags/%s'?"),
+ matched_src_name, dst_value);
+ } else if (type == OBJ_TREE) {
+ advise(_("The <src> part of the refspec is a tree object.\n"
+ "Did you mean to tag a new tree by pushing to\n"
+ "'%s:refs/tags/%s'?"),
+ matched_src_name, dst_value);
+ } else if (type == OBJ_BLOB) {
+ advise(_("The <src> part of the refspec is a blob object.\n"
+ "Did you mean to tag a new blob by pushing to\n"
+ "'%s:refs/tags/%s'?"),
+ matched_src_name, dst_value);
+ } else {
+ BUG("'%s' should be commit/tag/tree/blob, is '%d'",
+ matched_src_name, type);
+ }
}
static int match_explicit(struct ref *src, struct ref *dst,
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index d2a2cdd45..f069cbcc2 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -1222,4 +1222,32 @@ test_expect_success 'add remote matching the "insteadOf" URL' '
git remote add backup xyz@example.com
'
+test_expect_success 'unqualified <dst> refspec DWIM and advice' '
+ test_when_finished "(cd test && git tag -d some-tag)" &&
+ (
+ cd test &&
+ git tag -a -m "Some tag" some-tag master &&
+ exit_with=true &&
+ for type in commit tag tree blob
+ do
+ if test "$type" = "blob"
+ then
+ oid=$(git rev-parse some-tag:file)
+ else
+ oid=$(git rev-parse some-tag^{$type})
+ fi &&
+ test_must_fail git push origin $oid:dst 2>err &&
+ test_i18ngrep "error: The destination you" err &&
+ test_i18ngrep "hint: Did you mean" err &&
+ test_must_fail git -c advice.pushUnqualifiedRefName=false \
+ push origin $oid:dst 2>err &&
+ test_i18ngrep "error: The destination you" err &&
+ test_i18ngrep ! "hint: Did you mean" err ||
+ exit_with=false
+ done &&
+ $exit_with
+ )
+'
+
+
test_done