зеркало из https://github.com/microsoft/git.git
Merge branch 'sp/refspec-match'
* sp/refspec-match: refactor fetch's ref matching to use refname_match() push: use same rules as git-rev-parse to resolve refspecs add refname_match() push: support pushing HEAD to real branch name
This commit is contained in:
Коммит
9bbe6db85f
|
@ -85,7 +85,9 @@ Each pattern pair consists of the source side (before the colon)
|
|||
and the destination side (after the colon). The ref to be
|
||||
pushed is determined by finding a match that matches the source
|
||||
side, and where it is pushed is determined by using the
|
||||
destination side.
|
||||
destination side. The rules used to match a ref are the same
|
||||
rules used by gitlink:git-rev-parse[1] to resolve a symbolic ref
|
||||
name.
|
||||
|
||||
- It is an error if <src> does not match exactly one of the
|
||||
local refs.
|
||||
|
|
|
@ -44,6 +44,15 @@ static void set_refspecs(const char **refs, int nr)
|
|||
strcat(tag, refs[i]);
|
||||
ref = tag;
|
||||
}
|
||||
if (!strcmp("HEAD", ref)) {
|
||||
unsigned char sha1_dummy[20];
|
||||
ref = resolve_ref(ref, sha1_dummy, 1, NULL);
|
||||
if (!ref)
|
||||
die("HEAD cannot be resolved.");
|
||||
if (prefixcmp(ref, "refs/heads/"))
|
||||
die("HEAD cannot be resolved to branch.");
|
||||
ref = xstrdup(ref + 11);
|
||||
}
|
||||
add_refspec(ref);
|
||||
}
|
||||
}
|
||||
|
|
4
cache.h
4
cache.h
|
@ -423,6 +423,10 @@ extern const char *resolve_ref(const char *path, unsigned char *sha1, int, int *
|
|||
extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref);
|
||||
extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);
|
||||
|
||||
extern int refname_match(const char *abbrev_name, const char *full_name, const char **rules);
|
||||
extern const char *ref_rev_parse_rules[];
|
||||
extern const char *ref_fetch_rules[];
|
||||
|
||||
extern int create_symref(const char *ref, const char *refs_heads_master, const char *logmsg);
|
||||
extern int validate_headref(const char *ref);
|
||||
|
||||
|
|
31
refs.c
31
refs.c
|
@ -643,6 +643,37 @@ int check_ref_format(const char *ref)
|
|||
}
|
||||
}
|
||||
|
||||
const char *ref_rev_parse_rules[] = {
|
||||
"%.*s",
|
||||
"refs/%.*s",
|
||||
"refs/tags/%.*s",
|
||||
"refs/heads/%.*s",
|
||||
"refs/remotes/%.*s",
|
||||
"refs/remotes/%.*s/HEAD",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char *ref_fetch_rules[] = {
|
||||
"%.*s",
|
||||
"refs/%.*s",
|
||||
"refs/heads/%.*s",
|
||||
NULL
|
||||
};
|
||||
|
||||
int refname_match(const char *abbrev_name, const char *full_name, const char **rules)
|
||||
{
|
||||
const char **p;
|
||||
const int abbrev_name_len = strlen(abbrev_name);
|
||||
|
||||
for (p = rules; *p; p++) {
|
||||
if (!strcmp(full_name, mkpath(*p, abbrev_name_len, abbrev_name))) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ref_lock *verify_lock(struct ref_lock *lock,
|
||||
const unsigned char *old_sha1, int mustexist)
|
||||
{
|
||||
|
|
28
remote.c
28
remote.c
|
@ -419,25 +419,6 @@ int remote_has_url(struct remote *remote, const char *url)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if, under the matching rules for fetching, name is the
|
||||
* same as the given full name.
|
||||
*/
|
||||
static int ref_matches_abbrev(const char *name, const char *full)
|
||||
{
|
||||
if (!prefixcmp(name, "refs/") || !strcmp(name, "HEAD"))
|
||||
return !strcmp(name, full);
|
||||
if (prefixcmp(full, "refs/"))
|
||||
return 0;
|
||||
if (!prefixcmp(name, "heads/") ||
|
||||
!prefixcmp(name, "tags/") ||
|
||||
!prefixcmp(name, "remotes/"))
|
||||
return !strcmp(name, full + 5);
|
||||
if (prefixcmp(full + 5, "heads/"))
|
||||
return 0;
|
||||
return !strcmp(full + 11, name);
|
||||
}
|
||||
|
||||
int remote_find_tracking(struct remote *remote, struct refspec *refspec)
|
||||
{
|
||||
int find_src = refspec->src == NULL;
|
||||
|
@ -533,10 +514,7 @@ static int count_refspec_match(const char *pattern,
|
|||
char *name = refs->name;
|
||||
int namelen = strlen(name);
|
||||
|
||||
if (namelen < patlen ||
|
||||
memcmp(name + namelen - patlen, pattern, patlen))
|
||||
continue;
|
||||
if (namelen != patlen && name[namelen - patlen - 1] != '/')
|
||||
if (!refname_match(pattern, name, ref_rev_parse_rules))
|
||||
continue;
|
||||
|
||||
/* A match is "weak" if it is with refs outside
|
||||
|
@ -818,7 +796,7 @@ int branch_merge_matches(struct branch *branch,
|
|||
{
|
||||
if (!branch || i < 0 || i >= branch->merge_nr)
|
||||
return 0;
|
||||
return ref_matches_abbrev(branch->merge[i]->src, refname);
|
||||
return refname_match(branch->merge[i]->src, refname, ref_fetch_rules);
|
||||
}
|
||||
|
||||
static struct ref *get_expanded_map(const struct ref *remote_refs,
|
||||
|
@ -857,7 +835,7 @@ static const struct ref *find_ref_by_name_abbrev(const struct ref *refs, const c
|
|||
{
|
||||
const struct ref *ref;
|
||||
for (ref = refs; ref; ref = ref->next) {
|
||||
if (ref_matches_abbrev(name, ref->name))
|
||||
if (refname_match(name, ref->name, ref_fetch_rules))
|
||||
return ref;
|
||||
}
|
||||
return NULL;
|
||||
|
|
14
sha1_name.c
14
sha1_name.c
|
@ -239,23 +239,13 @@ static int ambiguous_path(const char *path, int len)
|
|||
return slash;
|
||||
}
|
||||
|
||||
static const char *ref_fmt[] = {
|
||||
"%.*s",
|
||||
"refs/%.*s",
|
||||
"refs/tags/%.*s",
|
||||
"refs/heads/%.*s",
|
||||
"refs/remotes/%.*s",
|
||||
"refs/remotes/%.*s/HEAD",
|
||||
NULL
|
||||
};
|
||||
|
||||
int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref)
|
||||
{
|
||||
const char **p, *r;
|
||||
int refs_found = 0;
|
||||
|
||||
*ref = NULL;
|
||||
for (p = ref_fmt; *p; p++) {
|
||||
for (p = ref_rev_parse_rules; *p; p++) {
|
||||
unsigned char sha1_from_ref[20];
|
||||
unsigned char *this_result;
|
||||
|
||||
|
@ -277,7 +267,7 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log)
|
|||
int logs_found = 0;
|
||||
|
||||
*log = NULL;
|
||||
for (p = ref_fmt; *p; p++) {
|
||||
for (p = ref_rev_parse_rules; *p; p++) {
|
||||
struct stat st;
|
||||
unsigned char hash[20];
|
||||
char path[PATH_MAX];
|
||||
|
|
|
@ -95,6 +95,31 @@ test_expect_success 'fetch following tags' '
|
|||
|
||||
'
|
||||
|
||||
test_expect_failure 'fetch must not resolve short tag name' '
|
||||
|
||||
cd "$D" &&
|
||||
|
||||
mkdir five &&
|
||||
cd five &&
|
||||
git init &&
|
||||
|
||||
git fetch .. anno:five
|
||||
|
||||
'
|
||||
|
||||
test_expect_failure 'fetch must not resolve short remote name' '
|
||||
|
||||
cd "$D" &&
|
||||
git-update-ref refs/remotes/six/HEAD HEAD
|
||||
|
||||
mkdir six &&
|
||||
cd six &&
|
||||
git init &&
|
||||
|
||||
git fetch .. six:six
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'create bundle 1' '
|
||||
cd "$D" &&
|
||||
echo >file updated again by origin &&
|
||||
|
|
|
@ -145,11 +145,21 @@ test_expect_success 'push with no ambiguity (1)' '
|
|||
test_expect_success 'push with no ambiguity (2)' '
|
||||
|
||||
mk_test remotes/origin/master &&
|
||||
git push testrepo master:master &&
|
||||
git push testrepo master:origin/master &&
|
||||
check_push_result $the_commit remotes/origin/master
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'push with colon-less refspec, no ambiguity' '
|
||||
|
||||
mk_test heads/master heads/t/master &&
|
||||
git branch -f t/master master &&
|
||||
git push testrepo master &&
|
||||
check_push_result $the_commit heads/master &&
|
||||
check_push_result $the_first_commit heads/t/master
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'push with weak ambiguity (1)' '
|
||||
|
||||
mk_test heads/master remotes/origin/master &&
|
||||
|
@ -244,6 +254,23 @@ test_expect_success 'push with colon-less refspec (4)' '
|
|||
|
||||
'
|
||||
|
||||
test_expect_success 'push with HEAD' '
|
||||
|
||||
mk_test heads/master &&
|
||||
git checkout master &&
|
||||
git push testrepo HEAD &&
|
||||
check_push_result $the_commit heads/master
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'push with HEAD nonexisting at remote' '
|
||||
|
||||
mk_test heads/master &&
|
||||
git checkout -b local master &&
|
||||
git push testrepo HEAD &&
|
||||
check_push_result $the_commit heads/local
|
||||
'
|
||||
|
||||
test_expect_success 'push with dry-run' '
|
||||
|
||||
mk_test heads/master &&
|
||||
|
|
Загрузка…
Ссылка в новой задаче