Merge branch 'jc/lock-report-on-error'
[gitweb.git] / builtin / receive-pack.c
index f7cd1802524e2ba41a41d6479e69534dc042b404..6b97cbdbe9444d72d575c149678e4b609a154842 100644 (file)
@@ -20,6 +20,7 @@
 #include "gpg-interface.h"
 #include "sigchain.h"
 #include "fsck.h"
+#include "tmp-objdir.h"
 
 static const char * const receive_pack_usage[] = {
        N_("git receive-pack <git-dir>"),
@@ -86,6 +87,8 @@ static enum {
 } use_keepalive;
 static int keepalive_in_sec = 5;
 
+static struct tmp_objdir *tmp_objdir;
+
 static enum deny_action parse_deny_action(const char *var, const char *value)
 {
        if (value) {
@@ -224,7 +227,7 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
 static void show_ref(const char *path, const unsigned char *sha1)
 {
        if (sent_capabilities) {
-               packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
+               packet_write_fmt(1, "%s %s\n", sha1_to_hex(sha1), path);
        } else {
                struct strbuf cap = STRBUF_INIT;
 
@@ -239,7 +242,7 @@ static void show_ref(const char *path, const unsigned char *sha1)
                if (advertise_push_options)
                        strbuf_addstr(&cap, " push-options");
                strbuf_addf(&cap, " agent=%s", git_user_agent_sanitized());
-               packet_write(1, "%s %s%c%s\n",
+               packet_write_fmt(1, "%s %s%c%s\n",
                             sha1_to_hex(sha1), path, 0, cap.buf);
                strbuf_release(&cap);
                sent_capabilities = 1;
@@ -664,6 +667,9 @@ static int run_and_feed_hook(const char *hook_name, feed_fn feed,
        } else
                argv_array_pushf(&proc.env_array, "GIT_PUSH_OPTION_COUNT");
 
+       if (tmp_objdir)
+               argv_array_pushv(&proc.env_array, tmp_objdir_env(tmp_objdir));
+
        if (use_sideband) {
                memset(&muxer, 0, sizeof(muxer));
                muxer.proc = copy_to_sideband;
@@ -763,6 +769,7 @@ static int run_update_hook(struct command *cmd)
        proc.stdout_to_stderr = 1;
        proc.err = use_sideband ? -1 : 0;
        proc.argv = argv;
+       proc.env = tmp_objdir_env(tmp_objdir);
 
        code = start_command(&proc);
        if (code)
@@ -788,8 +795,8 @@ static char *refuse_unconfigured_deny_msg =
           "with what you pushed, and will require 'git reset --hard' to match\n"
           "the work tree to HEAD.\n"
           "\n"
-          "You can set 'receive.denyCurrentBranch' configuration variable to\n"
-          "'ignore' or 'warn' in the remote repository to allow pushing into\n"
+          "You can set the 'receive.denyCurrentBranch' configuration variable\n"
+          "to 'ignore' or 'warn' in the remote repository to allow pushing into\n"
           "its current branch; however, this is not recommended unless you\n"
           "arranged to update its work tree to match what you pushed in some\n"
           "other way.\n"
@@ -834,6 +841,7 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
                    !delayed_reachability_test(si, i))
                        sha1_array_append(&extra, si->shallow->sha1[i]);
 
+       opt.env = tmp_objdir_env(tmp_objdir);
        setup_alternate_shallow(&shallow_lock, &opt.shallow_file, &extra);
        if (check_connected(command_singleton_iterator, cmd, &opt)) {
                rollback_lock_file(&shallow_lock);
@@ -1155,10 +1163,6 @@ static void check_aliased_update(struct command *cmd, struct string_list *list)
        struct string_list_item *item;
        struct command *dst_cmd;
        unsigned char sha1[GIT_SHA1_RAWSZ];
-       char cmd_oldh[GIT_SHA1_HEXSZ + 1],
-            cmd_newh[GIT_SHA1_HEXSZ + 1],
-            dst_oldh[GIT_SHA1_HEXSZ + 1],
-            dst_newh[GIT_SHA1_HEXSZ + 1];
        int flag;
 
        strbuf_addf(&buf, "%s%s", get_git_namespace(), cmd->ref_name);
@@ -1189,14 +1193,14 @@ static void check_aliased_update(struct command *cmd, struct string_list *list)
 
        dst_cmd->skip_update = 1;
 
-       find_unique_abbrev_r(cmd_oldh, cmd->old_sha1, DEFAULT_ABBREV);
-       find_unique_abbrev_r(cmd_newh, cmd->new_sha1, DEFAULT_ABBREV);
-       find_unique_abbrev_r(dst_oldh, dst_cmd->old_sha1, DEFAULT_ABBREV);
-       find_unique_abbrev_r(dst_newh, dst_cmd->new_sha1, DEFAULT_ABBREV);
        rp_error("refusing inconsistent update between symref '%s' (%s..%s) and"
                 " its target '%s' (%s..%s)",
-                cmd->ref_name, cmd_oldh, cmd_newh,
-                dst_cmd->ref_name, dst_oldh, dst_newh);
+                cmd->ref_name,
+                find_unique_abbrev(cmd->old_sha1, DEFAULT_ABBREV),
+                find_unique_abbrev(cmd->new_sha1, DEFAULT_ABBREV),
+                dst_cmd->ref_name,
+                find_unique_abbrev(dst_cmd->old_sha1, DEFAULT_ABBREV),
+                find_unique_abbrev(dst_cmd->new_sha1, DEFAULT_ABBREV));
 
        cmd->error_string = dst_cmd->error_string =
                "inconsistent aliased update";
@@ -1241,12 +1245,17 @@ static void set_connectivity_errors(struct command *commands,
 
        for (cmd = commands; cmd; cmd = cmd->next) {
                struct command *singleton = cmd;
+               struct check_connected_options opt = CHECK_CONNECTED_INIT;
+
                if (shallow_update && si->shallow_ref[cmd->index])
                        /* to be checked in update_shallow_ref() */
                        continue;
+
+               opt.env = tmp_objdir_env(tmp_objdir);
                if (!check_connected(command_singleton_iterator, &singleton,
-                                    NULL))
+                                    &opt))
                        continue;
+
                cmd->error_string = "missing necessary objects";
        }
 }
@@ -1429,6 +1438,7 @@ static void execute_commands(struct command *commands,
        data.si = si;
        opt.err_fd = err_fd;
        opt.progress = err_fd && !quiet;
+       opt.env = tmp_objdir_env(tmp_objdir);
        if (check_connected(iterate_receive_command_list, &data, &opt))
                set_connectivity_errors(commands, si);
 
@@ -1445,6 +1455,19 @@ static void execute_commands(struct command *commands,
                return;
        }
 
+       /*
+        * Now we'll start writing out refs, which means the objects need
+        * to be in their final positions so that other processes can see them.
+        */
+       if (tmp_objdir_migrate(tmp_objdir) < 0) {
+               for (cmd = commands; cmd; cmd = cmd->next) {
+                       if (!cmd->error_string)
+                               cmd->error_string = "unable to migrate objects to permanent storage";
+               }
+               return;
+       }
+       tmp_objdir = NULL;
+
        check_aliased_updates(commands);
 
        free(head_name_to_free);
@@ -1640,6 +1663,18 @@ static const char *unpack(int err_fd, struct shallow_info *si)
                argv_array_push(&child.args, alt_shallow_file);
        }
 
+       tmp_objdir = tmp_objdir_create();
+       if (!tmp_objdir)
+               return "unable to create temporary object directory";
+       child.env = tmp_objdir_env(tmp_objdir);
+
+       /*
+        * Normally we just pass the tmp_objdir environment to the child
+        * processes that do the heavy lifting, but we may need to see these
+        * objects ourselves to set up shallow information.
+        */
+       tmp_objdir_add_as_alternate(tmp_objdir);
+
        if (ntohl(hdr.hdr_entries) < unpack_limit) {
                argv_array_pushl(&child.args, "unpack-objects", hdr_arg, NULL);
                if (quiet)