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:
commit
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
|
and the destination side (after the colon). The ref to be
|
||||||
pushed is determined by finding a match that matches the source
|
pushed is determined by finding a match that matches the source
|
||||||
side, and where it is pushed is determined by using the
|
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
|
- It is an error if <src> does not match exactly one of the
|
||||||
local refs.
|
local refs.
|
||||||
|
@ -44,6 +44,15 @@ static void set_refspecs(const char **refs, int nr)
|
|||||||
strcat(tag, refs[i]);
|
strcat(tag, refs[i]);
|
||||||
ref = tag;
|
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);
|
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_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 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 create_symref(const char *ref, const char *refs_heads_master, const char *logmsg);
|
||||||
extern int validate_headref(const char *ref);
|
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,
|
static struct ref_lock *verify_lock(struct ref_lock *lock,
|
||||||
const unsigned char *old_sha1, int mustexist)
|
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;
|
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 remote_find_tracking(struct remote *remote, struct refspec *refspec)
|
||||||
{
|
{
|
||||||
int find_src = refspec->src == NULL;
|
int find_src = refspec->src == NULL;
|
||||||
@ -533,10 +514,7 @@ static int count_refspec_match(const char *pattern,
|
|||||||
char *name = refs->name;
|
char *name = refs->name;
|
||||||
int namelen = strlen(name);
|
int namelen = strlen(name);
|
||||||
|
|
||||||
if (namelen < patlen ||
|
if (!refname_match(pattern, name, ref_rev_parse_rules))
|
||||||
memcmp(name + namelen - patlen, pattern, patlen))
|
|
||||||
continue;
|
|
||||||
if (namelen != patlen && name[namelen - patlen - 1] != '/')
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* A match is "weak" if it is with refs outside
|
/* 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)
|
if (!branch || i < 0 || i >= branch->merge_nr)
|
||||||
return 0;
|
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,
|
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;
|
const struct ref *ref;
|
||||||
for (ref = refs; ref; ref = ref->next) {
|
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 ref;
|
||||||
}
|
}
|
||||||
return NULL;
|
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;
|
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)
|
int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref)
|
||||||
{
|
{
|
||||||
const char **p, *r;
|
const char **p, *r;
|
||||||
int refs_found = 0;
|
int refs_found = 0;
|
||||||
|
|
||||||
*ref = NULL;
|
*ref = NULL;
|
||||||
for (p = ref_fmt; *p; p++) {
|
for (p = ref_rev_parse_rules; *p; p++) {
|
||||||
unsigned char sha1_from_ref[20];
|
unsigned char sha1_from_ref[20];
|
||||||
unsigned char *this_result;
|
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;
|
int logs_found = 0;
|
||||||
|
|
||||||
*log = NULL;
|
*log = NULL;
|
||||||
for (p = ref_fmt; *p; p++) {
|
for (p = ref_rev_parse_rules; *p; p++) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
unsigned char hash[20];
|
unsigned char hash[20];
|
||||||
char path[PATH_MAX];
|
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' '
|
test_expect_success 'create bundle 1' '
|
||||||
cd "$D" &&
|
cd "$D" &&
|
||||||
echo >file updated again by origin &&
|
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)' '
|
test_expect_success 'push with no ambiguity (2)' '
|
||||||
|
|
||||||
mk_test remotes/origin/master &&
|
mk_test remotes/origin/master &&
|
||||||
git push testrepo master:master &&
|
git push testrepo master:origin/master &&
|
||||||
check_push_result $the_commit remotes/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)' '
|
test_expect_success 'push with weak ambiguity (1)' '
|
||||||
|
|
||||||
mk_test heads/master remotes/origin/master &&
|
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' '
|
test_expect_success 'push with dry-run' '
|
||||||
|
|
||||||
mk_test heads/master &&
|
mk_test heads/master &&
|
||||||
|
Loading…
Reference in New Issue
Block a user