summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/branch.c6
-rw-r--r--src/checkout.c4
-rw-r--r--src/global.c6
-rw-r--r--src/indexer.c12
-rw-r--r--src/odb.c4
-rw-r--r--src/push.c70
-rw-r--r--src/push.h6
-rw-r--r--src/refspec.c6
-rw-r--r--src/remote.c66
-rw-r--r--src/transports/http.c1
-rw-r--r--src/transports/local.c4
-rw-r--r--src/transports/smart_protocol.c12
12 files changed, 127 insertions, 70 deletions
diff --git a/src/branch.c b/src/branch.c
index 01402a2e9..b4e4b0564 100644
--- a/src/branch.c
+++ b/src/branch.c
@@ -400,6 +400,12 @@ int git_branch_upstream_remote(git_buf *buf, git_repository *repo, const char *r
if ((error = retrieve_upstream_configuration(&str, cfg, refname, "branch.%s.remote")) < 0)
goto cleanup;
+ if (!*str) {
+ giterr_set(GITERR_REFERENCE, "branch '%s' does not have an upstream remote", refname);
+ error = GIT_ENOTFOUND;
+ goto cleanup;
+ }
+
error = git_buf_puts(buf, str);
cleanup:
diff --git a/src/checkout.c b/src/checkout.c
index 44e2f3b27..4e879e36f 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -1145,12 +1145,16 @@ static int checkout_conflict_append_remove(
checkout_data *data = payload;
const char *name;
+ assert(ancestor || ours || theirs);
+
if (ancestor)
name = git__strdup(ancestor->path);
else if (ours)
name = git__strdup(ours->path);
else if (theirs)
name = git__strdup(theirs->path);
+ else
+ abort();
GITERR_CHECK_ALLOC(name);
diff --git a/src/global.c b/src/global.c
index da903cb94..006202a2c 100644
--- a/src/global.c
+++ b/src/global.c
@@ -67,7 +67,13 @@ void openssl_locking_function(int mode, int n, const char *file, int line)
static void shutdown_ssl_locking(void)
{
+ int num_locks, i;
+
+ num_locks = CRYPTO_num_locks();
CRYPTO_set_locking_callback(NULL);
+
+ for (i = 0; i < num_locks; ++i)
+ git_mutex_free(openssl_locks);
git__free(openssl_locks);
}
#endif
diff --git a/src/indexer.c b/src/indexer.c
index 620e8186b..0e682dd6e 100644
--- a/src/indexer.c
+++ b/src/indexer.c
@@ -120,6 +120,7 @@ int git_indexer_new(
idx->progress_cb = progress_cb;
idx->progress_payload = progress_payload;
idx->mode = mode ? mode : GIT_PACK_FILE_MODE;
+ git_hash_ctx_init(&idx->hash_ctx);
git_hash_ctx_init(&idx->trailer);
error = git_buf_joinpath(&path, prefix, suff);
@@ -265,7 +266,6 @@ static int store_object(git_indexer *idx)
struct entry *entry;
git_off_t entry_size;
struct git_pack_entry *pentry;
- git_hash_ctx *ctx = &idx->hash_ctx;
git_off_t entry_start = idx->entry_start;
entry = git__calloc(1, sizeof(*entry));
@@ -274,7 +274,7 @@ static int store_object(git_indexer *idx)
pentry = git__calloc(1, sizeof(struct git_pack_entry));
GITERR_CHECK_ALLOC(pentry);
- git_hash_final(&oid, ctx);
+ git_hash_final(&oid, &idx->hash_ctx);
entry_size = idx->off - entry_start;
if (entry_start > UINT31_MAX) {
entry->offset = UINT32_MAX;
@@ -557,7 +557,7 @@ int git_indexer_append(git_indexer *idx, const void *data, size_t size, git_tran
git_mwindow_close(&w);
idx->entry_start = entry_start;
- git_hash_ctx_init(&idx->hash_ctx);
+ git_hash_init(&idx->hash_ctx);
if (type == GIT_OBJ_REF_DELTA || type == GIT_OBJ_OFS_DELTA) {
error = advance_delta_offset(idx, type);
@@ -843,12 +843,10 @@ static int update_header_and_rehash(git_indexer *idx, git_transfer_progress *sta
git_mwindow *w = NULL;
git_mwindow_file *mwf;
unsigned int left;
- git_hash_ctx *ctx;
mwf = &idx->pack->mwf;
- ctx = &idx->trailer;
- git_hash_ctx_init(ctx);
+ git_hash_init(&idx->trailer);
/* Update the header to include the numer of local objects we injected */
@@ -1061,5 +1059,7 @@ void git_indexer_free(git_indexer *idx)
git_mutex_unlock(&git__mwindow_mutex);
}
+ git_hash_ctx_cleanup(&idx->trailer);
+ git_hash_ctx_cleanup(&idx->hash_ctx);
git__free(idx);
}
diff --git a/src/odb.c b/src/odb.c
index 2c19c0311..5961b35a7 100644
--- a/src/odb.c
+++ b/src/odb.c
@@ -762,12 +762,12 @@ static int hardcoded_objects(git_rawobj *raw, const git_oid *id)
if (!git_oid_cmp(id, &empty_blob)) {
raw->type = GIT_OBJ_BLOB;
raw->len = 0;
- raw->data = NULL;
+ raw->data = git__calloc(1, sizeof(uint8_t));
return 0;
} else if (!git_oid_cmp(id, &empty_tree)) {
raw->type = GIT_OBJ_TREE;
raw->len = 0;
- raw->data = NULL;
+ raw->data = git__calloc(1, sizeof(uint8_t));
return 0;
} else {
return GIT_ENOTFOUND;
diff --git a/src/push.c b/src/push.c
index be5ec1c0e..6671da465 100644
--- a/src/push.c
+++ b/src/push.c
@@ -19,7 +19,7 @@ static int push_spec_rref_cmp(const void *a, const void *b)
{
const push_spec *push_spec_a = a, *push_spec_b = b;
- return strcmp(push_spec_a->rref, push_spec_b->rref);
+ return strcmp(push_spec_a->refspec.dst, push_spec_b->refspec.dst);
}
static int push_status_ref_cmp(const void *a, const void *b)
@@ -94,12 +94,7 @@ static void free_refspec(push_spec *spec)
if (spec == NULL)
return;
- if (spec->lref)
- git__free(spec->lref);
-
- if (spec->rref)
- git__free(spec->rref);
-
+ git_refspec__free(&spec->refspec);
git__free(spec);
}
@@ -134,47 +129,25 @@ static int check_lref(git_push *push, char *ref)
static int parse_refspec(git_push *push, push_spec **spec, const char *str)
{
push_spec *s;
- char *delim;
*spec = NULL;
s = git__calloc(1, sizeof(*s));
GITERR_CHECK_ALLOC(s);
- if (str[0] == '+') {
- s->force = true;
- str++;
+ if (git_refspec__parse(&s->refspec, str, false) < 0) {
+ giterr_set(GITERR_INVALID, "invalid refspec %s", str);
+ goto on_error;
}
- delim = strchr(str, ':');
- if (delim == NULL) {
- s->lref = git__strdup(str);
- if (!s->lref || check_lref(push, s->lref) < 0)
- goto on_error;
- } else {
- if (delim - str) {
- s->lref = git__strndup(str, delim - str);
- if (!s->lref || check_lref(push, s->lref) < 0)
- goto on_error;
- }
-
- if (strlen(delim + 1)) {
- s->rref = git__strdup(delim + 1);
- if (!s->rref || check_rref(s->rref) < 0)
- goto on_error;
- }
+ if (s->refspec.src && s->refspec.src[0] != '\0' &&
+ check_lref(push, s->refspec.src) < 0) {
+ goto on_error;
}
- if (!s->lref && !s->rref)
+ if (check_rref(s->refspec.dst) < 0)
goto on_error;
- /* If rref is ommitted, use the same ref name as lref */
- if (!s->rref) {
- s->rref = git__strdup(s->lref);
- if (!s->rref || check_rref(s->rref) < 0)
- goto on_error;
- }
-
*spec = s;
return 0;
@@ -220,7 +193,7 @@ int git_push_update_tips(
/* Find matching push ref spec */
git_vector_foreach(&push->specs, j, push_spec) {
- if (!strcmp(push_spec->rref, status->ref))
+ if (!strcmp(push_spec->refspec.dst, status->ref))
break;
}
@@ -353,14 +326,15 @@ static int revwalk(git_vector *commits, git_push *push)
} else if (git_revwalk_push(rw, &spec->loid) < 0)
goto on_error;
- if (!spec->force) {
+ if (!spec->refspec.force) {
git_oid base;
if (git_oid_iszero(&spec->roid))
continue;
if (!git_odb_exists(push->repo->_odb, &spec->roid)) {
- giterr_set(GITERR_REFERENCE, "Cannot push missing reference");
+ giterr_set(GITERR_REFERENCE,
+ "Cannot push because a reference that you are trying to update on the remote contains commits that are not present locally.");
error = GIT_ENONFASTFORWARD;
goto on_error;
}
@@ -571,22 +545,20 @@ static int calculate_work(git_push *push)
/* Update local and remote oids*/
git_vector_foreach(&push->specs, i, spec) {
- if (spec->lref) {
+ if (spec->refspec.src && spec->refspec.src[0]!= '\0') {
/* This is a create or update. Local ref must exist. */
if (git_reference_name_to_id(
- &spec->loid, push->repo, spec->lref) < 0) {
- giterr_set(GITERR_REFERENCE, "No such reference '%s'", spec->lref);
+ &spec->loid, push->repo, spec->refspec.src) < 0) {
+ giterr_set(GITERR_REFERENCE, "No such reference '%s'", spec->refspec.src);
return -1;
}
}
- if (spec->rref) {
- /* Remote ref may or may not (e.g. during create) already exist. */
- git_vector_foreach(&push->remote->refs, j, head) {
- if (!strcmp(spec->rref, head->name)) {
- git_oid_cpy(&spec->roid, &head->oid);
- break;
- }
+ /* Remote ref may or may not (e.g. during create) already exist. */
+ git_vector_foreach(&push->remote->refs, j, head) {
+ if (!strcmp(spec->refspec.dst, head->name)) {
+ git_oid_cpy(&spec->roid, &head->oid);
+ break;
}
}
}
diff --git a/src/push.h b/src/push.h
index 6c8bf7229..68fa868dd 100644
--- a/src/push.h
+++ b/src/push.h
@@ -8,15 +8,13 @@
#define INCLUDE_push_h__
#include "git2.h"
+#include "refspec.h"
typedef struct push_spec {
- char *lref;
- char *rref;
+ struct git_refspec refspec;
git_oid loid;
git_oid roid;
-
- bool force;
} push_spec;
typedef struct push_status {
diff --git a/src/refspec.c b/src/refspec.c
index 9f0df35a7..a56c44cc0 100644
--- a/src/refspec.c
+++ b/src/refspec.c
@@ -119,6 +119,12 @@ int git_refspec__parse(git_refspec *refspec, const char *input, bool is_fetch)
if (!git_reference__is_valid_name(refspec->dst, flags))
goto invalid;
}
+
+ /* if the RHS is empty, then it's a copy of the LHS */
+ if (!refspec->dst) {
+ refspec->dst = git__strdup(refspec->src);
+ GITERR_CHECK_ALLOC(refspec->dst);
+ }
}
refspec->string = git__strdup(input);
diff --git a/src/remote.c b/src/remote.c
index cc9f85cd1..b1a84075e 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -163,6 +163,10 @@ static int create_internal(git_remote **out, git_repository *repo, const char *n
if (fetch != NULL) {
if (add_refspec(remote, fetch, true) < 0)
goto on_error;
+
+ /* Move the data over to where the matching functions can find them */
+ if (dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs) < 0)
+ goto on_error;
}
if (!name)
@@ -702,7 +706,7 @@ int git_remote_ls(const git_remote_head ***out, size_t *size, git_remote *remote
assert(remote);
if (!remote->transport) {
- giterr_set(GITERR_NET, "No transport bound to this remote");
+ giterr_set(GITERR_NET, "this remote has never connected");
return -1;
}
@@ -2111,3 +2115,63 @@ int git_remote_default_branch(git_buf *out, git_remote *remote)
return git_buf_puts(out, guess->name);
}
+
+int git_remote_push(git_remote *remote, git_strarray *refspecs, const git_push_options *opts,
+ const git_signature *signature, const char *reflog_message)
+{
+ int error;
+ size_t i;
+ git_push *push = NULL;
+ git_remote_callbacks *cbs;
+ git_refspec *spec;
+
+ assert(remote && refspecs);
+
+ if ((error = git_remote_connect(remote, GIT_DIRECTION_PUSH)) < 0)
+ return error;
+
+ if ((error = git_push_new(&push, remote)) < 0)
+ goto cleanup;
+
+ if (opts && (error = git_push_set_options(push, opts)) < 0)
+ goto cleanup;
+
+ if (refspecs && refspecs->count > 0) {
+ for (i = 0; i < refspecs->count; i++) {
+ if ((error = git_push_add_refspec(push, refspecs->strings[i])) < 0)
+ goto cleanup;
+ }
+ } else {
+ git_vector_foreach(&remote->refspecs, i, spec) {
+ if (!spec->push)
+ continue;
+ if ((error = git_push_add_refspec(push, spec->string)) < 0)
+ goto cleanup;
+ }
+ }
+
+ cbs = &remote->callbacks;
+ if ((error = git_push_set_callbacks(push,
+ cbs->pack_progress, cbs->payload,
+ cbs->push_transfer_progress, cbs->payload)) < 0)
+ goto cleanup;
+
+ if ((error = git_push_finish(push)) < 0)
+ goto cleanup;
+
+ if (!git_push_unpack_ok(push)) {
+ error = -1;
+ giterr_set(GITERR_NET, "error in the remote while trying to unpack");
+ goto cleanup;
+ }
+
+ if ((error = git_push_status_foreach(push, cbs->push_update_reference, cbs->payload)) < 0)
+ goto cleanup;
+
+ error = git_push_update_tips(push, signature, reflog_message);
+
+cleanup:
+ git_remote_disconnect(remote);
+ git_push_free(push);
+ return error;
+}
diff --git a/src/transports/http.c b/src/transports/http.c
index 4070b683a..234ee229f 100644
--- a/src/transports/http.c
+++ b/src/transports/http.c
@@ -1009,6 +1009,7 @@ static int http_close(git_smart_subtransport *subtransport)
git_vector_clear(&t->auth_contexts);
gitno_connection_data_free_ptrs(&t->connection_data);
+ memset(&t->connection_data, 0x0, sizeof(gitno_connection_data));
return 0;
}
diff --git a/src/transports/local.c b/src/transports/local.c
index f859f0b70..05302a13f 100644
--- a/src/transports/local.c
+++ b/src/transports/local.c
@@ -405,7 +405,7 @@ static int local_push(
git_vector_foreach(&push->specs, j, spec) {
push_status *status;
const git_error *last;
- char *ref = spec->rref ? spec->rref : spec->lref;
+ char *ref = spec->refspec.dst;
status = git__calloc(sizeof(push_status), 1);
if (!status)
@@ -417,7 +417,7 @@ static int local_push(
goto on_error;
}
- error = local_push_update_remote_ref(remote_repo, spec->lref, spec->rref,
+ error = local_push_update_remote_ref(remote_repo, spec->refspec.src, spec->refspec.dst,
&spec->loid, &spec->roid);
switch (error) {
diff --git a/src/transports/smart_protocol.c b/src/transports/smart_protocol.c
index 7c20382dc..e110da07e 100644
--- a/src/transports/smart_protocol.c
+++ b/src/transports/smart_protocol.c
@@ -645,7 +645,7 @@ static int gen_pktline(git_buf *buf, git_push *push)
old_id[GIT_OID_HEXSZ] = '\0'; new_id[GIT_OID_HEXSZ] = '\0';
git_vector_foreach(&push->specs, i, spec) {
- len = 2*GIT_OID_HEXSZ + 7 + strlen(spec->rref);
+ len = 2*GIT_OID_HEXSZ + 7 + strlen(spec->refspec.dst);
if (i == 0) {
++len; /* '\0' */
@@ -657,7 +657,7 @@ static int gen_pktline(git_buf *buf, git_push *push)
git_oid_fmt(old_id, &spec->roid);
git_oid_fmt(new_id, &spec->loid);
- git_buf_printf(buf, "%04"PRIxZ"%s %s %s", len, old_id, new_id, spec->rref);
+ git_buf_printf(buf, "%04"PRIxZ"%s %s %s", len, old_id, new_id, spec->refspec.dst);
if (i == 0) {
git_buf_putc(buf, '\0');
@@ -816,7 +816,7 @@ static int add_ref_from_push_spec(git_vector *refs, push_spec *push_spec)
added->type = GIT_PKT_REF;
git_oid_cpy(&added->head.oid, &push_spec->loid);
- added->head.name = git__strdup(push_spec->rref);
+ added->head.name = git__strdup(push_spec->refspec.dst);
if (!added->head.name ||
git_vector_insert(refs, added) < 0) {
@@ -855,7 +855,7 @@ static int update_refs_from_report(
/* For each push spec we sent to the server, we should have
* gotten back a status packet in the push report which matches */
- if (strcmp(push_spec->rref, push_status->ref)) {
+ if (strcmp(push_spec->refspec.dst, push_status->ref)) {
giterr_set(GITERR_NET, "report-status: protocol error");
return -1;
}
@@ -872,7 +872,7 @@ static int update_refs_from_report(
push_status = git_vector_get(push_report, i);
ref = git_vector_get(refs, j);
- cmp = strcmp(push_spec->rref, ref->head.name);
+ cmp = strcmp(push_spec->refspec.dst, ref->head.name);
/* Iterate appropriately */
if (cmp <= 0) i++;
@@ -985,7 +985,7 @@ int git_smart__push(git_transport *transport, git_push *push)
* cases except when we only send delete commands
*/
git_vector_foreach(&push->specs, i, spec) {
- if (spec->lref) {
+ if (spec->refspec.src && spec->refspec.src[0] != '\0') {
need_pack = 1;
break;
}