Skip to content

Commit 083b1a2

Browse files
authored
Merge pull request libgit2#4021 from carlosmn/cmn/refspecs-fetchhead
FETCH_HEAD and multiple refspecs
2 parents 4110fc8 + c081f0d commit 083b1a2

File tree

5 files changed

+113
-9
lines changed

5 files changed

+113
-9
lines changed

src/fetchhead.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ int git_fetchhead_write(git_repository *repo, git_vector *fetchhead_refs)
118118
if (git_buf_joinpath(&path, repo->gitdir, GIT_FETCH_HEAD_FILE) < 0)
119119
return -1;
120120

121-
if (git_filebuf_open(&file, path.ptr, GIT_FILEBUF_FORCE, GIT_REFS_FILE_MODE) < 0) {
121+
if (git_filebuf_open(&file, path.ptr, GIT_FILEBUF_APPEND, GIT_REFS_FILE_MODE) < 0) {
122122
git_buf_free(&path);
123123
return -1;
124124
}

src/fileops.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,16 @@ int git_futils_open_ro(const char *path)
102102
return fd;
103103
}
104104

105+
int git_futils_truncate(const char *path, int mode)
106+
{
107+
int fd = p_open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, mode);
108+
if (fd < 0)
109+
return git_path_set_error(errno, path, "open");
110+
111+
close(fd);
112+
return 0;
113+
}
114+
105115
git_off_t git_futils_filesize(git_file fd)
106116
{
107117
struct stat sb;

src/fileops.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,11 @@ extern int git_futils_cp_r(
247247
*/
248248
extern int git_futils_open_ro(const char *path);
249249

250+
/**
251+
* Truncate a file, creating it if it doesn't exist.
252+
*/
253+
extern int git_futils_truncate(const char *path, int mode);
254+
250255
/**
251256
* Get the filesize in bytes of a file
252257
*/

src/remote.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1541,6 +1541,20 @@ static int opportunistic_updates(const git_remote *remote, const git_remote_call
15411541
return error;
15421542
}
15431543

1544+
static int truncate_fetch_head(const char *gitdir)
1545+
{
1546+
git_buf path = GIT_BUF_INIT;
1547+
int error;
1548+
1549+
if ((error = git_buf_joinpath(&path, gitdir, GIT_FETCH_HEAD_FILE)) < 0)
1550+
return error;
1551+
1552+
error = git_futils_truncate(path.ptr, GIT_REFS_FILE_MODE);
1553+
git_buf_free(&path);
1554+
1555+
return error;
1556+
}
1557+
15441558
int git_remote_update_tips(
15451559
git_remote *remote,
15461560
const git_remote_callbacks *callbacks,
@@ -1571,6 +1585,9 @@ int git_remote_update_tips(
15711585
else
15721586
tagopt = download_tags;
15731587

1588+
if ((error = truncate_fetch_head(git_repository_path(remote->repo))) < 0)
1589+
goto out;
1590+
15741591
if (tagopt == GIT_REMOTE_DOWNLOAD_TAGS_ALL) {
15751592
if ((error = update_tips_for_spec(remote, callbacks, update_fetchhead, tagopt, &tagspec, &refs, reflog_message)) < 0)
15761593
goto out;

tests/fetchhead/nonetwork.c

Lines changed: 80 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -353,20 +353,25 @@ void test_fetchhead_nonetwork__quote_in_branch_name(void)
353353
}
354354

355355
static bool found_master;
356-
static bool find_master_called;
356+
static bool found_haacked;
357+
static bool find_master_haacked_called;
357358

358-
int find_master(const char *ref_name, const char *remote_url, const git_oid *oid, unsigned int is_merge, void *payload)
359+
int find_master_haacked(const char *ref_name, const char *remote_url, const git_oid *oid, unsigned int is_merge, void *payload)
359360
{
360361
GIT_UNUSED(remote_url);
361362
GIT_UNUSED(oid);
362363
GIT_UNUSED(payload);
363364

364-
find_master_called = true;
365+
find_master_haacked_called = true;
365366

366367
if (!strcmp("refs/heads/master", ref_name)) {
367368
cl_assert(is_merge);
368369
found_master = true;
369370
}
371+
if (!strcmp("refs/heads/haacked", ref_name)) {
372+
cl_assert(is_merge);
373+
found_haacked = true;
374+
}
370375

371376
return 0;
372377
}
@@ -375,10 +380,12 @@ void test_fetchhead_nonetwork__create_when_refpecs_given(void)
375380
{
376381
git_remote *remote;
377382
git_buf path = GIT_BUF_INIT;
378-
char *refspec = "refs/heads/master";
383+
char *refspec1 = "refs/heads/master";
384+
char *refspec2 = "refs/heads/haacked";
385+
char *refspecs[] = { refspec1, refspec2 };
379386
git_strarray specs = {
380-
&refspec,
381-
1,
387+
refspecs,
388+
2,
382389
};
383390

384391
cl_set_cleanup(&cleanup_repository, "./test1");
@@ -391,9 +398,74 @@ void test_fetchhead_nonetwork__create_when_refpecs_given(void)
391398
cl_git_pass(git_remote_fetch(remote, &specs, NULL, NULL));
392399
cl_assert(git_path_exists(path.ptr));
393400

394-
cl_git_pass(git_repository_fetchhead_foreach(g_repo, find_master, NULL));
395-
cl_assert(find_master_called);
401+
cl_git_pass(git_repository_fetchhead_foreach(g_repo, find_master_haacked, NULL));
402+
cl_assert(find_master_haacked_called);
396403
cl_assert(found_master);
404+
cl_assert(found_haacked);
405+
406+
git_remote_free(remote);
407+
git_buf_free(&path);
408+
}
409+
410+
static bool count_refs_called;
411+
struct prefix_count {
412+
const char *prefix;
413+
int count;
414+
int expected;
415+
};
416+
417+
int count_refs(const char *ref_name, const char *remote_url, const git_oid *oid, unsigned int is_merge, void *payload)
418+
{
419+
int i;
420+
struct prefix_count *prefix_counts = (struct prefix_count *) payload;
421+
422+
GIT_UNUSED(remote_url);
423+
GIT_UNUSED(oid);
424+
GIT_UNUSED(is_merge);
425+
426+
count_refs_called = true;
427+
428+
for (i = 0; prefix_counts[i].prefix; i++) {
429+
if (!git__prefixcmp(ref_name, prefix_counts[i].prefix))
430+
prefix_counts[i].count++;
431+
}
432+
433+
return 0;
434+
}
435+
436+
void test_fetchhead_nonetwork__create_with_multiple_refspecs(void)
437+
{
438+
git_remote *remote;
439+
git_buf path = GIT_BUF_INIT;
440+
441+
cl_set_cleanup(&cleanup_repository, "./test1");
442+
cl_git_pass(git_repository_init(&g_repo, "./test1", 0));
443+
444+
cl_git_pass(git_remote_create(&remote, g_repo, "origin", cl_fixture("testrepo.git")));
445+
git_remote_free(remote);
446+
cl_git_pass(git_remote_add_fetch(g_repo, "origin", "+refs/notes/*:refs/origin/notes/*"));
447+
/* Pick up the new refspec */
448+
cl_git_pass(git_remote_lookup(&remote, g_repo, "origin"));
449+
450+
cl_git_pass(git_buf_joinpath(&path, git_repository_path(g_repo), "FETCH_HEAD"));
451+
cl_assert(!git_path_exists(path.ptr));
452+
cl_git_pass(git_remote_fetch(remote, NULL, NULL, NULL));
453+
cl_assert(git_path_exists(path.ptr));
454+
455+
{
456+
int i;
457+
struct prefix_count prefix_counts[] = {
458+
{"refs/notes/", 0, 1},
459+
{"refs/heads/", 0, 12},
460+
{"refs/tags/", 0, 7},
461+
{NULL, 0, 0},
462+
};
463+
464+
cl_git_pass(git_repository_fetchhead_foreach(g_repo, count_refs, &prefix_counts));
465+
cl_assert(count_refs_called);
466+
for (i = 0; prefix_counts[i].prefix; i++)
467+
cl_assert_equal_i(prefix_counts[i].expected, prefix_counts[i].count);
468+
}
397469

398470
git_remote_free(remote);
399471
git_buf_free(&path);

0 commit comments

Comments
 (0)