diff --git a/include/git2/merge.h b/include/git2/merge.h index cef6f775bde..3f21fb4c85b 100644 --- a/include/git2/merge.h +++ b/include/git2/merge.h @@ -7,11 +7,11 @@ #ifndef INCLUDE_git_merge_h__ #define INCLUDE_git_merge_h__ -#include "git2/common.h" -#include "git2/types.h" -#include "git2/oid.h" -#include "git2/checkout.h" -#include "git2/index.h" +#include "common.h" +#include "types.h" +#include "oid.h" +#include "checkout.h" +#include "index.h" /** * @file git2/merge.h diff --git a/include/git2/transport.h b/include/git2/transport.h index 81bb3abe156..cbd14c75e4d 100644 --- a/include/git2/transport.h +++ b/include/git2/transport.h @@ -11,10 +11,6 @@ #include "net.h" #include "types.h" -#ifdef GIT_SSH -#include -#endif - /** * @file git2/transport.h * @brief Git transport interfaces and functions @@ -30,9 +26,9 @@ GIT_BEGIN_DECL typedef enum { /* git_cred_userpass_plaintext */ - GIT_CREDTYPE_USERPASS_PLAINTEXT = 1, - GIT_CREDTYPE_SSH_KEYFILE_PASSPHRASE = 2, - GIT_CREDTYPE_SSH_PUBLICKEY = 3, + GIT_CREDTYPE_USERPASS_PLAINTEXT = 1 << 0, + GIT_CREDTYPE_SSH_KEYFILE_PASSPHRASE = 1 << 1, + GIT_CREDTYPE_SSH_PUBLICKEY = 1 << 2, } git_credtype_t; /* The base structure for all credential types */ @@ -49,9 +45,6 @@ typedef struct git_cred_userpass_plaintext { char *password; } git_cred_userpass_plaintext; -#ifdef GIT_SSH -typedef LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*git_cred_sign_callback)); - /* A ssh key file and passphrase */ typedef struct git_cred_ssh_keyfile_passphrase { git_cred parent; @@ -68,7 +61,6 @@ typedef struct git_cred_ssh_publickey { void *sign_callback; void *sign_data; } git_cred_ssh_publickey; -#endif /** * Creates a new plain-text username and password credential object. @@ -84,7 +76,6 @@ GIT_EXTERN(int) git_cred_userpass_plaintext_new( const char *username, const char *password); -#ifdef GIT_SSH /** * Creates a new ssh key file and passphrase credential object. * The supplied credential parameter will be internally duplicated. @@ -116,9 +107,8 @@ GIT_EXTERN(int) git_cred_ssh_publickey_new( git_cred **out, const char *publickey, size_t publickey_len, - git_cred_sign_callback, + void* git_cred_sign_callback, void *sign_data); -#endif /** * Signature of a function which acquires a credential object. diff --git a/src/push.c b/src/push.c index 452d7178914..9a9783b0a5d 100644 --- a/src/push.c +++ b/src/push.c @@ -122,8 +122,10 @@ static int parse_refspec(git_push *push, push_spec **spec, const char *str) s = git__calloc(1, sizeof(*s)); GITERR_CHECK_ALLOC(s); + s->spec_type = SPECTYPE_NORMAL; + if (str[0] == '+') { - s->force = true; + s->spec_type = SPECTYPE_FORCED; str++; } @@ -258,8 +260,10 @@ static int revwalk(git_vector *commits, git_push *push) */ continue; - if (git_oid_equal(&spec->loid, &spec->roid)) + if (git_oid_equal(&spec->loid, &spec->roid)) { + spec->spec_type = SPECTYPE_UNCHANGED; continue; /* up-to-date */ + } if (git_odb_read_header(&size, &type, push->repo->_odb, &spec->loid) < 0) goto on_error; @@ -293,35 +297,41 @@ static int revwalk(git_vector *commits, git_push *push) } } git_object_free(target); - } else if (git_revwalk_push(rw, &spec->loid) < 0) - goto on_error; + } + + push_spec_t spec_type = spec->spec_type; - if (!spec->force) { + if (spec_type != SPECTYPE_FORCED) { 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"); - error = GIT_ENONFASTFORWARD; - goto on_error; - } - - error = git_merge_base(&base, push->repo, - &spec->loid, &spec->roid); - - if (error == GIT_ENOTFOUND || - (!error && !git_oid_equal(&base, &spec->roid))) { - giterr_set(GITERR_REFERENCE, - "Cannot push non-fastforwardable reference"); - error = GIT_ENONFASTFORWARD; - goto on_error; - } - - if (error < 0) - goto on_error; + if (!git_oid_iszero(&spec->roid)) { + if (!git_odb_exists(push->repo->_odb, &spec->roid)) { + giterr_set(GITERR_REFERENCE, "Cannot push missing reference"); + error = GIT_ENONFASTFORWARD; + goto on_error; + } + + error = git_merge_base(&base, push->repo, + &spec->loid, &spec->roid); + if (error == GIT_ENOTFOUND) { + giterr_set(GITERR_REFERENCE, + "Cannot push non-fastforwardable reference"); + error = GIT_ENONFASTFORWARD; + goto on_error; + } + + if ((!error && !git_oid_equal(&base, &spec->roid))) { + spec->spec_type = SPECTYPE_REJECTED; + spec_type = spec->spec_type; + } + + if (error < 0) + goto on_error; + } } + + if (spec_type != SPECTYPE_REJECTED && spec_type != SPECTYPE_UNCHANGED && git_revwalk_push(rw, &spec->loid) < 0) + goto on_error; } git_vector_foreach(&push->remote->refs, i, head) { @@ -540,6 +550,34 @@ static int calculate_work(git_push *push) return 0; } +static int filter_rejected_refs(git_push *push) +{ + int error = 0; + + git_vector filtered_specs; + if ((error = git_vector_init(&filtered_specs, 0, push_spec_rref_cmp)) < 0) { + return error; + } + + push_spec *spec; + push_spec_t spec_type; + unsigned int i; + git_vector_foreach(&push->specs, i, spec) { + spec_type = spec->spec_type; + if (spec_type == SPECTYPE_NORMAL || spec_type == SPECTYPE_FORCED) { + if((error = git_vector_insert(&filtered_specs, spec)) < 0) { + git_vector_free(&filtered_specs); + return error; + } + } + } + + git_vector_free(&push->specs); + push->specs = filtered_specs; + + return 0; +} + static int do_push(git_push *push) { int error; @@ -564,8 +602,9 @@ static int do_push(git_push *push) if ((error = calculate_work(push)) < 0 || (error = queue_objects(push)) < 0 || - (error = transport->push(transport, push)) < 0) - goto on_error; + (error = filter_rejected_refs(push)) < 0 || + (error = transport->push(transport, push)) < 0) + goto on_error; error = 0; diff --git a/src/push.h b/src/push.h index e982b838550..0371e125be8 100644 --- a/src/push.h +++ b/src/push.h @@ -9,6 +9,13 @@ #include "git2.h" +typedef enum { + SPECTYPE_NORMAL, + SPECTYPE_FORCED, + SPECTYPE_REJECTED, + SPECTYPE_UNCHANGED, +} push_spec_t; + typedef struct push_spec { char *lref; char *rref; @@ -16,7 +23,7 @@ typedef struct push_spec { git_oid loid; git_oid roid; - bool force; + push_spec_t spec_type; } push_spec; typedef struct push_status { diff --git a/src/stash.c b/src/stash.c index 1222634d5e5..93f3ad1aae2 100644 --- a/src/stash.c +++ b/src/stash.c @@ -186,12 +186,12 @@ static int update_index_cb( case GIT_DELTA_ADDED: case GIT_DELTA_MODIFIED: - if (data->include_changed) + if (data->include_changed && !S_ISGITLINK(delta->new_file.mode)) add_path = delta->new_file.path; break; case GIT_DELTA_DELETED: - if (!data->include_changed) + if (!data->include_changed || S_ISGITLINK(delta->new_file.mode)) break; if (git_index_find(NULL, data->index, delta->old_file.path) == 0) data->error = git_index_remove( diff --git a/src/transports/cred.c b/src/transports/cred.c index ba5de6e93f5..2b42045632e 100644 --- a/src/transports/cred.c +++ b/src/transports/cred.c @@ -133,7 +133,7 @@ int git_cred_ssh_publickey_new( git_cred **cred, const char *publickey, size_t publickey_len, - LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*sign_callback)), + void *sign_callback, void *sign_data) { git_cred_ssh_publickey *c; diff --git a/src/transports/ssh.c b/src/transports/ssh.c index a312c8d089a..d8d8c47ebb5 100644 --- a/src/transports/ssh.c +++ b/src/transports/ssh.c @@ -51,7 +51,7 @@ static int gen_proto(git_buf *request, const char *cmd, const char *url) url = url + strlen(prefix_ssh); repo = strchr(url, '/'); } else { - repo = strchr(url, ':'); + repo = strchr(url, ':') + 1; } if (!repo) { @@ -125,13 +125,17 @@ static int ssh_stream_write( if (!s->sent_command && send_command(s) < 0) return -1; - - int rc = libssh2_channel_write(s->channel, buffer, len); - if (rc < 0) { - return -1; + + size_t bytes_written = 0; + while (bytes_written < len) { + int rc = libssh2_channel_write(s->channel, buffer + bytes_written, len - bytes_written); + if (rc < 0) { + return -1; + } + bytes_written += rc; } - return rc; + return 0; } static void ssh_stream_free(git_smart_subtransport_stream *stream) @@ -349,7 +353,7 @@ static int _git_ssh_setup_conn( if (t->owner->cred_acquire_cb(&t->cred, t->owner->url, user, - GIT_CREDTYPE_USERPASS_PLAINTEXT | GIT_CREDTYPE_SSH_KEYFILE_PASSPHRASE, + GIT_CREDTYPE_USERPASS_PLAINTEXT | GIT_CREDTYPE_SSH_KEYFILE_PASSPHRASE | GIT_CREDTYPE_SSH_PUBLICKEY, t->owner->cred_acquire_payload) < 0) return -1; }