From: "brian m. carlson" <sandals@crustytoothpaste.net>
To: git@vger.kernel.org
Cc: Junio C Hamano <gitster@pobox.com>,
Brandon Williams <bmwill@google.com>, Jeff King <peff@peff.net>
Subject: [PATCH] refspec: allow @ on the left-hand side of refspecs
Date: Sun, 29 Jul 2018 19:28:03 +0000 [thread overview]
Message-ID: <20180729192803.1047050-1-sandals@crustytoothpaste.net> (raw)
The object ID parsing machinery is aware of "@" as a synonym for "HEAD"
and this is documented accordingly in gitrevisions(7). The push
documentation describes the source portion of a refspec as "any
arbitrary 'SHA-1 expression'"; however, "@" is not allowed on the
left-hand side of a refspec, since we attempt to check for it being a
valid ref name and fail (since it is not).
Teach the refspec machinery about this alias and silently substitute
"HEAD" when we see "@". This handles the fact that HEAD is a symref and
preserves its special behavior. We need not handle other arbitrary
object ID expressions (such as "@^") when pushing because the revision
machinery already handles that for us.
Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
---
I probably type "git push upstream HEAD" from five to thirty times a
day, many of those where I typo "HEAD", so I decided to implement the
shorter form. This design handles @ as HEAD in both fetch and push,
whereas alternate solutions would not.
check_refname_format explicitly rejects "@"; I tried at first to simply
ignore that with a flag, but we end up calling that from several other
places in the codebase and rejecting it and all of those places would
have needed updating.
I thought about putting the if/else logic in a function, but since it's
just four lines, I decided not to. However, if people think it would be
tidier, I can do so.
Note that the test portion of the patch is best read with git diff -w;
the current version is very noisy.
refspec.c | 6 ++-
t/t5516-fetch-push.sh | 104 +++++++++++++++++++++---------------------
2 files changed, 58 insertions(+), 52 deletions(-)
diff --git a/refspec.c b/refspec.c
index e8010dce0c..57c2f65104 100644
--- a/refspec.c
+++ b/refspec.c
@@ -62,8 +62,12 @@ static int parse_refspec(struct refspec_item *item, const char *refspec, int fet
return 0;
}
+ if (llen == 1 && lhs[0] == '@')
+ item->src = xstrdup("HEAD");
+ else
+ item->src = xstrndup(lhs, llen);
+
item->pattern = is_glob;
- item->src = xstrndup(lhs, llen);
flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0);
if (fetch) {
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index a5077d8b7c..cbccbd2f8d 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -436,70 +436,72 @@ test_expect_success 'push ref expression with non-existent, incomplete dest' '
'
-test_expect_success 'push with HEAD' '
+for ref in HEAD @
+do
+ test_expect_success "push with $ref" '
- mk_test testrepo heads/master &&
- git checkout master &&
- git push testrepo HEAD &&
- check_push_result testrepo $the_commit heads/master
+ mk_test testrepo heads/master &&
+ git checkout master &&
+ git push testrepo $ref &&
+ check_push_result testrepo $the_commit heads/master
-'
+ '
-test_expect_success 'push with HEAD nonexisting at remote' '
+ test_expect_success "push with $ref nonexisting at remote" '
- mk_test testrepo heads/master &&
- git checkout -b local master &&
- git push testrepo HEAD &&
- check_push_result testrepo $the_commit heads/local
-'
+ mk_test testrepo heads/master &&
+ git checkout -B local master &&
+ git push testrepo $ref &&
+ check_push_result testrepo $the_commit heads/local
+ '
-test_expect_success 'push with +HEAD' '
+ test_expect_success "push with +$ref" '
- mk_test testrepo heads/master &&
- git checkout master &&
- git branch -D local &&
- git checkout -b local &&
- git push testrepo master local &&
- check_push_result testrepo $the_commit heads/master &&
- check_push_result testrepo $the_commit heads/local &&
+ mk_test testrepo heads/master &&
+ git checkout master &&
+ git branch -D local &&
+ git checkout -b local &&
+ git push testrepo master local &&
+ check_push_result testrepo $the_commit heads/master &&
+ check_push_result testrepo $the_commit heads/local &&
- # Without force rewinding should fail
- git reset --hard HEAD^ &&
- test_must_fail git push testrepo HEAD &&
- check_push_result testrepo $the_commit heads/local &&
+ # Without force rewinding should fail
+ git reset --hard HEAD^ &&
+ test_must_fail git push testrepo $ref &&
+ check_push_result testrepo $the_commit heads/local &&
- # With force rewinding should succeed
- git push testrepo +HEAD &&
- check_push_result testrepo $the_first_commit heads/local
+ # With force rewinding should succeed
+ git push testrepo +$ref &&
+ check_push_result testrepo $the_first_commit heads/local
-'
+ '
-test_expect_success 'push HEAD with non-existent, incomplete dest' '
+ test_expect_success "push $ref with non-existent, incomplete dest" '
- mk_test testrepo &&
- git checkout master &&
- git push testrepo HEAD:branch &&
- check_push_result testrepo $the_commit heads/branch
+ mk_test testrepo &&
+ git checkout master &&
+ git push testrepo $ref:branch &&
+ check_push_result testrepo $the_commit heads/branch
-'
+ '
-test_expect_success 'push with config remote.*.push = HEAD' '
-
- mk_test testrepo heads/local &&
- git checkout master &&
- git branch -f local $the_commit &&
- (
- cd testrepo &&
- git checkout local &&
- git reset --hard $the_first_commit
- ) &&
- test_config remote.there.url testrepo &&
- test_config remote.there.push HEAD &&
- test_config branch.master.remote there &&
- git push &&
- check_push_result testrepo $the_commit heads/master &&
- check_push_result testrepo $the_first_commit heads/local
-'
+ test_expect_success "push with config remote.*.push = $ref" '
+ mk_test testrepo heads/local &&
+ git checkout master &&
+ git branch -f local $the_commit &&
+ (
+ cd testrepo &&
+ git checkout local &&
+ git reset --hard $the_first_commit
+ ) &&
+ test_config remote.there.url testrepo &&
+ test_config remote.there.push $ref &&
+ test_config branch.master.remote there &&
+ git push &&
+ check_push_result testrepo $the_commit heads/master &&
+ check_push_result testrepo $the_first_commit heads/local
+ '
+done
test_expect_success 'push with remote.pushdefault' '
mk_test up_repo heads/master &&
next reply other threads:[~2018-07-29 19:28 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-07-29 19:28 brian m. carlson [this message]
2018-07-30 17:50 ` [PATCH] refspec: allow @ on the left-hand side of refspecs Brandon Williams
2018-07-30 23:14 ` brian m. carlson
2018-07-31 16:02 ` Brandon Williams
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: http://vger.kernel.org/majordomo-info.html
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180729192803.1047050-1-sandals@crustytoothpaste.net \
--to=sandals@crustytoothpaste.net \
--cc=bmwill@google.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=peff@peff.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://80x24.org/mirrors/git.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).