commit_ref_update(): write error message to *err, not stderr
[gitweb.git] / refs / files-backend.c
index 71848ab9d60013023ce1fe09f8f52d1077e7d78a..2d3a8c669a5b04a7e70da881f70e04dc5ba96c5e 100644 (file)
@@ -1477,7 +1477,16 @@ int read_raw_ref(const char *refname, unsigned char *sha1,
 
        /* Is it a directory? */
        if (S_ISDIR(st.st_mode)) {
-               errno = EISDIR;
+               /*
+                * Even though there is a directory where the loose
+                * ref is supposed to be, there could still be a
+                * packed ref:
+                */
+               if (resolve_missing_loose_ref(refname, sha1, flags)) {
+                       errno = EISDIR;
+                       goto out;
+               }
+               ret = 0;
                goto out;
        }
 
@@ -2457,6 +2466,30 @@ static int close_ref(struct ref_lock *lock)
 
 static int commit_ref(struct ref_lock *lock)
 {
+       char *path = get_locked_file_path(lock->lk);
+       struct stat st;
+
+       if (!lstat(path, &st) && S_ISDIR(st.st_mode)) {
+               /*
+                * There is a directory at the path we want to rename
+                * the lockfile to. Hopefully it is empty; try to
+                * delete it.
+                */
+               size_t len = strlen(path);
+               struct strbuf sb_path = STRBUF_INIT;
+
+               strbuf_attach(&sb_path, path, len, len);
+
+               /*
+                * If this fails, commit_lock_file() will also fail
+                * and will report the problem.
+                */
+               remove_empty_directories(&sb_path);
+               strbuf_release(&sb_path);
+       } else {
+               free(path);
+       }
+
        if (commit_lock_file(lock->lk))
                return -1;
        return 0;
@@ -2686,7 +2719,7 @@ static int commit_ref_update(struct ref_lock *lock,
                }
        }
        if (commit_ref(lock)) {
-               error("Couldn't set %s", lock->ref_name);
+               strbuf_addf(err, "Couldn't set %s", lock->ref_name);
                unlock_ref(lock);
                return -1;
        }
@@ -2763,6 +2796,42 @@ int create_symref(const char *refname, const char *target, const char *logmsg)
        return ret;
 }
 
+int set_worktree_head_symref(const char *gitdir, const char *target)
+{
+       static struct lock_file head_lock;
+       struct ref_lock *lock;
+       struct strbuf head_path = STRBUF_INIT;
+       const char *head_rel;
+       int ret;
+
+       strbuf_addf(&head_path, "%s/HEAD", absolute_path(gitdir));
+       if (hold_lock_file_for_update(&head_lock, head_path.buf,
+                                     LOCK_NO_DEREF) < 0) {
+               struct strbuf err = STRBUF_INIT;
+               unable_to_lock_message(head_path.buf, errno, &err);
+               error("%s", err.buf);
+               strbuf_release(&err);
+               strbuf_release(&head_path);
+               return -1;
+       }
+
+       /* head_rel will be "HEAD" for the main tree, "worktrees/wt/HEAD" for
+          linked trees */
+       head_rel = remove_leading_path(head_path.buf,
+                                      absolute_path(get_git_common_dir()));
+       /* to make use of create_symref_locked(), initialize ref_lock */
+       lock = xcalloc(1, sizeof(struct ref_lock));
+       lock->lk = &head_lock;
+       lock->ref_name = xstrdup(head_rel);
+       lock->orig_ref_name = xstrdup(head_rel);
+
+       ret = create_symref_locked(lock, head_rel, target, NULL);
+
+       unlock_ref(lock); /* will free lock */
+       strbuf_release(&head_path);
+       return ret;
+}
+
 int reflog_exists(const char *refname)
 {
        struct stat st;
@@ -3314,7 +3383,8 @@ int reflog_expire(const char *refname, const unsigned char *sha1,
         * reference itself, plus we might need to update the
         * reference if --updateref was specified:
         */
-       lock = lock_ref_sha1_basic(refname, sha1, NULL, NULL, 0, &type, &err);
+       lock = lock_ref_sha1_basic(refname, sha1, NULL, NULL, REF_NODEREF,
+                                  &type, &err);
        if (!lock) {
                error("cannot lock ref '%s': %s", refname, err.buf);
                strbuf_release(&err);