builtin-receive-pack.con commit Merge git://git.kernel.org/pub/scm/gitk/gitk (d4f6bc8)
   1#include "cache.h"
   2#include "pack.h"
   3#include "refs.h"
   4#include "pkt-line.h"
   5#include "run-command.h"
   6#include "exec_cmd.h"
   7#include "commit.h"
   8#include "object.h"
   9#include "remote.h"
  10#include "transport.h"
  11
  12static const char receive_pack_usage[] = "git receive-pack <git-dir>";
  13
  14enum deny_action {
  15        DENY_UNCONFIGURED,
  16        DENY_IGNORE,
  17        DENY_WARN,
  18        DENY_REFUSE,
  19};
  20
  21static int deny_deletes;
  22static int deny_non_fast_forwards;
  23static enum deny_action deny_current_branch = DENY_UNCONFIGURED;
  24static enum deny_action deny_delete_current = DENY_UNCONFIGURED;
  25static int receive_fsck_objects;
  26static int receive_unpack_limit = -1;
  27static int transfer_unpack_limit = -1;
  28static int unpack_limit = 100;
  29static int report_status;
  30static int prefer_ofs_delta = 1;
  31static const char *head_name;
  32static char *capabilities_to_send;
  33
  34static enum deny_action parse_deny_action(const char *var, const char *value)
  35{
  36        if (value) {
  37                if (!strcasecmp(value, "ignore"))
  38                        return DENY_IGNORE;
  39                if (!strcasecmp(value, "warn"))
  40                        return DENY_WARN;
  41                if (!strcasecmp(value, "refuse"))
  42                        return DENY_REFUSE;
  43        }
  44        if (git_config_bool(var, value))
  45                return DENY_REFUSE;
  46        return DENY_IGNORE;
  47}
  48
  49static int receive_pack_config(const char *var, const char *value, void *cb)
  50{
  51        if (strcmp(var, "receive.denydeletes") == 0) {
  52                deny_deletes = git_config_bool(var, value);
  53                return 0;
  54        }
  55
  56        if (strcmp(var, "receive.denynonfastforwards") == 0) {
  57                deny_non_fast_forwards = git_config_bool(var, value);
  58                return 0;
  59        }
  60
  61        if (strcmp(var, "receive.unpacklimit") == 0) {
  62                receive_unpack_limit = git_config_int(var, value);
  63                return 0;
  64        }
  65
  66        if (strcmp(var, "transfer.unpacklimit") == 0) {
  67                transfer_unpack_limit = git_config_int(var, value);
  68                return 0;
  69        }
  70
  71        if (strcmp(var, "receive.fsckobjects") == 0) {
  72                receive_fsck_objects = git_config_bool(var, value);
  73                return 0;
  74        }
  75
  76        if (!strcmp(var, "receive.denycurrentbranch")) {
  77                deny_current_branch = parse_deny_action(var, value);
  78                return 0;
  79        }
  80
  81        if (strcmp(var, "receive.denydeletecurrent") == 0) {
  82                deny_delete_current = parse_deny_action(var, value);
  83                return 0;
  84        }
  85
  86        if (strcmp(var, "repack.usedeltabaseoffset") == 0) {
  87                prefer_ofs_delta = git_config_bool(var, value);
  88                return 0;
  89        }
  90
  91        return git_default_config(var, value, cb);
  92}
  93
  94static int show_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
  95{
  96        if (!capabilities_to_send)
  97                packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
  98        else
  99                packet_write(1, "%s %s%c%s\n",
 100                             sha1_to_hex(sha1), path, 0, capabilities_to_send);
 101        capabilities_to_send = NULL;
 102        return 0;
 103}
 104
 105static void write_head_info(void)
 106{
 107        for_each_ref(show_ref, NULL);
 108        if (capabilities_to_send)
 109                show_ref("capabilities^{}", null_sha1, 0, NULL);
 110
 111}
 112
 113struct command {
 114        struct command *next;
 115        const char *error_string;
 116        unsigned char old_sha1[20];
 117        unsigned char new_sha1[20];
 118        char ref_name[FLEX_ARRAY]; /* more */
 119};
 120
 121static struct command *commands;
 122
 123static const char pre_receive_hook[] = "hooks/pre-receive";
 124static const char post_receive_hook[] = "hooks/post-receive";
 125
 126static int hook_status(int code, const char *hook_name)
 127{
 128        switch (code) {
 129        case 0:
 130                return 0;
 131        case -ERR_RUN_COMMAND_FORK:
 132                return error("hook fork failed");
 133        case -ERR_RUN_COMMAND_EXEC:
 134                return error("hook execute failed");
 135        case -ERR_RUN_COMMAND_PIPE:
 136                return error("hook pipe failed");
 137        case -ERR_RUN_COMMAND_WAITPID:
 138                return error("waitpid failed");
 139        case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
 140                return error("waitpid is confused");
 141        case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
 142                return error("%s died of signal", hook_name);
 143        case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
 144                return error("%s died strangely", hook_name);
 145        default:
 146                error("%s exited with error code %d", hook_name, -code);
 147                return -code;
 148        }
 149}
 150
 151static int run_receive_hook(const char *hook_name)
 152{
 153        static char buf[sizeof(commands->old_sha1) * 2 + PATH_MAX + 4];
 154        struct command *cmd;
 155        struct child_process proc;
 156        const char *argv[2];
 157        int have_input = 0, code;
 158
 159        for (cmd = commands; !have_input && cmd; cmd = cmd->next) {
 160                if (!cmd->error_string)
 161                        have_input = 1;
 162        }
 163
 164        if (!have_input || access(hook_name, X_OK) < 0)
 165                return 0;
 166
 167        argv[0] = hook_name;
 168        argv[1] = NULL;
 169
 170        memset(&proc, 0, sizeof(proc));
 171        proc.argv = argv;
 172        proc.in = -1;
 173        proc.stdout_to_stderr = 1;
 174
 175        code = start_command(&proc);
 176        if (code)
 177                return hook_status(code, hook_name);
 178        for (cmd = commands; cmd; cmd = cmd->next) {
 179                if (!cmd->error_string) {
 180                        size_t n = snprintf(buf, sizeof(buf), "%s %s %s\n",
 181                                sha1_to_hex(cmd->old_sha1),
 182                                sha1_to_hex(cmd->new_sha1),
 183                                cmd->ref_name);
 184                        if (write_in_full(proc.in, buf, n) != n)
 185                                break;
 186                }
 187        }
 188        close(proc.in);
 189        return hook_status(finish_command(&proc), hook_name);
 190}
 191
 192static int run_update_hook(struct command *cmd)
 193{
 194        static const char update_hook[] = "hooks/update";
 195        const char *argv[5];
 196
 197        if (access(update_hook, X_OK) < 0)
 198                return 0;
 199
 200        argv[0] = update_hook;
 201        argv[1] = cmd->ref_name;
 202        argv[2] = sha1_to_hex(cmd->old_sha1);
 203        argv[3] = sha1_to_hex(cmd->new_sha1);
 204        argv[4] = NULL;
 205
 206        return hook_status(run_command_v_opt(argv, RUN_COMMAND_NO_STDIN |
 207                                        RUN_COMMAND_STDOUT_TO_STDERR),
 208                        update_hook);
 209}
 210
 211static int is_ref_checked_out(const char *ref)
 212{
 213        if (is_bare_repository())
 214                return 0;
 215
 216        if (!head_name)
 217                return 0;
 218        return !strcmp(head_name, ref);
 219}
 220
 221static char *warn_unconfigured_deny_msg[] = {
 222        "Updating the currently checked out branch may cause confusion,",
 223        "as the index and work tree do not reflect changes that are in HEAD.",
 224        "As a result, you may see the changes you just pushed into it",
 225        "reverted when you run 'git diff' over there, and you may want",
 226        "to run 'git reset --hard' before starting to work to recover.",
 227        "",
 228        "You can set 'receive.denyCurrentBranch' configuration variable to",
 229        "'refuse' in the remote repository to forbid pushing into its",
 230        "current branch."
 231        "",
 232        "To allow pushing into the current branch, you can set it to 'ignore';",
 233        "but this is not recommended unless you arranged to update its work",
 234        "tree to match what you pushed in some other way.",
 235        "",
 236        "To squelch this message, you can set it to 'warn'.",
 237        "",
 238        "Note that the default will change in a future version of git",
 239        "to refuse updating the current branch unless you have the",
 240        "configuration variable set to either 'ignore' or 'warn'."
 241};
 242
 243static void warn_unconfigured_deny(void)
 244{
 245        int i;
 246        for (i = 0; i < ARRAY_SIZE(warn_unconfigured_deny_msg); i++)
 247                warning("%s", warn_unconfigured_deny_msg[i]);
 248}
 249
 250static char *warn_unconfigured_deny_delete_current_msg[] = {
 251        "Deleting the current branch can cause confusion by making the next",
 252        "'git clone' not check out any file.",
 253        "",
 254        "You can set 'receive.denyDeleteCurrent' configuration variable to",
 255        "'refuse' in the remote repository to disallow deleting the current",
 256        "branch.",
 257        "",
 258        "You can set it to 'ignore' to allow such a delete without a warning.",
 259        "",
 260        "To make this warning message less loud, you can set it to 'warn'.",
 261        "",
 262        "Note that the default will change in a future version of git",
 263        "to refuse deleting the current branch unless you have the",
 264        "configuration variable set to either 'ignore' or 'warn'."
 265};
 266
 267static void warn_unconfigured_deny_delete_current(void)
 268{
 269        int i;
 270        for (i = 0;
 271             i < ARRAY_SIZE(warn_unconfigured_deny_delete_current_msg);
 272             i++)
 273                warning("%s", warn_unconfigured_deny_delete_current_msg[i]);
 274}
 275
 276static const char *update(struct command *cmd)
 277{
 278        const char *name = cmd->ref_name;
 279        unsigned char *old_sha1 = cmd->old_sha1;
 280        unsigned char *new_sha1 = cmd->new_sha1;
 281        struct ref_lock *lock;
 282
 283        /* only refs/... are allowed */
 284        if (prefixcmp(name, "refs/") || check_ref_format(name + 5)) {
 285                error("refusing to create funny ref '%s' remotely", name);
 286                return "funny refname";
 287        }
 288
 289        if (is_ref_checked_out(name)) {
 290                switch (deny_current_branch) {
 291                case DENY_IGNORE:
 292                        break;
 293                case DENY_UNCONFIGURED:
 294                case DENY_WARN:
 295                        warning("updating the current branch");
 296                        if (deny_current_branch == DENY_UNCONFIGURED)
 297                                warn_unconfigured_deny();
 298                        break;
 299                case DENY_REFUSE:
 300                        error("refusing to update checked out branch: %s", name);
 301                        return "branch is currently checked out";
 302                }
 303        }
 304
 305        if (!is_null_sha1(new_sha1) && !has_sha1_file(new_sha1)) {
 306                error("unpack should have generated %s, "
 307                      "but I can't find it!", sha1_to_hex(new_sha1));
 308                return "bad pack";
 309        }
 310
 311        if (!is_null_sha1(old_sha1) && is_null_sha1(new_sha1)) {
 312                if (deny_deletes && !prefixcmp(name, "refs/heads/")) {
 313                        error("denying ref deletion for %s", name);
 314                        return "deletion prohibited";
 315                }
 316
 317                if (!strcmp(name, head_name)) {
 318                        switch (deny_delete_current) {
 319                        case DENY_IGNORE:
 320                                break;
 321                        case DENY_WARN:
 322                        case DENY_UNCONFIGURED:
 323                                if (deny_delete_current == DENY_UNCONFIGURED)
 324                                        warn_unconfigured_deny_delete_current();
 325                                warning("deleting the current branch");
 326                                break;
 327                        case DENY_REFUSE:
 328                                error("refusing to delete the current branch: %s", name);
 329                                return "deletion of the current branch prohibited";
 330                        }
 331                }
 332        }
 333
 334        if (deny_non_fast_forwards && !is_null_sha1(new_sha1) &&
 335            !is_null_sha1(old_sha1) &&
 336            !prefixcmp(name, "refs/heads/")) {
 337                struct object *old_object, *new_object;
 338                struct commit *old_commit, *new_commit;
 339                struct commit_list *bases, *ent;
 340
 341                old_object = parse_object(old_sha1);
 342                new_object = parse_object(new_sha1);
 343
 344                if (!old_object || !new_object ||
 345                    old_object->type != OBJ_COMMIT ||
 346                    new_object->type != OBJ_COMMIT) {
 347                        error("bad sha1 objects for %s", name);
 348                        return "bad ref";
 349                }
 350                old_commit = (struct commit *)old_object;
 351                new_commit = (struct commit *)new_object;
 352                bases = get_merge_bases(old_commit, new_commit, 1);
 353                for (ent = bases; ent; ent = ent->next)
 354                        if (!hashcmp(old_sha1, ent->item->object.sha1))
 355                                break;
 356                free_commit_list(bases);
 357                if (!ent) {
 358                        error("denying non-fast forward %s"
 359                              " (you should pull first)", name);
 360                        return "non-fast forward";
 361                }
 362        }
 363        if (run_update_hook(cmd)) {
 364                error("hook declined to update %s", name);
 365                return "hook declined";
 366        }
 367
 368        if (is_null_sha1(new_sha1)) {
 369                if (!parse_object(old_sha1)) {
 370                        warning ("Allowing deletion of corrupt ref.");
 371                        old_sha1 = NULL;
 372                }
 373                if (delete_ref(name, old_sha1, 0)) {
 374                        error("failed to delete %s", name);
 375                        return "failed to delete";
 376                }
 377                return NULL; /* good */
 378        }
 379        else {
 380                lock = lock_any_ref_for_update(name, old_sha1, 0);
 381                if (!lock) {
 382                        error("failed to lock %s", name);
 383                        return "failed to lock";
 384                }
 385                if (write_ref_sha1(lock, new_sha1, "push")) {
 386                        return "failed to write"; /* error() already called */
 387                }
 388                return NULL; /* good */
 389        }
 390}
 391
 392static char update_post_hook[] = "hooks/post-update";
 393
 394static void run_update_post_hook(struct command *cmd)
 395{
 396        struct command *cmd_p;
 397        int argc;
 398        const char **argv;
 399
 400        for (argc = 0, cmd_p = cmd; cmd_p; cmd_p = cmd_p->next) {
 401                if (cmd_p->error_string)
 402                        continue;
 403                argc++;
 404        }
 405        if (!argc || access(update_post_hook, X_OK) < 0)
 406                return;
 407        argv = xmalloc(sizeof(*argv) * (2 + argc));
 408        argv[0] = update_post_hook;
 409
 410        for (argc = 1, cmd_p = cmd; cmd_p; cmd_p = cmd_p->next) {
 411                char *p;
 412                if (cmd_p->error_string)
 413                        continue;
 414                p = xmalloc(strlen(cmd_p->ref_name) + 1);
 415                strcpy(p, cmd_p->ref_name);
 416                argv[argc] = p;
 417                argc++;
 418        }
 419        argv[argc] = NULL;
 420        run_command_v_opt(argv, RUN_COMMAND_NO_STDIN
 421                | RUN_COMMAND_STDOUT_TO_STDERR);
 422}
 423
 424static void execute_commands(const char *unpacker_error)
 425{
 426        struct command *cmd = commands;
 427        unsigned char sha1[20];
 428
 429        if (unpacker_error) {
 430                while (cmd) {
 431                        cmd->error_string = "n/a (unpacker error)";
 432                        cmd = cmd->next;
 433                }
 434                return;
 435        }
 436
 437        if (run_receive_hook(pre_receive_hook)) {
 438                while (cmd) {
 439                        cmd->error_string = "pre-receive hook declined";
 440                        cmd = cmd->next;
 441                }
 442                return;
 443        }
 444
 445        head_name = resolve_ref("HEAD", sha1, 0, NULL);
 446
 447        while (cmd) {
 448                cmd->error_string = update(cmd);
 449                cmd = cmd->next;
 450        }
 451}
 452
 453static void read_head_info(void)
 454{
 455        struct command **p = &commands;
 456        for (;;) {
 457                static char line[1000];
 458                unsigned char old_sha1[20], new_sha1[20];
 459                struct command *cmd;
 460                char *refname;
 461                int len, reflen;
 462
 463                len = packet_read_line(0, line, sizeof(line));
 464                if (!len)
 465                        break;
 466                if (line[len-1] == '\n')
 467                        line[--len] = 0;
 468                if (len < 83 ||
 469                    line[40] != ' ' ||
 470                    line[81] != ' ' ||
 471                    get_sha1_hex(line, old_sha1) ||
 472                    get_sha1_hex(line + 41, new_sha1))
 473                        die("protocol error: expected old/new/ref, got '%s'",
 474                            line);
 475
 476                refname = line + 82;
 477                reflen = strlen(refname);
 478                if (reflen + 82 < len) {
 479                        if (strstr(refname + reflen + 1, "report-status"))
 480                                report_status = 1;
 481                }
 482                cmd = xmalloc(sizeof(struct command) + len - 80);
 483                hashcpy(cmd->old_sha1, old_sha1);
 484                hashcpy(cmd->new_sha1, new_sha1);
 485                memcpy(cmd->ref_name, line + 82, len - 81);
 486                cmd->error_string = NULL;
 487                cmd->next = NULL;
 488                *p = cmd;
 489                p = &cmd->next;
 490        }
 491}
 492
 493static const char *parse_pack_header(struct pack_header *hdr)
 494{
 495        switch (read_pack_header(0, hdr)) {
 496        case PH_ERROR_EOF:
 497                return "eof before pack header was fully read";
 498
 499        case PH_ERROR_PACK_SIGNATURE:
 500                return "protocol error (pack signature mismatch detected)";
 501
 502        case PH_ERROR_PROTOCOL:
 503                return "protocol error (pack version unsupported)";
 504
 505        default:
 506                return "unknown error in parse_pack_header";
 507
 508        case 0:
 509                return NULL;
 510        }
 511}
 512
 513static const char *pack_lockfile;
 514
 515static const char *unpack(void)
 516{
 517        struct pack_header hdr;
 518        const char *hdr_err;
 519        char hdr_arg[38];
 520
 521        hdr_err = parse_pack_header(&hdr);
 522        if (hdr_err)
 523                return hdr_err;
 524        snprintf(hdr_arg, sizeof(hdr_arg),
 525                        "--pack_header=%"PRIu32",%"PRIu32,
 526                        ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries));
 527
 528        if (ntohl(hdr.hdr_entries) < unpack_limit) {
 529                int code, i = 0;
 530                const char *unpacker[4];
 531                unpacker[i++] = "unpack-objects";
 532                if (receive_fsck_objects)
 533                        unpacker[i++] = "--strict";
 534                unpacker[i++] = hdr_arg;
 535                unpacker[i++] = NULL;
 536                code = run_command_v_opt(unpacker, RUN_GIT_CMD);
 537                switch (code) {
 538                case 0:
 539                        return NULL;
 540                case -ERR_RUN_COMMAND_FORK:
 541                        return "unpack fork failed";
 542                case -ERR_RUN_COMMAND_EXEC:
 543                        return "unpack execute failed";
 544                case -ERR_RUN_COMMAND_WAITPID:
 545                        return "waitpid failed";
 546                case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
 547                        return "waitpid is confused";
 548                case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
 549                        return "unpacker died of signal";
 550                case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
 551                        return "unpacker died strangely";
 552                default:
 553                        return "unpacker exited with error code";
 554                }
 555        } else {
 556                const char *keeper[7];
 557                int s, status, i = 0;
 558                char keep_arg[256];
 559                struct child_process ip;
 560
 561                s = sprintf(keep_arg, "--keep=receive-pack %"PRIuMAX" on ", (uintmax_t) getpid());
 562                if (gethostname(keep_arg + s, sizeof(keep_arg) - s))
 563                        strcpy(keep_arg + s, "localhost");
 564
 565                keeper[i++] = "index-pack";
 566                keeper[i++] = "--stdin";
 567                if (receive_fsck_objects)
 568                        keeper[i++] = "--strict";
 569                keeper[i++] = "--fix-thin";
 570                keeper[i++] = hdr_arg;
 571                keeper[i++] = keep_arg;
 572                keeper[i++] = NULL;
 573                memset(&ip, 0, sizeof(ip));
 574                ip.argv = keeper;
 575                ip.out = -1;
 576                ip.git_cmd = 1;
 577                if (start_command(&ip))
 578                        return "index-pack fork failed";
 579                pack_lockfile = index_pack_lockfile(ip.out);
 580                close(ip.out);
 581                status = finish_command(&ip);
 582                if (!status) {
 583                        reprepare_packed_git();
 584                        return NULL;
 585                }
 586                return "index-pack abnormal exit";
 587        }
 588}
 589
 590static void report(const char *unpack_status)
 591{
 592        struct command *cmd;
 593        packet_write(1, "unpack %s\n",
 594                     unpack_status ? unpack_status : "ok");
 595        for (cmd = commands; cmd; cmd = cmd->next) {
 596                if (!cmd->error_string)
 597                        packet_write(1, "ok %s\n",
 598                                     cmd->ref_name);
 599                else
 600                        packet_write(1, "ng %s %s\n",
 601                                     cmd->ref_name, cmd->error_string);
 602        }
 603        packet_flush(1);
 604}
 605
 606static int delete_only(struct command *cmd)
 607{
 608        while (cmd) {
 609                if (!is_null_sha1(cmd->new_sha1))
 610                        return 0;
 611                cmd = cmd->next;
 612        }
 613        return 1;
 614}
 615
 616static int add_refs_from_alternate(struct alternate_object_database *e, void *unused)
 617{
 618        char *other;
 619        size_t len;
 620        struct remote *remote;
 621        struct transport *transport;
 622        const struct ref *extra;
 623
 624        e->name[-1] = '\0';
 625        other = xstrdup(make_absolute_path(e->base));
 626        e->name[-1] = '/';
 627        len = strlen(other);
 628
 629        while (other[len-1] == '/')
 630                other[--len] = '\0';
 631        if (len < 8 || memcmp(other + len - 8, "/objects", 8))
 632                return 0;
 633        /* Is this a git repository with refs? */
 634        memcpy(other + len - 8, "/refs", 6);
 635        if (!is_directory(other))
 636                return 0;
 637        other[len - 8] = '\0';
 638        remote = remote_get(other);
 639        transport = transport_get(remote, other);
 640        for (extra = transport_get_remote_refs(transport);
 641             extra;
 642             extra = extra->next) {
 643                add_extra_ref(".have", extra->old_sha1, 0);
 644        }
 645        transport_disconnect(transport);
 646        free(other);
 647        return 0;
 648}
 649
 650static void add_alternate_refs(void)
 651{
 652        foreach_alt_odb(add_refs_from_alternate, NULL);
 653}
 654
 655int cmd_receive_pack(int argc, const char **argv, const char *prefix)
 656{
 657        int i;
 658        char *dir = NULL;
 659
 660        argv++;
 661        for (i = 1; i < argc; i++) {
 662                const char *arg = *argv++;
 663
 664                if (*arg == '-') {
 665                        /* Do flag handling here */
 666                        usage(receive_pack_usage);
 667                }
 668                if (dir)
 669                        usage(receive_pack_usage);
 670                dir = xstrdup(arg);
 671        }
 672        if (!dir)
 673                usage(receive_pack_usage);
 674
 675        setup_path();
 676
 677        if (!enter_repo(dir, 0))
 678                die("'%s' does not appear to be a git repository", dir);
 679
 680        if (is_repository_shallow())
 681                die("attempt to push into a shallow repository");
 682
 683        git_config(receive_pack_config, NULL);
 684
 685        if (0 <= transfer_unpack_limit)
 686                unpack_limit = transfer_unpack_limit;
 687        else if (0 <= receive_unpack_limit)
 688                unpack_limit = receive_unpack_limit;
 689
 690        capabilities_to_send = (prefer_ofs_delta) ?
 691                " report-status delete-refs ofs-delta " :
 692                " report-status delete-refs ";
 693
 694        add_alternate_refs();
 695        write_head_info();
 696        clear_extra_refs();
 697
 698        /* EOF */
 699        packet_flush(1);
 700
 701        read_head_info();
 702        if (commands) {
 703                const char *unpack_status = NULL;
 704
 705                if (!delete_only(commands))
 706                        unpack_status = unpack();
 707                execute_commands(unpack_status);
 708                if (pack_lockfile)
 709                        unlink_or_warn(pack_lockfile);
 710                if (report_status)
 711                        report(unpack_status);
 712                run_receive_hook(post_receive_hook);
 713                run_update_post_hook(commands);
 714        }
 715        return 0;
 716}