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:
Junio C Hamano 2007-12-04 17:07:10 -08:00
Родитель f64c81d428 605b4978a1
Коммит 9bbe6db85f
8 изменённых файлов: 105 добавлений и 39 удалений

Просмотреть файл

@ -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);
}
}

Просмотреть файл

@ -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
Просмотреть файл

@ -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)
{

Просмотреть файл

@ -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;

Просмотреть файл

@ -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 &&