gitweb: Use git-for-each-ref to generate list of heads and/or tags
[gitweb.git] / receive-pack.c
index f0b4cb47c78434a27faaedaeac030d9ce1187edd..de1d6a4b1c3f51f8763484b6efea0a8ccd289bb3 100644 (file)
@@ -2,16 +2,32 @@
 #include "refs.h"
 #include "pkt-line.h"
 #include "run-command.h"
+#include "commit.h"
+#include "object.h"
 
 static const char receive_pack_usage[] = "git-receive-pack <git-dir>";
 
 static const char *unpacker[] = { "unpack-objects", NULL };
 
+static int deny_non_fast_forwards = 0;
 static int report_status;
 
 static char capabilities[] = "report-status";
 static int capabilities_sent;
 
+static int receive_pack_config(const char *var, const char *value)
+{
+       git_default_config(var, value);
+
+       if (strcmp(var, "receive.denynonfastforwards") == 0)
+       {
+               deny_non_fast_forwards = git_config_bool(var, value);
+               return 0;
+       }
+
+       return 0;
+}
+
 static int show_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
 {
        if (capabilities_sent)
@@ -94,6 +110,21 @@ static int update(struct command *cmd)
                return error("unpack should have generated %s, "
                             "but I can't find it!", new_hex);
        }
+       if (deny_non_fast_forwards && !is_null_sha1(old_sha1)) {
+               struct commit *old_commit, *new_commit;
+               struct commit_list *bases, *ent;
+
+               old_commit = (struct commit *)parse_object(old_sha1);
+               new_commit = (struct commit *)parse_object(new_sha1);
+               bases = get_merge_bases(old_commit, new_commit, 1);
+               for (ent = bases; ent; ent = ent->next)
+                       if (!hashcmp(old_sha1, ent->item->object.sha1))
+                               break;
+               free_commit_list(bases);
+               if (!ent)
+                       return error("denying non-fast forward;"
+                                    " you should pull first");
+       }
        if (run_update_hook(name, old_hex, new_hex)) {
                cmd->error_string = "hook declined";
                return error("hook declined to update %s", name);
@@ -261,7 +292,8 @@ int main(int argc, char **argv)
        if (!enter_repo(dir, 0))
                die("'%s': unable to chdir or not a git archive", dir);
 
-       git_config(git_default_config);
+       setup_ident();
+       git_config(receive_pack_config);
 
        write_head_info();