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>
This commit is contained in:
Johannes Schindelin 2007-10-17 02:50:45 +01:00 коммит произвёл Shawn O. Pearce
Родитель 207f1a75e7
Коммит 552cecc214
3 изменённых файлов: 90 добавлений и 0 удалений

Просмотреть файл

@ -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
-------

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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