Commit 85addddf by Patrick Steinhardt Committed by Carlos Martín Nieto

refspec: do not set empty rhs for fetch refspecs

According to git-fetch(1), "[t]he colon can be omitted when <dst>
is empty." So according to git, the refspec "refs/heads/master"
is the same as the refspec "refs/heads/master:" when fetching
changes. When trying to fetch from a remote with a trailing
colon with libgit2, though, the fetch actually fails while it
works when the trailing colon is left out. So obviously, libgit2
does _not_ treat these two refspec formats the same for fetches.

The problem results from parsing refspecs, where the resulting
refspec has its destination set to an empty string in the case of
a trailing colon and to a `NULL` pointer in the case of no
trailing colon. When passing this to our DWIM machinery, the
empty string gets translated to "refs/heads/", which is simply
wrong.

Fix the problem by having the parsing machinery treat both cases
the same for fetch refspecs.
parent d711165d
......@@ -53,8 +53,10 @@ int git_refspec__parse(git_refspec *refspec, const char *input, bool is_fetch)
if (rhs) {
size_t rlen = strlen(++rhs);
is_glob = (1 <= rlen && strchr(rhs, '*'));
refspec->dst = git__strndup(rhs, rlen);
if (rlen || !is_fetch) {
is_glob = (1 <= rlen && strchr(rhs, '*'));
refspec->dst = git__strndup(rhs, rlen);
}
}
llen = (rhs ? (size_t)(rhs - lhs - 1) : strlen(lhs));
......
......@@ -35,6 +35,19 @@ static void fetchhead_test_clone(void)
cl_git_pass(git_clone(&g_repo, LIVE_REPO_URL, "./foo", &g_options));
}
static int count_references(void)
{
git_strarray array;
int refs;
cl_git_pass(git_reference_list(&array, g_repo));
refs = array.count;
git_strarray_free(&array);
return refs;
}
static void fetchhead_test_fetch(const char *fetchspec, const char *expected_fetchhead)
{
git_remote *remote;
......@@ -101,3 +114,41 @@ void test_online_fetchhead__no_merges(void)
cl_git_pass(git_tag_delete(g_repo, "commit_tree"));
fetchhead_test_fetch(NULL, FETCH_HEAD_NO_MERGE_DATA3);
}
void test_online_fetchhead__explicit_dst_refspec_creates_branch(void)
{
git_reference *ref;
int refs;
fetchhead_test_clone();
refs = count_references();
fetchhead_test_fetch("refs/heads/first-merge:refs/heads/explicit-refspec", FETCH_HEAD_EXPLICIT_DATA);
cl_git_pass(git_branch_lookup(&ref, g_repo, "explicit-refspec", GIT_BRANCH_ALL));
cl_assert_equal_i(refs + 1, count_references());
}
void test_online_fetchhead__empty_dst_refspec_creates_no_branch(void)
{
git_reference *ref;
int refs;
fetchhead_test_clone();
refs = count_references();
fetchhead_test_fetch("refs/heads/first-merge", FETCH_HEAD_EXPLICIT_DATA);
cl_git_fail(git_branch_lookup(&ref, g_repo, "first-merge", GIT_BRANCH_ALL));
cl_assert_equal_i(refs, count_references());
}
void test_online_fetchhead__colon_only_dst_refspec_creates_no_branch(void)
{
int refs;
fetchhead_test_clone();
refs = count_references();
fetchhead_test_fetch("refs/heads/first-merge:", FETCH_HEAD_EXPLICIT_DATA);
cl_assert_equal_i(refs, count_references());
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment