Browse Source

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>
maint
Johannes Schindelin 18 years ago committed by Shawn O. Pearce
parent
commit
552cecc214
  1. 5
      Documentation/git-reflog.txt
  2. 59
      builtin-reflog.c
  3. 26
      t/t1410-reflog.sh

5
Documentation/git-reflog.txt

@ -19,6 +19,8 @@ depending on the subcommand: @@ -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 @@ -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
-------

59
builtin-reflog.c

@ -25,6 +25,7 @@ struct cmd_reflog_expire_cb { @@ -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, @@ -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) @@ -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) @@ -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);
}

26
t/t1410-reflog.sh

@ -175,4 +175,30 @@ test_expect_success 'recover and check' ' @@ -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

Loading…
Cancel
Save