git-hash-object.txt: document --literally option
[gitweb.git] / refs.c
diff --git a/refs.c b/refs.c
index a6b39ec2d7c96be3c307227ea221c4f05f179e45..2ce5d690907d33bda557f66150ef1317f39b4f93 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -24,6 +24,11 @@ static unsigned char refname_disposition[256] = {
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 4, 4
 };
 
+/*
+ * Used as a flag to ref_transaction_delete when a loose ref is being
+ * pruned.
+ */
+#define REF_ISPRUNING  0x0100
 /*
  * Try to read one refname component from the front of refname.
  * Return the length of the component found, or -1 if the component is
@@ -1162,7 +1167,7 @@ static void read_loose_refs(const char *dirname, struct ref_dir *dir)
 
                if (de->d_name[0] == '.')
                        continue;
-               if (has_extension(de->d_name, ".lock"))
+               if (ends_with(de->d_name, ".lock"))
                        continue;
                strbuf_addstr(&refname, de->d_name);
                refdir = *refs->name
@@ -1542,9 +1547,8 @@ static enum peel_status peel_object(const unsigned char *name, unsigned char *sh
 
        if (o->type == OBJ_NONE) {
                int type = sha1_object_info(name, NULL);
-               if (type < 0)
+               if (type < 0 || !object_as_type(o, type, 0))
                        return PEEL_INVALID;
-               o->type = type;
        }
 
        if (o->type != OBJ_TAG)
@@ -2173,15 +2177,6 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
        return NULL;
 }
 
-static struct ref_lock *lock_ref_sha1(const char *refname, const unsigned char *old_sha1)
-{
-       char refpath[PATH_MAX];
-       if (check_refname_format(refname, 0))
-               return NULL;
-       strcpy(refpath, mkpath("refs/%s", refname));
-       return lock_ref_sha1_basic(refpath, old_sha1, 0, NULL);
-}
-
 struct ref_lock *lock_any_ref_for_update(const char *refname,
                                         const unsigned char *old_sha1,
                                         int flags, int *type_p)
@@ -2391,13 +2386,25 @@ static void try_remove_empty_parents(char *name)
 /* make sure nobody touched the ref, and unlink */
 static void prune_ref(struct ref_to_prune *r)
 {
-       struct ref_lock *lock = lock_ref_sha1(r->name + 5, r->sha1);
+       struct ref_transaction *transaction;
+       struct strbuf err = STRBUF_INIT;
 
-       if (lock) {
-               unlink_or_warn(git_path("%s", r->name));
-               unlock_ref(lock);
-               try_remove_empty_parents(r->name);
+       if (check_refname_format(r->name, 0))
+               return;
+
+       transaction = ref_transaction_begin(&err);
+       if (!transaction ||
+           ref_transaction_delete(transaction, r->name, r->sha1,
+                                  REF_ISPRUNING, 1, &err) ||
+           ref_transaction_commit(transaction, NULL, &err)) {
+               ref_transaction_free(transaction);
+               error("%s", err.buf);
+               strbuf_release(&err);
+               return;
        }
+       ref_transaction_free(transaction);
+       strbuf_release(&err);
+       try_remove_empty_parents(r->name);
 }
 
 static void prune_refs(struct ref_to_prune *r)
@@ -2540,11 +2547,6 @@ int repack_without_refs(const char **refnames, int n, struct strbuf *err)
        return ret;
 }
 
-static int repack_without_ref(const char *refname)
-{
-       return repack_without_refs(&refname, 1, NULL);
-}
-
 static int delete_ref_loose(struct ref_lock *lock, int flag)
 {
        if (!(flag & REF_ISPACKED) || flag & REF_ISSYMREF) {
@@ -2562,24 +2564,22 @@ static int delete_ref_loose(struct ref_lock *lock, int flag)
 
 int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
 {
-       struct ref_lock *lock;
-       int ret = 0, flag = 0;
+       struct ref_transaction *transaction;
+       struct strbuf err = STRBUF_INIT;
 
-       lock = lock_ref_sha1_basic(refname, sha1, delopt, &flag);
-       if (!lock)
+       transaction = ref_transaction_begin(&err);
+       if (!transaction ||
+           ref_transaction_delete(transaction, refname, sha1, delopt,
+                                  sha1 && !is_null_sha1(sha1), &err) ||
+           ref_transaction_commit(transaction, NULL, &err)) {
+               error("%s", err.buf);
+               ref_transaction_free(transaction);
+               strbuf_release(&err);
                return 1;
-       ret |= delete_ref_loose(lock, flag);
-
-       /* removing the loose one could have resurrected an earlier
-        * packed one.  Also, if it was not loose we need to repack
-        * without it.
-        */
-       ret |= repack_without_ref(lock->ref_name);
-
-       unlink_or_warn(git_path("logs/%s", lock->ref_name));
-       clear_loose_ref_cache(&ref_cache);
-       unlock_ref(lock);
-       return ret;
+       }
+       ref_transaction_free(transaction);
+       strbuf_release(&err);
+       return 0;
 }
 
 /*
@@ -2878,7 +2878,7 @@ static int log_ref_write(const char *refname, const unsigned char *old_sha1,
        return 0;
 }
 
-static int is_branch(const char *refname)
+int is_branch(const char *refname)
 {
        return !strcmp(refname, "HEAD") || starts_with(refname, "refs/heads/");
 }
@@ -3301,7 +3301,7 @@ static int do_for_each_reflog(struct strbuf *name, each_ref_fn fn, void *cb_data
 
                if (de->d_name[0] == '.')
                        continue;
-               if (has_extension(de->d_name, ".lock"))
+               if (ends_with(de->d_name, ".lock"))
                        continue;
                strbuf_addstr(name, de->d_name);
                if (stat(git_path("logs/%s", name->buf), &st) < 0) {
@@ -3603,8 +3603,9 @@ int ref_transaction_commit(struct ref_transaction *transaction,
                struct ref_update *update = updates[i];
 
                if (update->lock) {
-                       delnames[delnum++] = update->lock->ref_name;
                        ret |= delete_ref_loose(update->lock, update->type);
+                       if (!(update->flags & REF_ISPRUNING))
+                               delnames[delnum++] = update->lock->ref_name;
                }
        }