diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 0d51bfb79eb3e8b234ca4ee98844de20d46503b6..9b56be3cc690d4a5e4eb65ccd8e364f3245cde39 100644 (file)
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
#include "transport.h"
#include "string-list.h"
#include "sha1-array.h"
+#include "connected.h"
static const char receive_pack_usage[] = "git receive-pack <git-dir>";
static int deny_non_fast_forwards;
static enum deny_action deny_current_branch = DENY_UNCONFIGURED;
static enum deny_action deny_delete_current = DENY_UNCONFIGURED;
-static int receive_fsck_objects;
+static int receive_fsck_objects = -1;
+static int transfer_fsck_objects = -1;
static int receive_unpack_limit = -1;
static int transfer_unpack_limit = -1;
static int unpack_limit = 100;
return 0;
}
+ if (strcmp(var, "transfer.fsckobjects") == 0) {
+ transfer_fsck_objects = git_config_bool(var, value);
+ return 0;
+ }
+
if (!strcmp(var, "receive.denycurrentbranch")) {
deny_current_branch = parse_deny_action(var, value);
return 0;
@@ -120,9 +127,25 @@ static int show_ref(const char *path, const unsigned char *sha1, int flag, void
return 0;
}
+static int show_ref_cb(const char *path, const unsigned char *sha1, int flag, void *cb_data)
+{
+ path = strip_namespace(path);
+ /*
+ * Advertise refs outside our current namespace as ".have"
+ * refs, so that the client can use them to minimize data
+ * transfer but will otherwise ignore them. This happens to
+ * cover ".have" that are thrown in by add_one_alternate_ref()
+ * to mark histories that are complete in our alternates as
+ * well.
+ */
+ if (!path)
+ path = ".have";
+ return show_ref(path, sha1, flag, cb_data);
+}
+
static void write_head_info(void)
{
- for_each_ref(show_ref, NULL);
+ for_each_ref(show_ref_cb, NULL);
if (!sent_capabilities)
show_ref("capabilities^{}", null_sha1, 0, NULL);
static const char *update(struct command *cmd)
{
const char *name = cmd->ref_name;
+ struct strbuf namespaced_name_buf = STRBUF_INIT;
+ const char *namespaced_name;
unsigned char *old_sha1 = cmd->old_sha1;
unsigned char *new_sha1 = cmd->new_sha1;
struct ref_lock *lock;
return "funny refname";
}
- if (is_ref_checked_out(name)) {
+ strbuf_addf(&namespaced_name_buf, "%s%s", get_git_namespace(), name);
+ namespaced_name = strbuf_detach(&namespaced_name_buf, NULL);
+
+ if (is_ref_checked_out(namespaced_name)) {
switch (deny_current_branch) {
case DENY_IGNORE:
break;
return "deletion prohibited";
}
- if (!strcmp(name, head_name)) {
+ if (!strcmp(namespaced_name, head_name)) {
switch (deny_delete_current) {
case DENY_IGNORE:
break;
rp_warning("Allowing deletion of corrupt ref.");
old_sha1 = NULL;
}
- if (delete_ref(name, old_sha1, 0)) {
+ if (delete_ref(namespaced_name, old_sha1, 0)) {
rp_error("failed to delete %s", name);
return "failed to delete";
}
return NULL; /* good */
}
else {
- lock = lock_any_ref_for_update(name, old_sha1, 0);
+ lock = lock_any_ref_for_update(namespaced_name, old_sha1, 0);
if (!lock) {
rp_error("failed to lock %s", name);
return "failed to lock";
static void check_aliased_update(struct command *cmd, struct string_list *list)
{
+ struct strbuf buf = STRBUF_INIT;
+ const char *dst_name;
struct string_list_item *item;
struct command *dst_cmd;
unsigned char sha1[20];
char cmd_oldh[41], cmd_newh[41], dst_oldh[41], dst_newh[41];
int flag;
- const char *dst_name = resolve_ref(cmd->ref_name, sha1, 0, &flag);
+ strbuf_addf(&buf, "%s%s", get_git_namespace(), cmd->ref_name);
+ dst_name = resolve_ref(buf.buf, sha1, 0, &flag);
+ strbuf_release(&buf);
if (!(flag & REF_ISSYMREF))
return;
+ dst_name = strip_namespace(dst_name);
+ if (!dst_name) {
+ rp_error("refusing update to broken symref '%s'", cmd->ref_name);
+ cmd->skip_update = 1;
+ cmd->error_string = "broken symref";
+ return;
+ }
+
if ((item = string_list_lookup(list, dst_name)) == NULL)
return;
string_list_clear(&ref_list, 0);
}
+static int command_singleton_iterator(void *cb_data, unsigned char sha1[20])
+{
+ struct command **cmd_list = cb_data;
+ struct command *cmd = *cmd_list;
+
+ if (!cmd)
+ return -1; /* end of list */
+ *cmd_list = NULL; /* this returns only one */
+ hashcpy(sha1, cmd->new_sha1);
+ return 0;
+}
+
+static void set_connectivity_errors(struct command *commands)
+{
+ struct command *cmd;
+
+ for (cmd = commands; cmd; cmd = cmd->next) {
+ struct command *singleton = cmd;
+ if (!check_everything_connected(command_singleton_iterator,
+ 0, &singleton))
+ continue;
+ cmd->error_string = "missing necessary objects";
+ }
+}
+
+static int iterate_receive_command_list(void *cb_data, unsigned char sha1[20])
+{
+ struct command **cmd_list = cb_data;
+ struct command *cmd = *cmd_list;
+
+ if (!cmd)
+ return -1; /* end of list */
+ *cmd_list = cmd->next;
+ hashcpy(sha1, cmd->new_sha1);
+ return 0;
+}
+
static void execute_commands(struct command *commands, const char *unpacker_error)
{
struct command *cmd;
@@ -557,6 +634,11 @@ static void execute_commands(struct command *commands, const char *unpacker_erro
return;
}
+ cmd = commands;
+ if (check_everything_connected(iterate_receive_command_list,
+ 0, &cmd))
+ set_connectivity_errors(commands);
+
if (run_receive_hook(commands, pre_receive_hook)) {
for (cmd = commands; cmd; cmd = cmd->next)
cmd->error_string = "pre-receive hook declined";
static const char *pack_lockfile;
-static const char *unpack(int quiet)
+static const char *unpack(void)
{
struct pack_header hdr;
const char *hdr_err;
char hdr_arg[38];
+ int fsck_objects = (receive_fsck_objects >= 0
+ ? receive_fsck_objects
+ : transfer_fsck_objects >= 0
+ ? transfer_fsck_objects
+ : 0);
hdr_err = parse_pack_header(&hdr);
if (hdr_err)
if (ntohl(hdr.hdr_entries) < unpack_limit) {
int code, i = 0;
- const char *unpacker[5];
+ const char *unpacker[4];
unpacker[i++] = "unpack-objects";
- if (quiet)
- unpacker[i++] = "-q";
- if (receive_fsck_objects)
+ if (fsck_objects)
unpacker[i++] = "--strict";
unpacker[i++] = hdr_arg;
unpacker[i++] = NULL;
keeper[i++] = "index-pack";
keeper[i++] = "--stdin";
- if (receive_fsck_objects)
+ if (fsck_objects)
keeper[i++] = "--strict";
keeper[i++] = "--fix-thin";
keeper[i++] = hdr_arg;
int cmd_receive_pack(int argc, const char **argv, const char *prefix)
{
- int quiet = 0;
int advertise_refs = 0;
int stateless_rpc = 0;
int i;
const char *arg = *argv++;
if (*arg == '-') {
- if (!strcmp(arg, "--quiet")) {
- quiet = 1;
- continue;
- }
-
if (!strcmp(arg, "--advertise-refs")) {
advertise_refs = 1;
continue;
const char *unpack_status = NULL;
if (!delete_only(commands))
- unpack_status = unpack(quiet);
+ unpack_status = unpack();
execute_commands(commands, unpack_status);
if (pack_lockfile)
unlink_or_warn(pack_lockfile);