]> git.ipfire.org Git - thirdparty/git.git/blobdiff - refs.c
fetch: no FETCH_HEAD display if --no-write-fetch-head
[thirdparty/git.git] / refs.c
diff --git a/refs.c b/refs.c
index 224ff66c7bb0ef587cf2b34763586f53ad73bd84..cf91711968019c6a11ad2be81388ed167decebae 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -9,13 +9,15 @@
 #include "iterator.h"
 #include "refs.h"
 #include "refs/refs-internal.h"
+#include "run-command.h"
 #include "object-store.h"
 #include "object.h"
 #include "tag.h"
 #include "submodule.h"
 #include "worktree.h"
-#include "argv-array.h"
+#include "strvec.h"
 #include "repository.h"
+#include "sigchain.h"
 
 /*
  * List of all available backends
@@ -339,7 +341,7 @@ enum peel_status peel_object(const struct object_id *name, struct object_id *oid
 
        if (o->type == OBJ_NONE) {
                int type = oid_object_info(the_repository, name, NULL);
-               if (type < 0 || !object_as_type(the_repository, o, type, 0))
+               if (type < 0 || !object_as_type(o, type, 0))
                        return PEEL_INVALID;
        }
 
@@ -551,13 +553,43 @@ int refname_match(const char *abbrev_name, const char *full_name)
  * Given a 'prefix' expand it by the rules in 'ref_rev_parse_rules' and add
  * the results to 'prefixes'
  */
-void expand_ref_prefix(struct argv_array *prefixes, const char *prefix)
+void expand_ref_prefix(struct strvec *prefixes, const char *prefix)
 {
        const char **p;
        int len = strlen(prefix);
 
        for (p = ref_rev_parse_rules; *p; p++)
-               argv_array_pushf(prefixes, *p, len, prefix);
+               strvec_pushf(prefixes, *p, len, prefix);
+}
+
+char *repo_default_branch_name(struct repository *r)
+{
+       const char *config_key = "init.defaultbranch";
+       const char *config_display_key = "init.defaultBranch";
+       char *ret = NULL, *full_ref;
+
+       if (repo_config_get_string(r, config_key, &ret) < 0)
+               die(_("could not retrieve `%s`"), config_display_key);
+
+       if (!ret)
+               ret = xstrdup("master");
+
+       full_ref = xstrfmt("refs/heads/%s", ret);
+       if (check_refname_format(full_ref, 0))
+               die(_("invalid branch name: %s = %s"), config_display_key, ret);
+       free(full_ref);
+
+       return ret;
+}
+
+const char *git_default_branch_name(void)
+{
+       static char *ret;
+
+       if (!ret)
+               ret = repo_default_branch_name(the_repository);
+
+       return ret;
 }
 
 /*
@@ -676,10 +708,9 @@ int dwim_log(const char *str, int len, struct object_id *oid, char **log)
 
 static int is_per_worktree_ref(const char *refname)
 {
-       return !strcmp(refname, "HEAD") ||
-               starts_with(refname, "refs/worktree/") ||
-               starts_with(refname, "refs/bisect/") ||
-               starts_with(refname, "refs/rewritten/");
+       return starts_with(refname, "refs/worktree/") ||
+              starts_with(refname, "refs/bisect/") ||
+              starts_with(refname, "refs/rewritten/");
 }
 
 static int is_pseudoref_syntax(const char *refname)
@@ -739,102 +770,6 @@ long get_files_ref_lock_timeout_ms(void)
        return timeout_ms;
 }
 
-static int write_pseudoref(const char *pseudoref, const struct object_id *oid,
-                          const struct object_id *old_oid, struct strbuf *err)
-{
-       const char *filename;
-       int fd;
-       struct lock_file lock = LOCK_INIT;
-       struct strbuf buf = STRBUF_INIT;
-       int ret = -1;
-
-       if (!oid)
-               return 0;
-
-       strbuf_addf(&buf, "%s\n", oid_to_hex(oid));
-
-       filename = git_path("%s", pseudoref);
-       fd = hold_lock_file_for_update_timeout(&lock, filename, 0,
-                                              get_files_ref_lock_timeout_ms());
-       if (fd < 0) {
-               strbuf_addf(err, _("could not open '%s' for writing: %s"),
-                           filename, strerror(errno));
-               goto done;
-       }
-
-       if (old_oid) {
-               struct object_id actual_old_oid;
-
-               if (read_ref(pseudoref, &actual_old_oid)) {
-                       if (!is_null_oid(old_oid)) {
-                               strbuf_addf(err, _("could not read ref '%s'"),
-                                           pseudoref);
-                               rollback_lock_file(&lock);
-                               goto done;
-                       }
-               } else if (is_null_oid(old_oid)) {
-                       strbuf_addf(err, _("ref '%s' already exists"),
-                                   pseudoref);
-                       rollback_lock_file(&lock);
-                       goto done;
-               } else if (!oideq(&actual_old_oid, old_oid)) {
-                       strbuf_addf(err, _("unexpected object ID when writing '%s'"),
-                                   pseudoref);
-                       rollback_lock_file(&lock);
-                       goto done;
-               }
-       }
-
-       if (write_in_full(fd, buf.buf, buf.len) < 0) {
-               strbuf_addf(err, _("could not write to '%s'"), filename);
-               rollback_lock_file(&lock);
-               goto done;
-       }
-
-       commit_lock_file(&lock);
-       ret = 0;
-done:
-       strbuf_release(&buf);
-       return ret;
-}
-
-static int delete_pseudoref(const char *pseudoref, const struct object_id *old_oid)
-{
-       const char *filename;
-
-       filename = git_path("%s", pseudoref);
-
-       if (old_oid && !is_null_oid(old_oid)) {
-               struct lock_file lock = LOCK_INIT;
-               int fd;
-               struct object_id actual_old_oid;
-
-               fd = hold_lock_file_for_update_timeout(
-                               &lock, filename, 0,
-                               get_files_ref_lock_timeout_ms());
-               if (fd < 0) {
-                       error_errno(_("could not open '%s' for writing"),
-                                   filename);
-                       return -1;
-               }
-               if (read_ref(pseudoref, &actual_old_oid))
-                       die(_("could not read ref '%s'"), pseudoref);
-               if (!oideq(&actual_old_oid, old_oid)) {
-                       error(_("unexpected object ID when deleting '%s'"),
-                             pseudoref);
-                       rollback_lock_file(&lock);
-                       return -1;
-               }
-
-               unlink(filename);
-               rollback_lock_file(&lock);
-       } else {
-               unlink(filename);
-       }
-
-       return 0;
-}
-
 int refs_delete_ref(struct ref_store *refs, const char *msg,
                    const char *refname,
                    const struct object_id *old_oid,
@@ -843,11 +778,6 @@ int refs_delete_ref(struct ref_store *refs, const char *msg,
        struct ref_transaction *transaction;
        struct strbuf err = STRBUF_INIT;
 
-       if (ref_type(refname) == REF_TYPE_PSEUDOREF) {
-               assert(refs == get_main_ref_store(the_repository));
-               return delete_pseudoref(refname, old_oid);
-       }
-
        transaction = ref_store_transaction_begin(refs, &err);
        if (!transaction ||
            ref_transaction_delete(transaction, refname, old_oid,
@@ -870,12 +800,11 @@ int delete_ref(const char *msg, const char *refname,
                               old_oid, flags);
 }
 
-void copy_reflog_msg(struct strbuf *sb, const char *msg)
+static void copy_reflog_msg(struct strbuf *sb, const char *msg)
 {
        char c;
        int wasspace = 1;
 
-       strbuf_addch(sb, '\t');
        while ((c = *msg++)) {
                if (wasspace && isspace(c))
                        continue;
@@ -887,6 +816,15 @@ void copy_reflog_msg(struct strbuf *sb, const char *msg)
        strbuf_rtrim(sb);
 }
 
+static char *normalize_reflog_message(const char *msg)
+{
+       struct strbuf sb = STRBUF_INIT;
+
+       if (msg && *msg)
+               copy_reflog_msg(&sb, msg);
+       return strbuf_detach(&sb, NULL);
+}
+
 int should_autocreate_reflog(const char *refname)
 {
        switch (log_all_ref_updates) {
@@ -1092,7 +1030,7 @@ struct ref_update *ref_transaction_add_update(
                oidcpy(&update->new_oid, new_oid);
        if (flags & REF_HAVE_OLD)
                oidcpy(&update->old_oid, old_oid);
-       update->msg = xstrdup_or_null(msg);
+       update->msg = normalize_reflog_message(msg);
        return update;
 }
 
@@ -1170,18 +1108,13 @@ int refs_update_ref(struct ref_store *refs, const char *msg,
        struct strbuf err = STRBUF_INIT;
        int ret = 0;
 
-       if (ref_type(refname) == REF_TYPE_PSEUDOREF) {
-               assert(refs == get_main_ref_store(the_repository));
-               ret = write_pseudoref(refname, new_oid, old_oid, &err);
-       } else {
-               t = ref_store_transaction_begin(refs, &err);
-               if (!t ||
-                   ref_transaction_update(t, refname, new_oid, old_oid,
-                                          flags, msg, &err) ||
-                   ref_transaction_commit(t, &err)) {
-                       ret = 1;
-                       ref_transaction_free(t);
-               }
+       t = ref_store_transaction_begin(refs, &err);
+       if (!t ||
+           ref_transaction_update(t, refname, new_oid, old_oid, flags, msg,
+                                  &err) ||
+           ref_transaction_commit(t, &err)) {
+               ret = 1;
+               ref_transaction_free(t);
        }
        if (ret) {
                const char *str = _("update_ref failed for ref '%s': %s");
@@ -1951,9 +1884,14 @@ int refs_create_symref(struct ref_store *refs,
                       const char *refs_heads_master,
                       const char *logmsg)
 {
-       return refs->be->create_symref(refs, ref_target,
-                                      refs_heads_master,
-                                      logmsg);
+       char *msg;
+       int retval;
+
+       msg = normalize_reflog_message(logmsg);
+       retval = refs->be->create_symref(refs, ref_target, refs_heads_master,
+                                        msg);
+       free(msg);
+       return retval;
 }
 
 int create_symref(const char *ref_target, const char *refs_heads_master,
@@ -1986,10 +1924,65 @@ int ref_update_reject_duplicates(struct string_list *refnames,
        return 0;
 }
 
+static const char hook_not_found;
+static const char *hook;
+
+static int run_transaction_hook(struct ref_transaction *transaction,
+                               const char *state)
+{
+       struct child_process proc = CHILD_PROCESS_INIT;
+       struct strbuf buf = STRBUF_INIT;
+       int ret = 0, i;
+
+       if (hook == &hook_not_found)
+               return ret;
+       if (!hook)
+               hook = xstrdup_or_null(find_hook("reference-transaction"));
+       if (!hook) {
+               hook = &hook_not_found;
+               return ret;
+       }
+
+       strvec_pushl(&proc.args, hook, state, NULL);
+       proc.in = -1;
+       proc.stdout_to_stderr = 1;
+       proc.trace2_hook_name = "reference-transaction";
+
+       ret = start_command(&proc);
+       if (ret)
+               return ret;
+
+       sigchain_push(SIGPIPE, SIG_IGN);
+
+       for (i = 0; i < transaction->nr; i++) {
+               struct ref_update *update = transaction->updates[i];
+
+               strbuf_reset(&buf);
+               strbuf_addf(&buf, "%s %s %s\n",
+                           oid_to_hex(&update->old_oid),
+                           oid_to_hex(&update->new_oid),
+                           update->refname);
+
+               if (write_in_full(proc.in, buf.buf, buf.len) < 0) {
+                       if (errno != EPIPE)
+                               ret = -1;
+                       break;
+               }
+       }
+
+       close(proc.in);
+       sigchain_pop(SIGPIPE);
+       strbuf_release(&buf);
+
+       ret |= finish_command(&proc);
+       return ret;
+}
+
 int ref_transaction_prepare(struct ref_transaction *transaction,
                            struct strbuf *err)
 {
        struct ref_store *refs = transaction->ref_store;
+       int ret;
 
        switch (transaction->state) {
        case REF_TRANSACTION_OPEN:
@@ -2012,7 +2005,17 @@ int ref_transaction_prepare(struct ref_transaction *transaction,
                return -1;
        }
 
-       return refs->be->transaction_prepare(refs, transaction, err);
+       ret = refs->be->transaction_prepare(refs, transaction, err);
+       if (ret)
+               return ret;
+
+       ret = run_transaction_hook(transaction, "prepared");
+       if (ret) {
+               ref_transaction_abort(transaction, err);
+               die(_("ref updates aborted by hook"));
+       }
+
+       return 0;
 }
 
 int ref_transaction_abort(struct ref_transaction *transaction,
@@ -2036,6 +2039,8 @@ int ref_transaction_abort(struct ref_transaction *transaction,
                break;
        }
 
+       run_transaction_hook(transaction, "aborted");
+
        ref_transaction_free(transaction);
        return ret;
 }
@@ -2064,7 +2069,10 @@ int ref_transaction_commit(struct ref_transaction *transaction,
                break;
        }
 
-       return refs->be->transaction_finish(refs, transaction, err);
+       ret = refs->be->transaction_finish(refs, transaction, err);
+       if (!ret)
+               run_transaction_hook(transaction, "committed");
+       return ret;
 }
 
 int refs_verify_refname_available(struct ref_store *refs,
@@ -2268,10 +2276,16 @@ int initial_ref_transaction_commit(struct ref_transaction *transaction,
        return refs->be->initial_transaction_commit(refs, transaction, err);
 }
 
-int refs_delete_refs(struct ref_store *refs, const char *msg,
+int refs_delete_refs(struct ref_store *refs, const char *logmsg,
                     struct string_list *refnames, unsigned int flags)
 {
-       return refs->be->delete_refs(refs, msg, refnames, flags);
+       char *msg;
+       int retval;
+
+       msg = normalize_reflog_message(logmsg);
+       retval = refs->be->delete_refs(refs, msg, refnames, flags);
+       free(msg);
+       return retval;
 }
 
 int delete_refs(const char *msg, struct string_list *refnames,
@@ -2283,7 +2297,13 @@ int delete_refs(const char *msg, struct string_list *refnames,
 int refs_rename_ref(struct ref_store *refs, const char *oldref,
                    const char *newref, const char *logmsg)
 {
-       return refs->be->rename_ref(refs, oldref, newref, logmsg);
+       char *msg;
+       int retval;
+
+       msg = normalize_reflog_message(logmsg);
+       retval = refs->be->rename_ref(refs, oldref, newref, msg);
+       free(msg);
+       return retval;
 }
 
 int rename_ref(const char *oldref, const char *newref, const char *logmsg)
@@ -2294,7 +2314,13 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg)
 int refs_copy_existing_ref(struct ref_store *refs, const char *oldref,
                    const char *newref, const char *logmsg)
 {
-       return refs->be->copy_ref(refs, oldref, newref, logmsg);
+       char *msg;
+       int retval;
+
+       msg = normalize_reflog_message(logmsg);
+       retval = refs->be->copy_ref(refs, oldref, newref, msg);
+       free(msg);
+       return retval;
 }
 
 int copy_existing_ref(const char *oldref, const char *newref, const char *logmsg)