зеркало из https://github.com/microsoft/git.git
Introduce <branch>@{upstream} notation
A new notation '<branch>@{upstream}' refers to the branch <branch> is set to build on top of. Missing <branch> (i.e. '@{upstream}') defaults to the current branch. This allows you to run, for example, for l in list of local branches do git log --oneline --left-right $l...$l@{upstream} done to inspect each of the local branches you are interested in for the divergence from its upstream. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Родитель
902f235378
Коммит
28fb84382b
|
@ -231,6 +231,10 @@ when you run 'git-merge'.
|
|||
* The special construct '@\{-<n>\}' means the <n>th branch checked out
|
||||
before the current one.
|
||||
|
||||
* The suffix '@{upstream}' to a ref (short form 'ref@{u}') refers to
|
||||
the branch the ref is set to build on top of. Missing ref defaults
|
||||
to the current branch.
|
||||
|
||||
* A suffix '{caret}' to a revision parameter means the first parent of
|
||||
that commit object. '{caret}<n>' means the <n>th parent (i.e.
|
||||
'rev{caret}'
|
||||
|
|
35
sha1_name.c
35
sha1_name.c
|
@ -5,6 +5,7 @@
|
|||
#include "blob.h"
|
||||
#include "tree-walk.h"
|
||||
#include "refs.h"
|
||||
#include "remote.h"
|
||||
|
||||
static int find_short_object_filename(int len, const char *name, unsigned char *sha1)
|
||||
{
|
||||
|
@ -238,9 +239,24 @@ static int ambiguous_path(const char *path, int len)
|
|||
return slash;
|
||||
}
|
||||
|
||||
static inline int tracked_suffix(const char *string, int len)
|
||||
{
|
||||
const char *suffix[] = { "@{upstream}", "@{u}" };
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(suffix); i++) {
|
||||
int suffix_len = strlen(suffix[i]);
|
||||
if (len >= suffix_len && !memcmp(string + len - suffix_len,
|
||||
suffix[i], suffix_len))
|
||||
return suffix_len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* *string and *len will only be substituted, and *string returned (for
|
||||
* later free()ing) if the string passed in is of the form @{-<n>}.
|
||||
* later free()ing) if the string passed in is of the form @{-<n>} or
|
||||
* of the form <branch>@{upstream}.
|
||||
*/
|
||||
static char *substitute_branch_name(const char **string, int *len)
|
||||
{
|
||||
|
@ -254,6 +270,21 @@ static char *substitute_branch_name(const char **string, int *len)
|
|||
return (char *)*string;
|
||||
}
|
||||
|
||||
ret = tracked_suffix(*string, *len);
|
||||
if (ret) {
|
||||
char *ref = xstrndup(*string, *len - ret);
|
||||
struct branch *tracking = branch_get(*ref ? ref : NULL);
|
||||
|
||||
if (!tracking)
|
||||
die ("No tracking branch found for '%s'", ref);
|
||||
free(ref);
|
||||
if (tracking->merge && tracking->merge[0]->dst) {
|
||||
*string = xstrdup(tracking->merge[0]->dst);
|
||||
*len = strlen(*string);
|
||||
return (char *)*string;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -340,8 +371,10 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
|
|||
if (len && str[len-1] == '}') {
|
||||
for (at = len-2; at >= 0; at--) {
|
||||
if (str[at] == '@' && str[at+1] == '{') {
|
||||
if (!tracked_suffix(str + at, len - at)) {
|
||||
reflog_len = (len-1) - (at+2);
|
||||
len = at;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
#!/bin/sh
|
||||
|
||||
test_description='test <branch>@{upstream} syntax'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
|
||||
test_expect_success 'setup' '
|
||||
|
||||
test_commit 1 &&
|
||||
git checkout -b side &&
|
||||
test_commit 2 &&
|
||||
git checkout master &&
|
||||
git clone . clone &&
|
||||
test_commit 3 &&
|
||||
(cd clone &&
|
||||
test_commit 4 &&
|
||||
git branch --track my-side origin/side)
|
||||
|
||||
'
|
||||
|
||||
full_name () {
|
||||
(cd clone &&
|
||||
git rev-parse --symbolic-full-name "$@")
|
||||
}
|
||||
|
||||
commit_subject () {
|
||||
(cd clone &&
|
||||
git show -s --pretty=format:%s "$@")
|
||||
}
|
||||
|
||||
test_expect_success '@{upstream} resolves to correct full name' '
|
||||
test refs/remotes/origin/master = "$(full_name @{upstream})"
|
||||
'
|
||||
|
||||
test_expect_success '@{u} resolves to correct full name' '
|
||||
test refs/remotes/origin/master = "$(full_name @{u})"
|
||||
'
|
||||
|
||||
test_expect_success 'my-side@{upstream} resolves to correct full name' '
|
||||
test refs/remotes/origin/side = "$(full_name my-side@{u})"
|
||||
'
|
||||
|
||||
test_expect_success 'my-side@{u} resolves to correct commit' '
|
||||
git checkout side &&
|
||||
test_commit 5 &&
|
||||
(cd clone && git fetch) &&
|
||||
test 2 = "$(commit_subject my-side)" &&
|
||||
test 5 = "$(commit_subject my-side@{u})"
|
||||
'
|
||||
|
||||
test_expect_success 'not-tracking@{u} fails' '
|
||||
test_must_fail full_name non-tracking@{u} &&
|
||||
(cd clone && git checkout --no-track -b non-tracking) &&
|
||||
test_must_fail full_name non-tracking@{u}
|
||||
'
|
||||
|
||||
test_expect_success '<branch>@{u}@{1} resolves correctly' '
|
||||
test_commit 6 &&
|
||||
(cd clone && git fetch) &&
|
||||
test 5 = $(commit_subject my-side@{u}@{1})
|
||||
'
|
||||
|
||||
test_expect_success '@{u} without specifying branch fails on a detached HEAD' '
|
||||
git checkout HEAD^0 &&
|
||||
test_must_fail git rev-parse @{u}
|
||||
'
|
||||
|
||||
test_done
|
Загрузка…
Ссылка в новой задаче