Merge branch 'ab/case-insensitive-upstream-and-push-marker'

On many keyboards, typing "@{" involves holding down SHIFT key and
one can easily end up with "@{Up..." when typing "@{upstream}".  As
the upstream/push keywords do not appear anywhere else in the syntax,
we can safely accept them case insensitively without introducing
ambiguity or confusion  to solve this.

* ab/case-insensitive-upstream-and-push-marker:
  rev-parse: match @{upstream}, @{u} and @{push} case-insensitively
This commit is contained in:
Junio C Hamano 2017-03-30 14:07:16 -07:00
commit 42e1cc517b
4 changed files with 23 additions and 8 deletions

View file

@ -96,7 +96,8 @@ some output processing may assume ref names in UTF-8.
refers to the branch that the branch specified by branchname is set to build on refers to the branch that the branch specified by branchname is set to build on
top of (configured with `branch.<name>.remote` and top of (configured with `branch.<name>.remote` and
`branch.<name>.merge`). A missing branchname defaults to the `branch.<name>.merge`). A missing branchname defaults to the
current one. current one. These suffixes are also accepted when spelled in uppercase, and
they mean the same thing no matter the case.
'<branchname>@\{push\}', e.g. 'master@\{push\}', '@\{push\}':: '<branchname>@\{push\}', e.g. 'master@\{push\}', '@\{push\}'::
The suffix '@\{push}' reports the branch "where we would push to" if The suffix '@\{push}' reports the branch "where we would push to" if
@ -122,6 +123,9 @@ refs/remotes/myfork/mybranch
Note in the example that we set up a triangular workflow, where we pull Note in the example that we set up a triangular workflow, where we pull
from one location and push to another. In a non-triangular workflow, from one location and push to another. In a non-triangular workflow,
'@\{push}' is the same as '@\{upstream}', and there is no need for it. '@\{push}' is the same as '@\{upstream}', and there is no need for it.
+
This suffix is also accepted when spelled in uppercase, and means the same
thing no matter the case.
'<rev>{caret}', e.g. 'HEAD{caret}, v1.5.1{caret}0':: '<rev>{caret}', e.g. 'HEAD{caret}, v1.5.1{caret}0'::
A suffix '{caret}' to a revision parameter means the first parent of A suffix '{caret}' to a revision parameter means the first parent of

View file

@ -549,7 +549,7 @@ static inline int at_mark(const char *string, int len,
for (i = 0; i < nr; i++) { for (i = 0; i < nr; i++) {
int suffix_len = strlen(suffix[i]); int suffix_len = strlen(suffix[i]);
if (suffix_len <= len if (suffix_len <= len
&& !memcmp(string, suffix[i], suffix_len)) && !strncasecmp(string, suffix[i], suffix_len))
return suffix_len; return suffix_len;
} }
return 0; return 0;

View file

@ -46,11 +46,14 @@ error_message () {
} }
test_expect_success '@{upstream} resolves to correct full name' ' test_expect_success '@{upstream} resolves to correct full name' '
test refs/remotes/origin/master = "$(full_name @{upstream})" test refs/remotes/origin/master = "$(full_name @{upstream})" &&
test refs/remotes/origin/master = "$(full_name @{UPSTREAM})" &&
test refs/remotes/origin/master = "$(full_name @{UpSTReam})"
' '
test_expect_success '@{u} resolves to correct full name' ' test_expect_success '@{u} resolves to correct full name' '
test refs/remotes/origin/master = "$(full_name @{u})" test refs/remotes/origin/master = "$(full_name @{u})" &&
test refs/remotes/origin/master = "$(full_name @{U})"
' '
test_expect_success 'my-side@{upstream} resolves to correct full name' ' test_expect_success 'my-side@{upstream} resolves to correct full name' '
@ -60,6 +63,8 @@ test_expect_success 'my-side@{upstream} resolves to correct full name' '
test_expect_success 'upstream of branch with @ in middle' ' test_expect_success 'upstream of branch with @ in middle' '
full_name fun@ny@{u} >actual && full_name fun@ny@{u} >actual &&
echo refs/remotes/origin/side >expect && echo refs/remotes/origin/side >expect &&
test_cmp expect actual &&
full_name fun@ny@{U} >actual &&
test_cmp expect actual test_cmp expect actual
' '
@ -96,12 +101,14 @@ test_expect_success 'not-tracking@{u} fails' '
test_expect_success '<branch>@{u}@{1} resolves correctly' ' test_expect_success '<branch>@{u}@{1} resolves correctly' '
test_commit 6 && test_commit 6 &&
(cd clone && git fetch) && (cd clone && git fetch) &&
test 5 = $(commit_subject my-side@{u}@{1}) test 5 = $(commit_subject my-side@{u}@{1}) &&
test 5 = $(commit_subject my-side@{U}@{1})
' '
test_expect_success '@{u} without specifying branch fails on a detached HEAD' ' test_expect_success '@{u} without specifying branch fails on a detached HEAD' '
git checkout HEAD^0 && git checkout HEAD^0 &&
test_must_fail git rev-parse @{u} test_must_fail git rev-parse @{u} &&
test_must_fail git rev-parse @{U}
' '
test_expect_success 'checkout -b new my-side@{u} forks from the same' ' test_expect_success 'checkout -b new my-side@{u} forks from the same' '

View file

@ -24,12 +24,16 @@ test_expect_success 'setup' '
test_expect_success '@{push} with default=nothing' ' test_expect_success '@{push} with default=nothing' '
test_config push.default nothing && test_config push.default nothing &&
test_must_fail git rev-parse master@{push} test_must_fail git rev-parse master@{push} &&
test_must_fail git rev-parse master@{PUSH} &&
test_must_fail git rev-parse master@{PuSH}
' '
test_expect_success '@{push} with default=simple' ' test_expect_success '@{push} with default=simple' '
test_config push.default simple && test_config push.default simple &&
resolve master@{push} refs/remotes/origin/master resolve master@{push} refs/remotes/origin/master &&
resolve master@{PUSH} refs/remotes/origin/master &&
resolve master@{pUSh} refs/remotes/origin/master
' '
test_expect_success 'triangular @{push} fails with default=simple' ' test_expect_success 'triangular @{push} fails with default=simple' '