summaryrefslogtreecommitdiff
path: root/builtin-reflog.c
diff options
context:
space:
mode:
authorLibravatar Johannes Schindelin <Johannes.Schindelin@gmx.de>2007-10-17 02:50:45 +0100
committerLibravatar Shawn O. Pearce <spearce@spearce.org>2007-10-17 02:54:51 -0400
commit552cecc21447efe9d5f9a86d55b5e428d56a0c53 (patch)
treec6dd9228628bd4db04a50539eee64a18f37c56b5 /builtin-reflog.c
parentgit-svn: simplify the handling of fatal errors (diff)
downloadtgif-552cecc21447efe9d5f9a86d55b5e428d56a0c53.tar.xz
Teach "git reflog" a subcommand to delete single entries
This commit implements the "delete" subcommand: git reflog delete master@{2} will delete the second reflog entry of the "master" branch. With this, it should be easy to implement "git stash pop" everybody seems to want these days. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
Diffstat (limited to 'builtin-reflog.c')
-rw-r--r--builtin-reflog.c59
1 files changed, 59 insertions, 0 deletions
diff --git a/builtin-reflog.c b/builtin-reflog.c
index ce093cad78..f4226939a9 100644
--- a/builtin-reflog.c
+++ b/builtin-reflog.c
@@ -25,6 +25,7 @@ struct cmd_reflog_expire_cb {
int verbose;
unsigned long expire_total;
unsigned long expire_unreachable;
+ int recno;
};
struct expire_reflog_cb {
@@ -220,6 +221,9 @@ static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
goto prune;
}
+ if (cb->cmd->recno && --(cb->cmd->recno) == 0)
+ goto prune;
+
if (cb->newlog) {
char sign = (tz < 0) ? '-' : '+';
int zone = (tz < 0) ? (-tz) : tz;
@@ -363,6 +367,58 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
return status;
}
+static int count_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
+ const char *email, unsigned long timestamp, int tz,
+ const char *message, void *cb_data)
+{
+ struct cmd_reflog_expire_cb *cb = cb_data;
+ if (!cb->expire_total || timestamp < cb->expire_total)
+ cb->recno++;
+ return 0;
+}
+
+static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
+{
+ struct cmd_reflog_expire_cb cb;
+ int i, status = 0;
+
+ if (argc < 2)
+ return error("Nothing to delete?");
+
+ memset(&cb, 0, sizeof(cb));
+
+ for (i = 1; i < argc; i++) {
+ const char *spec = strstr(argv[i], "@{");
+ unsigned char sha1[20];
+ char *ep, *ref;
+ int recno;
+
+ if (!spec) {
+ status |= error("Not a reflog: %s", ref);
+ continue;
+ }
+
+ if (!dwim_ref(argv[i], spec - argv[i], sha1, &ref)) {
+ status |= error("%s points nowhere!", argv[i]);
+ continue;
+ }
+
+ recno = strtoul(spec + 2, &ep, 10);
+ if (*ep == '}') {
+ cb.recno = -recno;
+ for_each_reflog_ent(ref, count_reflog_ent, &cb);
+ } else {
+ cb.expire_total = approxidate(spec + 2);
+ for_each_reflog_ent(ref, count_reflog_ent, &cb);
+ cb.expire_total = 0;
+ }
+
+ status |= expire_reflog(ref, sha1, 0, &cb);
+ free(ref);
+ }
+ return status;
+}
+
/*
* main "reflog"
*/
@@ -382,6 +438,9 @@ int cmd_reflog(int argc, const char **argv, const char *prefix)
if (!strcmp(argv[1], "expire"))
return cmd_reflog_expire(argc - 1, argv + 1, prefix);
+ if (!strcmp(argv[1], "delete"))
+ return cmd_reflog_delete(argc - 1, argv + 1, prefix);
+
/* Not a recognized reflog command..*/
usage(reflog_usage);
}