Skip to content

Commit dca31d2

Browse files
authored
Merge pull request libgit2#6101 from mkhl/fix/instead-of
remotes: fix insteadOf/pushInsteadOf handling
2 parents ab5b3f3 + de665a4 commit dca31d2

File tree

3 files changed

+153
-28
lines changed

3 files changed

+153
-28
lines changed

src/remote.c

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
static int dwim_refspecs(git_vector *out, git_vector *refspecs, git_vector *refs);
3232
static int lookup_remote_prune_config(git_remote *remote, git_config *config, const char *name);
33-
char *apply_insteadof(git_config *config, const char *url, int direction);
33+
char *apply_insteadof(bool *matched, git_config *config, const char *url, int direction);
3434

3535
static int add_refspec_to(git_vector *vector, const char *string, bool is_fetch)
3636
{
@@ -210,7 +210,9 @@ int git_remote_create_with_opts(git_remote **out, const char *url, const git_rem
210210
git_str var = GIT_STR_INIT;
211211
git_str specbuf = GIT_STR_INIT;
212212
const git_remote_create_options dummy_opts = GIT_REMOTE_CREATE_OPTIONS_INIT;
213+
char *tmp;
213214
int error = -1;
215+
bool matched;
214216

215217
GIT_ASSERT_ARG(out);
216218
GIT_ASSERT_ARG(url);
@@ -245,7 +247,12 @@ int git_remote_create_with_opts(git_remote **out, const char *url, const git_rem
245247
goto on_error;
246248

247249
if (opts->repository && !(opts->flags & GIT_REMOTE_CREATE_SKIP_INSTEADOF)) {
248-
remote->url = apply_insteadof(config_ro, canonical_url.ptr, GIT_DIRECTION_FETCH);
250+
remote->url = apply_insteadof(&matched, config_ro, canonical_url.ptr, GIT_DIRECTION_FETCH);
251+
tmp = apply_insteadof(&matched, config_ro, canonical_url.ptr, GIT_DIRECTION_PUSH);
252+
if (matched) {
253+
remote->pushurl = tmp;
254+
GIT_ERROR_CHECK_ALLOC(remote->pushurl);
255+
}
249256
} else {
250257
remote->url = git__strdup(canonical_url.ptr);
251258
}
@@ -457,7 +464,9 @@ int git_remote_lookup(git_remote **out, git_repository *repo, const char *name)
457464
git_remote *remote = NULL;
458465
git_str buf = GIT_STR_INIT;
459466
const char *val;
467+
char *tmp;
460468
int error = 0;
469+
bool matched;
461470
git_config *config;
462471
struct refspec_cb_data data = { NULL };
463472
bool optional_setting_found = false, found;
@@ -498,8 +507,13 @@ int git_remote_lookup(git_remote **out, git_repository *repo, const char *name)
498507
remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_AUTO;
499508

500509
if (found && strlen(val) > 0) {
501-
remote->url = apply_insteadof(config, val, GIT_DIRECTION_FETCH);
510+
remote->url = apply_insteadof(&matched, config, val, GIT_DIRECTION_FETCH);
502511
GIT_ERROR_CHECK_ALLOC(remote->url);
512+
tmp = apply_insteadof(&matched, config, val, GIT_DIRECTION_PUSH);
513+
if (matched) {
514+
remote->pushurl = tmp;
515+
GIT_ERROR_CHECK_ALLOC(remote->pushurl);
516+
}
503517
}
504518

505519
val = NULL;
@@ -518,7 +532,10 @@ int git_remote_lookup(git_remote **out, git_repository *repo, const char *name)
518532
}
519533

520534
if (found && strlen(val) > 0) {
521-
remote->pushurl = apply_insteadof(config, val, GIT_DIRECTION_PUSH);
535+
if (remote->pushurl) {
536+
git__free(remote->pushurl);
537+
}
538+
remote->pushurl = apply_insteadof(&matched, config, val, GIT_DIRECTION_FETCH);
522539
GIT_ERROR_CHECK_ALLOC(remote->pushurl);
523540
}
524541

@@ -2719,7 +2736,7 @@ int git_remote_push(git_remote *remote, const git_strarray *refspecs, const git_
27192736
#define SUFFIX_FETCH "insteadof"
27202737
#define SUFFIX_PUSH "pushinsteadof"
27212738

2722-
char *apply_insteadof(git_config *config, const char *url, int direction)
2739+
char *apply_insteadof(bool *matched, git_config *config, const char *url, int direction)
27232740
{
27242741
size_t match_length, prefix_length, suffix_length;
27252742
char *replacement = NULL;
@@ -2732,6 +2749,8 @@ char *apply_insteadof(git_config *config, const char *url, int direction)
27322749
GIT_ASSERT_ARG_WITH_RETVAL(config, NULL);
27332750
GIT_ASSERT_ARG_WITH_RETVAL(url, NULL);
27342751
GIT_ASSERT_ARG_WITH_RETVAL(direction == GIT_DIRECTION_FETCH || direction == GIT_DIRECTION_PUSH, NULL);
2752+
GIT_ASSERT_ARG_WITH_RETVAL(matched, NULL);
2753+
*matched = 0;
27352754

27362755
/* Add 1 to prefix/suffix length due to the additional escaped dot */
27372756
prefix_length = strlen(PREFIX) + 1;
@@ -2777,6 +2796,7 @@ char *apply_insteadof(git_config *config, const char *url, int direction)
27772796

27782797
git__free(replacement);
27792798

2799+
*matched = 1;
27802800
return result.ptr;
27812801
}
27822802

tests/remote/insteadof.c

Lines changed: 96 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@
44

55
#define REPO_PATH "testrepo2/.gitted"
66
#define REMOTE_ORIGIN "origin"
7-
#define REMOTE_INSTEADOF "insteadof-test"
7+
#define REMOTE_INSTEADOF_URL_FETCH "insteadof-url-fetch"
8+
#define REMOTE_INSTEADOF_URL_PUSH "insteadof-url-push"
9+
#define REMOTE_INSTEADOF_URL_BOTH "insteadof-url-both"
10+
#define REMOTE_INSTEADOF_PUSHURL_FETCH "insteadof-pushurl-fetch"
11+
#define REMOTE_INSTEADOF_PUSHURL_PUSH "insteadof-pushurl-push"
12+
#define REMOTE_INSTEADOF_PUSHURL_BOTH "insteadof-pushurl-both"
813

914
static git_repository *g_repo;
1015
static git_remote *g_remote;
@@ -21,52 +26,129 @@ void test_remote_insteadof__cleanup(void)
2126
git_remote_free(g_remote);
2227
}
2328

24-
void test_remote_insteadof__url_insteadof_not_applicable(void)
29+
void test_remote_insteadof__not_applicable(void)
2530
{
2631
cl_git_pass(git_repository_open(&g_repo, cl_fixture(REPO_PATH)));
2732
cl_git_pass(git_remote_lookup(&g_remote, g_repo, REMOTE_ORIGIN));
2833

2934
cl_assert_equal_s(
3035
git_remote_url(g_remote),
3136
"https://github.com/libgit2/false.git");
37+
cl_assert_equal_p(git_remote_pushurl(g_remote), NULL);
3238
}
3339

34-
void test_remote_insteadof__url_insteadof_applicable(void)
40+
void test_remote_insteadof__url_insteadof_fetch(void)
3541
{
3642
cl_git_pass(git_repository_open(&g_repo, cl_fixture(REPO_PATH)));
37-
cl_git_pass(git_remote_lookup(&g_remote, g_repo, REMOTE_INSTEADOF));
43+
cl_git_pass(git_remote_lookup(&g_remote, g_repo, REMOTE_INSTEADOF_URL_FETCH));
3844

3945
cl_assert_equal_s(
4046
git_remote_url(g_remote),
41-
"http://github.com/libgit2/libgit2");
47+
"http://github.com/url/fetch/libgit2");
48+
cl_assert_equal_p(git_remote_pushurl(g_remote), NULL);
4249
}
4350

44-
void test_remote_insteadof__pushurl_insteadof_not_applicable(void)
51+
void test_remote_insteadof__url_insteadof_push(void)
4552
{
4653
cl_git_pass(git_repository_open(&g_repo, cl_fixture(REPO_PATH)));
47-
cl_git_pass(git_remote_lookup(&g_remote, g_repo, REMOTE_ORIGIN));
54+
cl_git_pass(git_remote_lookup(&g_remote, g_repo, REMOTE_INSTEADOF_URL_PUSH));
4855

49-
cl_assert_equal_p(git_remote_pushurl(g_remote), NULL);
56+
cl_assert_equal_s(
57+
git_remote_url(g_remote),
58+
"http://example.com/url/push/libgit2");
59+
cl_assert_equal_s(
60+
git_remote_pushurl(g_remote),
61+
"git@github.com:url/push/libgit2");
5062
}
5163

52-
void test_remote_insteadof__pushurl_insteadof_applicable(void)
64+
void test_remote_insteadof__url_insteadof_both(void)
5365
{
5466
cl_git_pass(git_repository_open(&g_repo, cl_fixture(REPO_PATH)));
55-
cl_git_pass(git_remote_lookup(&g_remote, g_repo, REMOTE_INSTEADOF));
67+
cl_git_pass(git_remote_lookup(&g_remote, g_repo, REMOTE_INSTEADOF_URL_BOTH));
5668

69+
cl_assert_equal_s(
70+
git_remote_url(g_remote),
71+
"http://github.com/url/both/libgit2");
5772
cl_assert_equal_s(
5873
git_remote_pushurl(g_remote),
59-
"git@github.com:libgit2/libgit2");
74+
"git@github.com:url/both/libgit2");
6075
}
6176

62-
void test_remote_insteadof__anonymous_remote(void)
77+
void test_remote_insteadof__pushurl_insteadof_fetch(void)
78+
{
79+
cl_git_pass(git_repository_open(&g_repo, cl_fixture(REPO_PATH)));
80+
cl_git_pass(git_remote_lookup(&g_remote, g_repo, REMOTE_INSTEADOF_PUSHURL_FETCH));
81+
82+
cl_assert_equal_s(
83+
git_remote_url(g_remote),
84+
"http://github.com/url/fetch/libgit2");
85+
cl_assert_equal_s(
86+
git_remote_pushurl(g_remote),
87+
"http://github.com/url/fetch/libgit2-push");
88+
}
89+
90+
void test_remote_insteadof__pushurl_insteadof_push(void)
91+
{
92+
cl_git_pass(git_repository_open(&g_repo, cl_fixture(REPO_PATH)));
93+
cl_git_pass(git_remote_lookup(&g_remote, g_repo, REMOTE_INSTEADOF_PUSHURL_PUSH));
94+
95+
cl_assert_equal_s(
96+
git_remote_url(g_remote),
97+
"http://example.com/url/push/libgit2");
98+
cl_assert_equal_s(
99+
git_remote_pushurl(g_remote),
100+
"http://example.com/url/push/libgit2-push");
101+
}
102+
103+
void test_remote_insteadof__pushurl_insteadof_both(void)
104+
{
105+
cl_git_pass(git_repository_open(&g_repo, cl_fixture(REPO_PATH)));
106+
cl_git_pass(git_remote_lookup(&g_remote, g_repo, REMOTE_INSTEADOF_PUSHURL_BOTH));
107+
108+
cl_assert_equal_s(
109+
git_remote_url(g_remote),
110+
"http://github.com/url/both/libgit2");
111+
cl_assert_equal_s(
112+
git_remote_pushurl(g_remote),
113+
"http://github.com/url/both/libgit2-push");
114+
}
115+
116+
void test_remote_insteadof__anonymous_remote_fetch(void)
63117
{
64118
cl_git_pass(git_repository_open(&g_repo, cl_fixture(REPO_PATH)));
65119
cl_git_pass(git_remote_create_anonymous(&g_remote, g_repo,
66-
"http://example.com/libgit2/libgit2"));
120+
"http://example.com/url/fetch/libgit2"));
67121

68122
cl_assert_equal_s(
69123
git_remote_url(g_remote),
70-
"http://github.com/libgit2/libgit2");
124+
"http://github.com/url/fetch/libgit2");
71125
cl_assert_equal_p(git_remote_pushurl(g_remote), NULL);
72126
}
127+
128+
void test_remote_insteadof__anonymous_remote_push(void)
129+
{
130+
cl_git_pass(git_repository_open(&g_repo, cl_fixture(REPO_PATH)));
131+
cl_git_pass(git_remote_create_anonymous(&g_remote, g_repo,
132+
"http://example.com/url/push/libgit2"));
133+
134+
cl_assert_equal_s(
135+
git_remote_url(g_remote),
136+
"http://example.com/url/push/libgit2");
137+
cl_assert_equal_s(
138+
git_remote_pushurl(g_remote),
139+
"git@github.com:url/push/libgit2");
140+
}
141+
142+
void test_remote_insteadof__anonymous_remote_both(void)
143+
{
144+
cl_git_pass(git_repository_open(&g_repo, cl_fixture(REPO_PATH)));
145+
cl_git_pass(git_remote_create_anonymous(&g_remote, g_repo,
146+
"http://example.com/url/both/libgit2"));
147+
148+
cl_assert_equal_s(
149+
git_remote_url(g_remote),
150+
"http://github.com/url/both/libgit2");
151+
cl_assert_equal_s(
152+
git_remote_pushurl(g_remote),
153+
"git@github.com:url/both/libgit2");
154+
}

tests/resources/testrepo2/.gitted/config

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,42 @@
88
[remote "origin"]
99
url = https://github.com/libgit2/false.git
1010
fetch = +refs/heads/*:refs/remotes/origin/*
11-
[remote "insteadof-test"]
12-
url = http://example.com/libgit2/libgit2
13-
pushurl = http://github.com/libgit2/libgit2
11+
[remote "insteadof-url-fetch"]
12+
url = http://example.com/url/fetch/libgit2
13+
fetch = +refs/heads/*:refs/remotes/test/*
14+
[remote "insteadof-url-push"]
15+
url = http://example.com/url/push/libgit2
16+
fetch = +refs/heads/*:refs/remotes/test/*
17+
[remote "insteadof-url-both"]
18+
url = http://example.com/url/both/libgit2
19+
fetch = +refs/heads/*:refs/remotes/test/*
20+
[remote "insteadof-pushurl-fetch"]
21+
url = http://example.com/url/fetch/libgit2
22+
pushurl = http://example.com/url/fetch/libgit2-push
23+
fetch = +refs/heads/*:refs/remotes/test/*
24+
[remote "insteadof-pushurl-push"]
25+
url = http://example.com/url/push/libgit2
26+
pushurl = http://example.com/url/push/libgit2-push
27+
fetch = +refs/heads/*:refs/remotes/test/*
28+
[remote "insteadof-pushurl-both"]
29+
url = http://example.com/url/both/libgit2
30+
pushurl = http://example.com/url/both/libgit2-push
1431
fetch = +refs/heads/*:refs/remotes/test/*
1532
[branch "master"]
1633
remote = origin
1734
merge = refs/heads/master
1835
rebase = true
1936
[url "longer-non-prefix-match"]
20-
insteadOf = ttp://example.com/li
37+
# not applicable because it's not a prefix match
38+
insteadOf = ttp://example.com/url/fetch/li
2139
[url "shorter-prefix"]
22-
insteadOf = http://example.co
23-
[url "http://github.com"]
24-
insteadOf = http://example.com
25-
[url "git@github.com:"]
26-
pushInsteadOf = http://github.com/
40+
# not applicable because the matched prefix is shorter
41+
insteadOf = http://example.com/url/fe
42+
[url "http://github.com/url/fetch"]
43+
insteadOf = http://example.com/url/fetch
44+
[url "http://github.com/url/both"]
45+
insteadOf = http://example.com/url/both
46+
[url "git@github.com:url/push"]
47+
pushInsteadOf = http://example.com/url/push
48+
[url "git@github.com:url/both"]
49+
pushInsteadOf = http://example.com/url/both

0 commit comments

Comments
 (0)