post-checkout hook, tests, and docs
[gitweb.git] / http-push.c
index 57cefdea530171c71c72229a85aa0212dedb2c5a..7c3720f602bb8f50ed54a4f7e7a85c7e08d1c07b 100644 (file)
@@ -6,8 +6,10 @@
 #include "blob.h"
 #include "http.h"
 #include "refs.h"
+#include "diff.h"
 #include "revision.h"
 #include "exec_cmd.h"
+#include "remote.h"
 
 #include <expat.h>
 
@@ -59,28 +61,28 @@ enum XML_Status {
 #define LOCK_TIME 600
 #define LOCK_REFRESH 30
 
-/* bits #0-6 in revision.h */
+/* bits #0-15 in revision.h */
 
-#define LOCAL    (1u << 7)
-#define REMOTE   (1u << 8)
-#define FETCHING (1u << 9)
-#define PUSHING  (1u << 10)
+#define LOCAL    (1u<<16)
+#define REMOTE   (1u<<17)
+#define FETCHING (1u<<18)
+#define PUSHING  (1u<<19)
 
 /* We allow "recursive" symbolic refs. Only within reason, though */
 #define MAXDEPTH 5
 
-static int pushing = 0;
-static int aborted = 0;
+static int pushing;
+static int aborted;
 static signed char remote_dir_exists[256];
 
 static struct curl_slist *no_pragma_header;
 static struct curl_slist *default_headers;
 
-static int push_verbosely = 0;
-static int push_all = 0;
-static int force_all = 0;
+static int push_verbosely;
+static int push_all;
+static int force_all;
 
-static struct object_list *objects = NULL;
+static struct object_list *objects;
 
 struct repo
 {
@@ -93,7 +95,7 @@ struct repo
        struct remote_lock *locks;
 };
 
-static struct repo *remote = NULL;
+static struct repo *remote;
 
 enum transfer_state {
        NEED_FETCH,
@@ -133,7 +135,7 @@ struct transfer_request
        struct transfer_request *next;
 };
 
-static struct transfer_request *request_queue_head = NULL;
+static struct transfer_request *request_queue_head;
 
 struct xml_ctx
 {
@@ -185,6 +187,7 @@ static void process_response(void *callback_data)
        finish_request(request);
 }
 
+#ifdef USE_CURL_MULTI
 static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb,
                               void *data)
 {
@@ -193,8 +196,8 @@ static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb,
        int posn = 0;
        struct transfer_request *request = (struct transfer_request *)data;
        do {
-               ssize_t retval = write(request->local_fileno,
-                                      ptr + posn, size - posn);
+               ssize_t retval = xwrite(request->local_fileno,
+                                      (char *) ptr + posn, size - posn);
                if (retval < 0)
                        return posn;
                posn += retval;
@@ -286,7 +289,7 @@ static void start_fetch_loose(struct transfer_request *request)
        prevlocal = open(prevfile, O_RDONLY);
        if (prevlocal != -1) {
                do {
-                       prev_read = read(prevlocal, prev_buf, PREV_BUF_SIZE);
+                       prev_read = xread(prevlocal, prev_buf, PREV_BUF_SIZE);
                        if (prev_read>0) {
                                if (fwrite_sha1_file(prev_buf,
                                                     1,
@@ -310,7 +313,7 @@ static void start_fetch_loose(struct transfer_request *request)
                SHA1_Init(&request->c);
                if (prev_posn>0) {
                        prev_posn = 0;
-                       lseek(request->local_fileno, SEEK_SET, 0);
+                       lseek(request->local_fileno, 0, SEEK_SET);
                        ftruncate(request->local_fileno, 0);
                }
        }
@@ -348,6 +351,41 @@ static void start_fetch_loose(struct transfer_request *request)
        }
 }
 
+static void start_mkcol(struct transfer_request *request)
+{
+       char *hex = sha1_to_hex(request->obj->sha1);
+       struct active_request_slot *slot;
+       char *posn;
+
+       request->url = xmalloc(strlen(remote->url) + 13);
+       strcpy(request->url, remote->url);
+       posn = request->url + strlen(remote->url);
+       strcpy(posn, "objects/");
+       posn += 8;
+       memcpy(posn, hex, 2);
+       posn += 2;
+       strcpy(posn, "/");
+
+       slot = get_active_slot();
+       slot->callback_func = process_response;
+       slot->callback_data = request;
+       curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1); /* undo PUT setup */
+       curl_easy_setopt(slot->curl, CURLOPT_URL, request->url);
+       curl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, request->errorstr);
+       curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_MKCOL);
+       curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
+
+       if (start_active_slot(slot)) {
+               request->slot = slot;
+               request->state = RUN_MKCOL;
+       } else {
+               request->state = ABORTED;
+               free(request->url);
+               request->url = NULL;
+       }
+}
+#endif
+
 static void start_fetch_packed(struct transfer_request *request)
 {
        char *url;
@@ -437,46 +475,12 @@ static void start_fetch_packed(struct transfer_request *request)
        }
 }
 
-static void start_mkcol(struct transfer_request *request)
-{
-       char *hex = sha1_to_hex(request->obj->sha1);
-       struct active_request_slot *slot;
-       char *posn;
-
-       request->url = xmalloc(strlen(remote->url) + 13);
-       strcpy(request->url, remote->url);
-       posn = request->url + strlen(remote->url);
-       strcpy(posn, "objects/");
-       posn += 8;
-       memcpy(posn, hex, 2);
-       posn += 2;
-       strcpy(posn, "/");
-
-       slot = get_active_slot();
-       slot->callback_func = process_response;
-       slot->callback_data = request;
-       curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1); /* undo PUT setup */
-       curl_easy_setopt(slot->curl, CURLOPT_URL, request->url);
-       curl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, request->errorstr);
-       curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_MKCOL);
-       curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
-
-       if (start_active_slot(slot)) {
-               request->slot = slot;
-               request->state = RUN_MKCOL;
-       } else {
-               request->state = ABORTED;
-               free(request->url);
-               request->url = NULL;
-       }
-}
-
 static void start_put(struct transfer_request *request)
 {
        char *hex = sha1_to_hex(request->obj->sha1);
        struct active_request_slot *slot;
        char *posn;
-       char type[20];
+       enum object_type type;
        char hdr[50];
        void *unpacked;
        unsigned long len;
@@ -484,12 +488,12 @@ static void start_put(struct transfer_request *request)
        ssize_t size;
        z_stream stream;
 
-       unpacked = read_sha1_file(request->obj->sha1, type, &len);
-       hdrlen = sprintf(hdr, "%s %lu", type, len) + 1;
+       unpacked = read_sha1_file(request->obj->sha1, &type, &len);
+       hdrlen = sprintf(hdr, "%s %lu", typename(type), len) + 1;
 
        /* Set it up */
        memset(&stream, 0, sizeof(stream));
-       deflateInit(&stream, Z_BEST_COMPRESSION);
+       deflateInit(&stream, zlib_compression_level);
        size = deflateBound(&stream, len + hdrlen);
        request->buffer.buffer = xmalloc(size);
 
@@ -514,7 +518,7 @@ static void start_put(struct transfer_request *request)
        request->buffer.size = stream.total_out;
        request->buffer.posn = 0;
 
-       request->url = xmalloc(strlen(remote->url) + 
+       request->url = xmalloc(strlen(remote->url) +
                               strlen(request->lock->token) + 51);
        strcpy(request->url, remote->url);
        posn = request->url + strlen(remote->url);
@@ -527,7 +531,7 @@ static void start_put(struct transfer_request *request)
        request->dest = xmalloc(strlen(request->url) + 14);
        sprintf(request->dest, "Destination: %s", request->url);
        posn += 38;
-       *(posn++) = '.';
+       *(posn++) = '_';
        strcpy(posn, request->lock->token);
 
        slot = get_active_slot();
@@ -742,7 +746,7 @@ static void finish_request(struct transfer_request *request)
                        SHA1_Final(request->real_sha1, &request->c);
                        if (request->zret != Z_STREAM_END) {
                                unlink(request->tmpfile);
-                       } else if (memcmp(request->obj->sha1, request->real_sha1, 20)) {
+                       } else if (hashcmp(request->obj->sha1, request->real_sha1)) {
                                unlink(request->tmpfile);
                        } else {
                                request->rename =
@@ -767,11 +771,14 @@ static void finish_request(struct transfer_request *request)
                                request->url, curl_errorstr);
                        remote->can_update_info_refs = 0;
                } else {
+                       off_t pack_size = ftell(request->local_stream);
+
                        fclose(request->local_stream);
                        request->local_stream = NULL;
                        if (!move_temp_to_file(request->tmpfile,
                                               request->filename)) {
                                target = (struct packed_git *)request->userData;
+                               target->pack_size = pack_size;
                                lst = &remote->packs;
                                while (*lst != target)
                                        lst = &((*lst)->next);
@@ -787,6 +794,7 @@ static void finish_request(struct transfer_request *request)
        }
 }
 
+#ifdef USE_CURL_MULTI
 void fill_active_slots(void)
 {
        struct transfer_request *request = request_queue_head;
@@ -820,6 +828,7 @@ void fill_active_slots(void)
                slot = slot->next;
        }
 }
+#endif
 
 static void get_remote_object_list(unsigned char parent);
 
@@ -850,8 +859,10 @@ static void add_fetch_request(struct object *obj)
        request->next = request_queue_head;
        request_queue_head = request;
 
+#ifdef USE_CURL_MULTI
        fill_active_slots();
        step_active_slots();
+#endif
 }
 
 static int add_send_request(struct object *obj, struct remote_lock *lock)
@@ -888,8 +899,10 @@ static int add_send_request(struct object *obj, struct remote_lock *lock)
        request->next = request_queue_head;
        request_queue_head = request;
 
+#ifdef USE_CURL_MULTI
        fill_active_slots();
        step_active_slots();
+#endif
 
        return 1;
 }
@@ -1048,8 +1061,8 @@ static int fetch_indices(void)
                case 'P':
                        i++;
                        if (i + 52 < buffer.posn &&
-                           !strncmp(data + i, " pack-", 6) &&
-                           !strncmp(data + i + 46, ".pack\n", 6)) {
+                           !prefixcmp(data + i, " pack-") &&
+                           !prefixcmp(data + i + 46, ".pack\n")) {
                                get_sha1_hex(data + i + 6, sha1);
                                setup_index(sha1);
                                i += 51;
@@ -1068,13 +1081,14 @@ static int fetch_indices(void)
 
 static inline int needs_quote(int ch)
 {
-       switch (ch) {
-       case '/': case '-': case '.':
-       case 'A'...'Z': case 'a'...'z': case '0'...'9':
+       if (((ch >= 'A') && (ch <= 'Z'))
+                       || ((ch >= 'a') && (ch <= 'z'))
+                       || ((ch >= '0') && (ch <= '9'))
+                       || (ch == '/')
+                       || (ch == '-')
+                       || (ch == '.'))
                return 0;
-       default:
-               return 1;
-       }
+       return 1;
 }
 
 static inline int hex(int v)
@@ -1162,7 +1176,7 @@ static void one_remote_object(const char *hex)
 
        obj->flags |= REMOTE;
        if (!object_list_contains(objects, obj))
-               add_object(obj, &objects, NULL, "");
+               object_list_insert(obj, &objects);
 }
 
 static void handle_lockprop_ctx(struct xml_ctx *ctx, int tag_closed)
@@ -1193,11 +1207,11 @@ static void handle_new_lock_ctx(struct xml_ctx *ctx, int tag_closed)
                        lock->owner = xmalloc(strlen(ctx->cdata) + 1);
                        strcpy(lock->owner, ctx->cdata);
                } else if (!strcmp(ctx->name, DAV_ACTIVELOCK_TIMEOUT)) {
-                       if (!strncmp(ctx->cdata, "Second-", 7))
+                       if (!prefixcmp(ctx->cdata, "Second-"))
                                lock->timeout =
                                        strtol(ctx->cdata + 7, NULL, 10);
                } else if (!strcmp(ctx->name, DAV_ACTIVELOCK_TOKEN)) {
-                       if (!strncmp(ctx->cdata, "opaquelocktoken:", 16)) {
+                       if (!prefixcmp(ctx->cdata, "opaquelocktoken:")) {
                                lock->token = xmalloc(strlen(ctx->cdata) - 15);
                                strcpy(lock->token, ctx->cdata + 16);
                        }
@@ -1211,7 +1225,7 @@ static void
 xml_start_tag(void *userData, const char *name, const char **atts)
 {
        struct xml_ctx *ctx = (struct xml_ctx *)userData;
-       const char *c = index(name, ':');
+       const char *c = strchr(name, ':');
        int new_len;
 
        if (c == NULL)
@@ -1228,10 +1242,8 @@ xml_start_tag(void *userData, const char *name, const char **atts)
        strcat(ctx->name, ".");
        strcat(ctx->name, c);
 
-       if (ctx->cdata) {
-               free(ctx->cdata);
-               ctx->cdata = NULL;
-       }
+       free(ctx->cdata);
+       ctx->cdata = NULL;
 
        ctx->userFunc(ctx, 0);
 }
@@ -1240,7 +1252,7 @@ static void
 xml_end_tag(void *userData, const char *name)
 {
        struct xml_ctx *ctx = (struct xml_ctx *)userData;
-       const char *c = index(name, ':');
+       const char *c = strchr(name, ':');
        char *ep;
 
        ctx->userFunc(ctx, 1);
@@ -1258,13 +1270,14 @@ static void
 xml_cdata(void *userData, const XML_Char *s, int len)
 {
        struct xml_ctx *ctx = (struct xml_ctx *)userData;
-       if (ctx->cdata)
-               free(ctx->cdata);
-       ctx->cdata = xcalloc(len+1, 1);
-       strncpy(ctx->cdata, s, len);
+       free(ctx->cdata);
+       ctx->cdata = xmalloc(len + 1);
+       /* NB: 's' is not null-terminated, can not use strlcpy here */
+       memcpy(ctx->cdata, s, len);
+       ctx->cdata[len] = '\0';
 }
 
-static struct remote_lock *lock_remote(char *path, long timeout)
+static struct remote_lock *lock_remote(const char *path, long timeout)
 {
        struct active_request_slot *slot;
        struct slot_results results;
@@ -1285,7 +1298,7 @@ static struct remote_lock *lock_remote(char *path, long timeout)
        sprintf(url, "%s%s", remote->url, path);
 
        /* Make sure leading directories exist for the remote ref */
-       ep = strchr(url + strlen(remote->url) + 11, '/');
+       ep = strchr(url + strlen(remote->url) + 1, '/');
        while (ep) {
                *ep = 0;
                slot = get_active_slot();
@@ -1463,7 +1476,8 @@ static void process_ls_object(struct remote_ls_ctx *ls)
                return;
        path += 8;
        obj_hex = xmalloc(strlen(path));
-       strncpy(obj_hex, path, 2);
+       /* NB: path is not null-terminated, can not use strlcpy here */
+       memcpy(obj_hex, path, 2);
        strcpy(obj_hex + 2, path + 3);
        one_remote_object(obj_hex);
        free(obj_hex);
@@ -1508,9 +1522,7 @@ static void handle_remote_ls_ctx(struct xml_ctx *ctx, int tag_closed)
                        ls->dentry_flags |= IS_DIR;
                }
        } else if (!strcmp(ctx->name, DAV_PROPFIND_RESP)) {
-               if (ls->dentry_name) {
-                       free(ls->dentry_name);
-               }
+               free(ls->dentry_name);
                ls->dentry_name = NULL;
                ls->dentry_flags = 0;
        }
@@ -1534,7 +1546,7 @@ static void remote_ls(const char *path, int flags,
        struct remote_ls_ctx ls;
 
        ls.flags = flags;
-       ls.path = strdup(path);
+       ls.path = xstrdup(path);
        ls.dentry_name = NULL;
        ls.dentry_flags = 0;
        ls.userData = userData;
@@ -1690,6 +1702,15 @@ static int locking_available(void)
        return lock_flags;
 }
 
+static struct object_list **add_one_object(struct object *obj, struct object_list **p)
+{
+       struct object_list *entry = xmalloc(sizeof(struct object_list));
+       entry->item = obj;
+       entry->next = *p;
+       *p = entry;
+       return &entry->next;
+}
+
 static struct object_list **process_blob(struct blob *blob,
                                         struct object_list **p,
                                         struct name_path *path,
@@ -1703,7 +1724,7 @@ static struct object_list **process_blob(struct blob *blob,
                return p;
 
        obj->flags |= SEEN;
-       return add_object(obj, p, path, name);
+       return add_one_object(obj, p);
 }
 
 static struct object_list **process_tree(struct tree *tree,
@@ -1712,7 +1733,8 @@ static struct object_list **process_tree(struct tree *tree,
                                         const char *name)
 {
        struct object *obj = &tree->object;
-       struct tree_entry_list *entry;
+       struct tree_desc desc;
+       struct name_entry entry;
        struct name_path me;
 
        obj->flags |= LOCAL;
@@ -1723,28 +1745,30 @@ static struct object_list **process_tree(struct tree *tree,
                die("bad tree object %s", sha1_to_hex(obj->sha1));
 
        obj->flags |= SEEN;
-       p = add_object(obj, p, NULL, name);
+       name = xstrdup(name);
+       p = add_one_object(obj, p);
        me.up = path;
        me.elem = name;
        me.elem_len = strlen(name);
-       entry = tree->entries;
-       tree->entries = NULL;
-       while (entry) {
-               struct tree_entry_list *next = entry->next;
-               if (entry->directory)
-                       p = process_tree(entry->item.tree, p, &me, entry->name);
+
+       init_tree_desc(&desc, tree->buffer, tree->size);
+
+       while (tree_entry(&desc, &entry)) {
+               if (S_ISDIR(entry.mode))
+                       p = process_tree(lookup_tree(entry.sha1), p, &me, name);
                else
-                       p = process_blob(entry->item.blob, p, &me, entry->name);
-               free(entry);
-               entry = next;
+                       p = process_blob(lookup_blob(entry.sha1), p, &me, name);
        }
+       free(tree->buffer);
+       tree->buffer = NULL;
        return p;
 }
 
 static int get_delta(struct rev_info *revs, struct remote_lock *lock)
 {
+       int i;
        struct commit *commit;
-       struct object_list **p = &objects, *pending;
+       struct object_list **p = &objects;
        int count = 0;
 
        while ((commit = get_revision(revs)) != NULL) {
@@ -1754,22 +1778,23 @@ static int get_delta(struct rev_info *revs, struct remote_lock *lock)
                        count += add_send_request(&commit->object, lock);
        }
 
-       for (pending = revs->pending_objects; pending; pending = pending->next) {
-               struct object *obj = pending->item;
-               const char *name = pending->name;
+       for (i = 0; i < revs->pending.nr; i++) {
+               struct object_array_entry *entry = revs->pending.objects + i;
+               struct object *obj = entry->item;
+               const char *name = entry->name;
 
                if (obj->flags & (UNINTERESTING | SEEN))
                        continue;
-               if (obj->type == tag_type) {
+               if (obj->type == OBJ_TAG) {
                        obj->flags |= SEEN;
-                       p = add_object(obj, p, NULL, name);
+                       p = add_one_object(obj, p);
                        continue;
                }
-               if (obj->type == tree_type) {
+               if (obj->type == OBJ_TREE) {
                        p = process_tree((struct tree *)obj, p, NULL, name);
                        continue;
                }
-               if (obj->type == blob_type) {
+               if (obj->type == OBJ_BLOB) {
                        p = process_blob((struct blob *)obj, p, NULL, name);
                        continue;
                }
@@ -1845,12 +1870,12 @@ static int update_remote(unsigned char *sha1, struct remote_lock *lock)
 static struct ref *local_refs, **local_tail;
 static struct ref *remote_refs, **remote_tail;
 
-static int one_local_ref(const char *refname, const unsigned char *sha1)
+static int one_local_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
 {
        struct ref *ref;
        int len = strlen(refname) + 1;
        ref = xcalloc(1, sizeof(*ref) + len);
-       memcpy(ref->new_sha1, sha1, 20);
+       hashcpy(ref->new_sha1, sha1);
        memcpy(ref->name, refname, len);
        *local_tail = ref;
        local_tail = &ref->next;
@@ -1885,7 +1910,7 @@ static void one_remote_ref(char *refname)
        }
 
        ref = xcalloc(1, sizeof(*ref) + len);
-       memcpy(ref->old_sha1, remote_sha1, 20);
+       hashcpy(ref->old_sha1, remote_sha1);
        memcpy(ref->name, refname, len);
        *remote_tail = ref;
        remote_tail = &ref->next;
@@ -1894,7 +1919,7 @@ static void one_remote_ref(char *refname)
 static void get_local_heads(void)
 {
        local_tail = &local_refs;
-       for_each_ref(one_local_ref);
+       for_each_ref(one_local_ref, NULL);
 }
 
 static void get_dav_remote_heads(void)
@@ -1936,12 +1961,12 @@ static int ref_newer(const unsigned char *new_sha1,
         * old.  Otherwise we require --force.
         */
        o = deref_tag(parse_object(old_sha1), NULL, 0);
-       if (!o || o->type != commit_type)
+       if (!o || o->type != OBJ_COMMIT)
                return 0;
        old = (struct commit *) o;
 
        o = deref_tag(parse_object(new_sha1), NULL, 0);
-       if (!o || o->type != commit_type)
+       if (!o || o->type != OBJ_COMMIT)
                return 0;
        new = (struct commit *) o;
 
@@ -2020,7 +2045,7 @@ static void add_remote_info_ref(struct remote_ls_ctx *ls)
        fwrite_buffer(ref_info, 1, len, buf);
        free(ref_info);
 
-       if (o->type == tag_type) {
+       if (o->type == OBJ_TAG) {
                o = deref_tag(o, ls->dentry_name, 0);
                if (o) {
                        len = strlen(ls->dentry_name) + 45;
@@ -2106,7 +2131,7 @@ static int remote_exists(const char *path)
        return -1;
 }
 
-static void fetch_symref(char *path, char **symref, unsigned char *sha1)
+static void fetch_symref(const char *path, char **symref, unsigned char *sha1)
 {
        char *url;
        struct buffer buffer;
@@ -2140,15 +2165,16 @@ static void fetch_symref(char *path, char **symref, unsigned char *sha1)
        if (*symref != NULL)
                free(*symref);
        *symref = NULL;
-       memset(sha1, 0, 20);
+       hashclr(sha1);
 
        if (buffer.posn == 0)
                return;
 
        /* If it's a symref, set the refname; otherwise try for a sha1 */
-       if (!strncmp((char *)buffer.buffer, "ref: ", 5)) {
-               *symref = xcalloc(buffer.posn - 5, 1);
-               strncpy(*symref, (char *)buffer.buffer + 5, buffer.posn - 6);
+       if (!prefixcmp((char *)buffer.buffer, "ref: ")) {
+               *symref = xmalloc(buffer.posn - 5);
+               memcpy(*symref, (char *)buffer.buffer + 5, buffer.posn - 6);
+               (*symref)[buffer.posn - 6] = '\0';
        } else {
                get_sha1_hex(buffer.buffer, sha1);
        }
@@ -2158,49 +2184,11 @@ static void fetch_symref(char *path, char **symref, unsigned char *sha1)
 
 static int verify_merge_base(unsigned char *head_sha1, unsigned char *branch_sha1)
 {
-       int pipe_fd[2];
-       pid_t merge_base_pid;
-       char line[PATH_MAX + 20];
-       unsigned char merge_sha1[20];
-       int verified = 0;
-
-       if (pipe(pipe_fd) < 0)
-               die("Verify merge base: pipe failed");
-
-       merge_base_pid = fork();
-       if (!merge_base_pid) {
-               static const char *args[] = {
-                       "merge-base",
-                       "-a",
-                       NULL,
-                       NULL,
-                       NULL
-               };
-               args[2] = strdup(sha1_to_hex(head_sha1));
-               args[3] = sha1_to_hex(branch_sha1);
-
-               dup2(pipe_fd[1], 1);
-               close(pipe_fd[0]);
-               close(pipe_fd[1]);
-               execv_git_cmd(args);
-               die("merge-base setup failed");
-       }
-       if (merge_base_pid < 0)
-               die("merge-base fork failed");
-
-       dup2(pipe_fd[0], 0);
-       close(pipe_fd[0]);
-       close(pipe_fd[1]);
-       while (fgets(line, sizeof(line), stdin) != NULL) {
-               if (get_sha1_hex(line, merge_sha1))
-                       die("expected sha1, got garbage:\n %s", line);
-               if (!memcmp(branch_sha1, merge_sha1, 20)) {
-                       verified = 1;
-                       break;
-               }
-       }
+       struct commit *head = lookup_commit(head_sha1);
+       struct commit *branch = lookup_commit(branch_sha1);
+       struct commit_list *merge_bases = get_merge_bases(head, branch, 1);
 
-       return verified;
+       return (merge_bases && !merge_bases->next && merge_bases->item == branch);
 }
 
 static int delete_remote_branch(char *pattern, int force)
@@ -2315,7 +2303,6 @@ int main(int argc, char **argv)
        struct ref *ref;
 
        setup_git_directory();
-       setup_ident();
 
        remote = xcalloc(sizeof(*remote), 1);
 
@@ -2350,7 +2337,7 @@ int main(int argc, char **argv)
                        char *path = strstr(arg, "//");
                        remote->url = arg;
                        if (path) {
-                               path = index(path+2, '/');
+                               path = strchr(path+2, '/');
                                if (path)
                                        remote->path_len = strlen(path);
                        }
@@ -2430,7 +2417,7 @@ int main(int argc, char **argv)
 
                if (!ref->peer_ref)
                        continue;
-               if (!memcmp(ref->old_sha1, ref->peer_ref->new_sha1, 20)) {
+               if (!hashcmp(ref->old_sha1, ref->peer_ref->new_sha1)) {
                        if (push_verbosely || 1)
                                fprintf(stderr, "'%s': up-to-date\n", ref->name);
                        continue;
@@ -2459,7 +2446,7 @@ int main(int argc, char **argv)
                                continue;
                        }
                }
-               memcpy(ref->new_sha1, ref->peer_ref->new_sha1, 20);
+               hashcpy(ref->new_sha1, ref->peer_ref->new_sha1);
                if (is_zero_sha1(ref->new_sha1)) {
                        error("cannot happen anymore");
                        rc = -3;
@@ -2486,7 +2473,7 @@ int main(int argc, char **argv)
 
                /* Set up revision info for this refspec */
                commit_argc = 3;
-               new_sha1_hex = strdup(sha1_to_hex(ref->new_sha1));
+               new_sha1_hex = xstrdup(sha1_to_hex(ref->new_sha1));
                old_sha1_hex = NULL;
                commit_argv[1] = "--objects";
                commit_argv[2] = new_sha1_hex;
@@ -2497,6 +2484,7 @@ int main(int argc, char **argv)
                        commit_argv[3] = old_sha1_hex;
                        commit_argc++;
                }
+               init_revisions(&revs, setup_git_directory());
                setup_revisions(commit_argc, commit_argv, &revs, NULL);
                free(new_sha1_hex);
                if (old_sha1_hex) {
@@ -2517,7 +2505,9 @@ int main(int argc, char **argv)
                if (objects_to_send)
                        fprintf(stderr, "    sending %d objects\n",
                                objects_to_send);
+#ifdef USE_CURL_MULTI
                fill_active_slots();
+#endif
                finish_all_active_slots();
 
                /* Update the remote branch if all went well */