stash: convert pop to builtin
[gitweb.git] / builtin / reflog.c
index a48984d37e4f5f9e1f07a840582f82e202bd09f0..7a85e4b1640b12d4c8f7958cb59b66e037fd2ce2 100644 (file)
@@ -1,6 +1,8 @@
 #include "builtin.h"
 #include "config.h"
 #include "lockfile.h"
+#include "object-store.h"
+#include "repository.h"
 #include "commit.h"
 #include "refs.h"
 #include "dir.h"
@@ -8,6 +10,7 @@
 #include "diff.h"
 #include "revision.h"
 #include "reachable.h"
+#include "worktree.h"
 
 /* NEEDSWORK: switch to using parse_options */
 static const char reflog_expire_usage[] =
@@ -50,6 +53,7 @@ struct collect_reflog_cb {
        struct collected_reflog **e;
        int alloc;
        int nr;
+       struct worktree *wt;
 };
 
 /* Remember to update object flag allocation in object.h */
@@ -64,7 +68,7 @@ static int tree_is_complete(const struct object_id *oid)
        int complete;
        struct tree *tree;
 
-       tree = lookup_tree(oid);
+       tree = lookup_tree(the_repository, oid);
        if (!tree)
                return 0;
        if (tree->object.flags & SEEN)
@@ -128,7 +132,7 @@ static int commit_is_complete(struct commit *commit)
                struct commit_list *parent;
 
                c = (struct commit *)object_array_pop(&study);
-               if (!c->object.parsed && !parse_object(&c->object.oid))
+               if (!c->object.parsed && !parse_object(the_repository, &c->object.oid))
                        c->object.flags |= INCOMPLETE;
 
                if (c->object.flags & INCOMPLETE) {
@@ -194,7 +198,7 @@ static int keep_entry(struct commit **it, struct object_id *oid)
 
        if (is_null_oid(oid))
                return 1;
-       commit = lookup_commit_reference_gently(oid, 1);
+       commit = lookup_commit_reference_gently(the_repository, oid, 1);
        if (!commit)
                return 0;
 
@@ -263,7 +267,8 @@ static int unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit
                if (is_null_oid(oid))
                        return 0;
 
-               commit = lookup_commit_reference_gently(oid, 1);
+               commit = lookup_commit_reference_gently(the_repository, oid,
+                                                       1);
 
                /* Not a commit -- keep it */
                if (!commit)
@@ -320,24 +325,39 @@ static int push_tip_to_list(const char *refname, const struct object_id *oid,
        struct commit *tip_commit;
        if (flags & REF_ISSYMREF)
                return 0;
-       tip_commit = lookup_commit_reference_gently(oid, 1);
+       tip_commit = lookup_commit_reference_gently(the_repository, oid, 1);
        if (!tip_commit)
                return 0;
        commit_list_insert(tip_commit, list);
        return 0;
 }
 
+static int is_head(const char *refname)
+{
+       switch (ref_type(refname)) {
+       case REF_TYPE_OTHER_PSEUDOREF:
+       case REF_TYPE_MAIN_PSEUDOREF:
+               if (parse_worktree_ref(refname, NULL, NULL, &refname))
+                       BUG("not a worktree ref: %s", refname);
+               break;
+       default:
+               break;
+       }
+       return !strcmp(refname, "HEAD");
+}
+
 static void reflog_expiry_prepare(const char *refname,
                                  const struct object_id *oid,
                                  void *cb_data)
 {
        struct expire_reflog_policy_cb *cb = cb_data;
 
-       if (!cb->cmd.expire_unreachable || !strcmp(refname, "HEAD")) {
+       if (!cb->cmd.expire_unreachable || is_head(refname)) {
                cb->tip_commit = NULL;
                cb->unreachable_expire_kind = UE_HEAD;
        } else {
-               cb->tip_commit = lookup_commit_reference_gently(oid, 1);
+               cb->tip_commit = lookup_commit_reference_gently(the_repository,
+                                                               oid, 1);
                if (!cb->tip_commit)
                        cb->unreachable_expire_kind = UE_ALWAYS;
                else
@@ -384,8 +404,19 @@ static int collect_reflog(const char *ref, const struct object_id *oid, int unus
 {
        struct collected_reflog *e;
        struct collect_reflog_cb *cb = cb_data;
+       struct strbuf newref = STRBUF_INIT;
+
+       /*
+        * Avoid collecting the same shared ref multiple times because
+        * they are available via all worktrees.
+        */
+       if (!cb->wt->is_current && ref_type(ref) == REF_TYPE_NORMAL)
+               return 0;
+
+       strbuf_worktree_ref(cb->wt, &newref, ref);
+       FLEX_ALLOC_STR(e, reflog, newref.buf);
+       strbuf_release(&newref);
 
-       FLEX_ALLOC_STR(e, reflog, ref);
        oidcpy(&e->oid, oid);
        ALLOC_GROW(cb->e, cb->nr + 1, cb->alloc);
        cb->e[cb->nr++] = e;
@@ -508,7 +539,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
 {
        struct expire_reflog_policy_cb cb;
        timestamp_t now = time(NULL);
-       int i, status, do_all;
+       int i, status, do_all, all_worktrees = 1;
        int explicit_expiry = 0;
        unsigned int flags = 0;
 
@@ -545,6 +576,8 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
                        flags |= EXPIRE_REFLOGS_UPDATE_REF;
                else if (!strcmp(arg, "--all"))
                        do_all = 1;
+               else if (!strcmp(arg, "--single-worktree"))
+                       all_worktrees = 0;
                else if (!strcmp(arg, "--verbose"))
                        flags |= EXPIRE_REFLOGS_VERBOSE;
                else if (!strcmp(arg, "--")) {
@@ -563,7 +596,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
         * from reflog if the repository was pruned with older git.
         */
        if (cb.cmd.stalefix) {
-               init_revisions(&cb.cmd.revs, prefix);
+               repo_init_revisions(the_repository, &cb.cmd.revs, prefix);
                if (flags & EXPIRE_REFLOGS_VERBOSE)
                        printf("Marking reachable objects...");
                mark_reachable_objects(&cb.cmd.revs, 0, 0, NULL);
@@ -573,10 +606,19 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
 
        if (do_all) {
                struct collect_reflog_cb collected;
+               struct worktree **worktrees, **p;
                int i;
 
                memset(&collected, 0, sizeof(collected));
-               for_each_reflog(collect_reflog, &collected);
+               worktrees = get_worktrees(0);
+               for (p = worktrees; *p; p++) {
+                       if (!all_worktrees && !(*p)->is_current)
+                               continue;
+                       collected.wt = *p;
+                       refs_for_each_reflog(get_worktree_ref_store(*p),
+                                            collect_reflog, &collected);
+               }
+               free_worktrees(worktrees);
                for (i = 0; i < collected.nr; i++) {
                        struct collected_reflog *e = collected.e[i];
                        set_reflog_expiry_param(&cb.cmd, explicit_expiry, e->reflog);