diff options
-rw-r--r-- | Documentation/git-reflog.txt | 5 | ||||
-rw-r--r-- | builtin-reflog.c | 59 | ||||
-rwxr-xr-x | t/t1410-reflog.sh | 26 |
3 files changed, 90 insertions, 0 deletions
diff --git a/Documentation/git-reflog.txt b/Documentation/git-reflog.txt index 5c7316ceb8..a0c7ceead2 100644 --- a/Documentation/git-reflog.txt +++ b/Documentation/git-reflog.txt @@ -19,6 +19,8 @@ depending on the subcommand: git reflog expire [--dry-run] [--stale-fix] [--verbose] [--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>... +git reflog delete ref@\{specifier\}... + git reflog [show] [log-options] Reflog is a mechanism to record when the tip of branches are @@ -36,6 +38,9 @@ subcommands) will take all the normal log options, and show the log of It is basically an alias for 'git log -g --abbrev-commit --pretty=oneline', see gitlink:git-log[1]. +To delete single entries from the reflog, use the subcommand "delete" +and specify the _exact_ entry (e.g. ``git reflog delete master@\{2\}''). + OPTIONS ------- 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); } diff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh index e5bbc384f7..12a53edfdc 100755 --- a/t/t1410-reflog.sh +++ b/t/t1410-reflog.sh @@ -175,4 +175,30 @@ test_expect_success 'recover and check' ' ' +test_expect_success 'delete' ' + echo 1 > C && + test_tick && + git commit -m rat C && + + echo 2 > C && + test_tick && + git commit -m ox C && + + echo 3 > C && + test_tick && + git commit -m tiger C && + + test 5 = $(git reflog | wc -l) && + + git reflog delete master@{1} && + git reflog show master > output && + test 4 = $(wc -l < output) && + ! grep ox < output && + + git reflog delete master@{07.04.2005.15:15:00.-0700} && + git reflog show master > output && + test 3 = $(wc -l < output) && + ! grep dragon < output +' + test_done |