X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=send-pack.c;h=9f9a6e70b8789f63891c5b6e07822c546af8eec4;hb=8548ea8ded0d7025f2540ce8d4648dbf76065d3a;hp=4d015fd6e47e5c8cc518fac1d5601cfa012a46d4;hpb=37fde874c2448ae2cd98abe24df2bd2a50aa2cda;p=git.git diff --git a/send-pack.c b/send-pack.c index 4d015fd6..9f9a6e70 100644 --- a/send-pack.c +++ b/send-pack.c @@ -105,12 +105,23 @@ static int pack_objects(int fd, struct ref *refs) return 0; } +static void unmark_and_free(struct commit_list *list, unsigned int mark) +{ + while (list) { + struct commit_list *temp = list; + temp->item->object.flags &= ~mark; + list = temp->next; + free(temp); + } +} + static int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1) { struct object *o; struct commit *old, *new; - struct commit_list *list; + struct commit_list *list, *used; + int found = 0; /* Both new and old must be commit-ish and new is descendant of * old. Otherwise we require --force. @@ -127,14 +138,20 @@ static int ref_newer(const unsigned char *new_sha1, if (parse_commit(new) < 0) return 0; - list = NULL; + + used = list = NULL; commit_list_insert(new, &list); while (list) { new = pop_most_recent_commit(&list, 1); - if (new == old) - return 1; + commit_list_insert(new, &used); + if (new == old) { + found = 1; + break; + } } - return 0; + unmark_and_free(list, 1); + unmark_and_free(used, 1); + return found; } static struct ref *local_refs, **local_tail; @@ -164,7 +181,7 @@ static int send_pack(int in, int out, int nr_refspec, char **refspec) int new_refs; /* No funny business with the matcher */ - remote_tail = get_remote_heads(in, &remote_refs, 0, NULL); + remote_tail = get_remote_heads(in, &remote_refs, 0, NULL, 1); get_local_heads(); /* match them up */ @@ -189,7 +206,8 @@ static int send_pack(int in, int out, int nr_refspec, char **refspec) /* This part determines what can overwrite what. * The rules are: * - * (0) you can always use --force. + * (0) you can always use --force or +A:B notation to + * selectively force individual ref pairs. * * (1) if the old thing does not exist, it is OK. * @@ -201,16 +219,19 @@ static int send_pack(int in, int out, int nr_refspec, char **refspec) * descendant of old, it is OK. */ - if (!force_update && !is_zero_sha1(ref->old_sha1)) { + if (!force_update && + !is_zero_sha1(ref->old_sha1) && + !ref->force) { if (!has_sha1_file(ref->old_sha1)) { error("remote '%s' object %s does not " "exist on local", ref->name, sha1_to_hex(ref->old_sha1)); continue; } + /* We assume that local is fsck-clean. Otherwise - * you _could_ have a old tag which points at - * something you do not have which may or may not + * you _could_ have an old tag which points at + * something you do not have, which may or may not * be a commit. */ if (!ref_newer(ref->peer_ref->new_sha1,