Skip to content

Commit 4bfab58

Browse files
committed
Merge branch 'ps/guess-repo-name-at-root'
"git clone $URL", when cloning from a site whose sole purpose is to host a single repository (hence, no path after <scheme>://<site>/), tried to use the site name as the new repository name, but did not remove username or password when <site> part was of the form <user>@<pass>:<host>. The code is taught to redact these. * ps/guess-repo-name-at-root: clone: abort if no dir name could be guessed clone: do not use port number as dir name clone: do not include authentication data in guessed dir
2 parents 8259da5 + adef956 commit 4bfab58

File tree

2 files changed

+61
-19
lines changed

2 files changed

+61
-19
lines changed

builtin/clone.c

Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -146,37 +146,79 @@ static char *get_repo_path(const char *repo, int *is_bundle)
146146

147147
static char *guess_dir_name(const char *repo, int is_bundle, int is_bare)
148148
{
149-
const char *end = repo + strlen(repo), *start;
149+
const char *end = repo + strlen(repo), *start, *ptr;
150150
size_t len;
151151
char *dir;
152152

153+
/*
154+
* Skip scheme.
155+
*/
156+
start = strstr(repo, "://");
157+
if (start == NULL)
158+
start = repo;
159+
else
160+
start += 3;
161+
162+
/*
163+
* Skip authentication data. The stripping does happen
164+
* greedily, such that we strip up to the last '@' inside
165+
* the host part.
166+
*/
167+
for (ptr = start; ptr < end && !is_dir_sep(*ptr); ptr++) {
168+
if (*ptr == '@')
169+
start = ptr + 1;
170+
}
171+
153172
/*
154173
* Strip trailing spaces, slashes and /.git
155174
*/
156-
while (repo < end && (is_dir_sep(end[-1]) || isspace(end[-1])))
175+
while (start < end && (is_dir_sep(end[-1]) || isspace(end[-1])))
157176
end--;
158-
if (end - repo > 5 && is_dir_sep(end[-5]) &&
177+
if (end - start > 5 && is_dir_sep(end[-5]) &&
159178
!strncmp(end - 4, ".git", 4)) {
160179
end -= 5;
161-
while (repo < end && is_dir_sep(end[-1]))
180+
while (start < end && is_dir_sep(end[-1]))
162181
end--;
163182
}
164183

165184
/*
166-
* Find last component, but be prepared that repo could have
167-
* the form "remote.example.com:foo.git", i.e. no slash
168-
* in the directory part.
185+
* Strip trailing port number if we've got only a
186+
* hostname (that is, there is no dir separator but a
187+
* colon). This check is required such that we do not
188+
* strip URI's like '/foo/bar:2222.git', which should
189+
* result in a dir '2222' being guessed due to backwards
190+
* compatibility.
191+
*/
192+
if (memchr(start, '/', end - start) == NULL
193+
&& memchr(start, ':', end - start) != NULL) {
194+
ptr = end;
195+
while (start < ptr && isdigit(ptr[-1]) && ptr[-1] != ':')
196+
ptr--;
197+
if (start < ptr && ptr[-1] == ':')
198+
end = ptr - 1;
199+
}
200+
201+
/*
202+
* Find last component. To remain backwards compatible we
203+
* also regard colons as path separators, such that
204+
* cloning a repository 'foo:bar.git' would result in a
205+
* directory 'bar' being guessed.
169206
*/
170-
start = end;
171-
while (repo < start && !is_dir_sep(start[-1]) && start[-1] != ':')
172-
start--;
207+
ptr = end;
208+
while (start < ptr && !is_dir_sep(ptr[-1]) && ptr[-1] != ':')
209+
ptr--;
210+
start = ptr;
173211

174212
/*
175213
* Strip .{bundle,git}.
176214
*/
177215
len = end - start;
178216
strip_suffix_mem(start, &len, is_bundle ? ".bundle" : ".git");
179217

218+
if (!len || (len == 1 && *start == '/'))
219+
die("No directory name could be guessed.\n"
220+
"Please specify a directory on the command line");
221+
180222
if (is_bare)
181223
dir = xstrfmt("%.*s.git", (int)len, start);
182224
else

t/t5603-clone-dirname.sh

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -76,17 +76,17 @@ test_clone_dir host:foo/.git/// foo
7676

7777
# omitting the path should default to the hostname
7878
test_clone_dir ssh://host/ host
79-
test_clone_dir ssh://host:1234/ host fail
80-
test_clone_dir ssh://user@host/ host fail
81-
test_clone_dir host:/ host fail
79+
test_clone_dir ssh://host:1234/ host
80+
test_clone_dir ssh://user@host/ host
81+
test_clone_dir host:/ host
8282

8383
# auth materials should be redacted
84-
test_clone_dir ssh://user:password@host/ host fail
85-
test_clone_dir ssh://user:password@host:1234/ host fail
86-
test_clone_dir ssh://user:passw@rd@host:1234/ host fail
87-
test_clone_dir user@host:/ host fail
88-
test_clone_dir user:password@host:/ host fail
89-
test_clone_dir user:passw@rd@host:/ host fail
84+
test_clone_dir ssh://user:password@host/ host
85+
test_clone_dir ssh://user:password@host:1234/ host
86+
test_clone_dir ssh://user:passw@rd@host:1234/ host
87+
test_clone_dir user@host:/ host
88+
test_clone_dir user:password@host:/ host
89+
test_clone_dir user:passw@rd@host:/ host
9090

9191
# auth-like material should not be dropped
9292
test_clone_dir ssh://host/foo@bar foo@bar

0 commit comments

Comments
 (0)