Merge pull request #2057 from GrahamDennis/local-file-url-push-fix Fix local push to file:// URL.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
diff --git a/src/transports/local.c b/src/transports/local.c
index 253aca3..26ada48 100644
--- a/src/transports/local.c
+++ b/src/transports/local.c
@@ -156,6 +156,24 @@ on_error:
return -1;
}
+static int path_from_url_or_path(git_buf *local_path_out, const char *url_or_path)
+{
+ int error;
+
+ /* If url_or_path begins with file:// treat it as a URL */
+ if (!git__prefixcmp(url_or_path, "file://")) {
+ if ((error = git_path_fromurl(local_path_out, url_or_path)) < 0) {
+ return error;
+ }
+ } else { /* We assume url_or_path is already a path */
+ if ((error = git_buf_sets(local_path_out, url_or_path)) < 0) {
+ return error;
+ }
+ }
+
+ return 0;
+}
+
/*
* Try to open the url as a git directory. The direction doesn't
* matter in this case because we're calulating the heads ourselves.
@@ -181,17 +199,12 @@ static int local_connect(
t->direction = direction;
t->flags = flags;
- /* The repo layer doesn't want the prefix */
- if (!git__prefixcmp(t->url, "file://")) {
- if (git_path_fromurl(&buf, t->url) < 0) {
- git_buf_free(&buf);
- return -1;
- }
- path = git_buf_cstr(&buf);
-
- } else { /* We assume transport->url is already a path */
- path = t->url;
+ /* 'url' may be a url or path; convert to a path */
+ if ((error = path_from_url_or_path(&buf, url)) < 0) {
+ git_buf_free(&buf);
+ return error;
}
+ path = git_buf_cstr(&buf);
error = git_repository_open(&repo, path);
@@ -344,11 +357,24 @@ static int local_push(
git_repository *remote_repo = NULL;
push_spec *spec;
char *url = NULL;
+ const char *path;
+ git_buf buf = GIT_BUF_INIT;
int error;
unsigned int i;
size_t j;
- if ((error = git_repository_open(&remote_repo, push->remote->url)) < 0)
+ /* 'push->remote->url' may be a url or path; convert to a path */
+ if ((error = path_from_url_or_path(&buf, push->remote->url)) < 0) {
+ git_buf_free(&buf);
+ return error;
+ }
+ path = git_buf_cstr(&buf);
+
+ error = git_repository_open(&remote_repo, path);
+
+ git_buf_free(&buf);
+
+ if (error < 0)
return error;
/* We don't currently support pushing locally to non-bare repos. Proper
diff --git a/tests/network/remote/local.c b/tests/network/remote/local.c
index 3091429..c713ade 100644
--- a/tests/network/remote/local.c
+++ b/tests/network/remote/local.c
@@ -197,6 +197,46 @@ void test_network_remote_local__push_to_bare_remote(void)
cl_fixture_cleanup("localbare.git");
}
+void test_network_remote_local__push_to_bare_remote_with_file_url(void)
+{
+ /* Should be able to push to a bare remote */
+ git_remote *localremote;
+ git_push *push;
+
+ /* Get some commits */
+ connect_to_local_repository(cl_fixture("testrepo.git"));
+ cl_git_pass(git_remote_add_fetch(remote, "master:master"));
+ cl_git_pass(git_remote_download(remote));
+ cl_git_pass(git_remote_update_tips(remote));
+ git_remote_disconnect(remote);
+
+ /* Set up an empty bare repo to push into */
+ {
+ git_repository *localbarerepo;
+ cl_git_pass(git_repository_init(&localbarerepo, "./localbare.git", 1));
+ git_repository_free(localbarerepo);
+ }
+
+ /* Create a file URL */
+ const char *url = cl_git_path_url("./localbare.git");
+
+ /* Connect to the bare repo */
+ cl_git_pass(git_remote_create_inmemory(&localremote, repo, NULL, url));
+ cl_git_pass(git_remote_connect(localremote, GIT_DIRECTION_PUSH));
+
+ /* Try to push */
+ cl_git_pass(git_push_new(&push, localremote));
+ cl_git_pass(git_push_add_refspec(push, "refs/heads/master:"));
+ cl_git_pass(git_push_finish(push));
+ cl_assert(git_push_unpack_ok(push));
+
+ /* Clean up */
+ git_push_free(push);
+ git_remote_free(localremote);
+ cl_fixture_cleanup("localbare.git");
+}
+
+
void test_network_remote_local__push_to_non_bare_remote(void)
{
/* Shouldn't be able to push to a non-bare remote */