зеркало из https://github.com/microsoft/git.git
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:
Родитель
207f1a75e7
Коммит
552cecc214
|
@ -19,6 +19,8 @@ depending on the subcommand:
|
||||||
git reflog expire [--dry-run] [--stale-fix] [--verbose]
|
git reflog expire [--dry-run] [--stale-fix] [--verbose]
|
||||||
[--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>...
|
[--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>...
|
||||||
|
|
||||||
|
git reflog delete ref@\{specifier\}...
|
||||||
|
|
||||||
git reflog [show] [log-options]
|
git reflog [show] [log-options]
|
||||||
|
|
||||||
Reflog is a mechanism to record when the tip of branches are
|
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
|
It is basically an alias for 'git log -g --abbrev-commit
|
||||||
--pretty=oneline', see gitlink:git-log[1].
|
--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
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
|
|
|
@ -25,6 +25,7 @@ struct cmd_reflog_expire_cb {
|
||||||
int verbose;
|
int verbose;
|
||||||
unsigned long expire_total;
|
unsigned long expire_total;
|
||||||
unsigned long expire_unreachable;
|
unsigned long expire_unreachable;
|
||||||
|
int recno;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct expire_reflog_cb {
|
struct expire_reflog_cb {
|
||||||
|
@ -220,6 +221,9 @@ static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
|
||||||
goto prune;
|
goto prune;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cb->cmd->recno && --(cb->cmd->recno) == 0)
|
||||||
|
goto prune;
|
||||||
|
|
||||||
if (cb->newlog) {
|
if (cb->newlog) {
|
||||||
char sign = (tz < 0) ? '-' : '+';
|
char sign = (tz < 0) ? '-' : '+';
|
||||||
int zone = (tz < 0) ? (-tz) : tz;
|
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;
|
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"
|
* main "reflog"
|
||||||
*/
|
*/
|
||||||
|
@ -382,6 +438,9 @@ int cmd_reflog(int argc, const char **argv, const char *prefix)
|
||||||
if (!strcmp(argv[1], "expire"))
|
if (!strcmp(argv[1], "expire"))
|
||||||
return cmd_reflog_expire(argc - 1, argv + 1, prefix);
|
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..*/
|
/* Not a recognized reflog command..*/
|
||||||
usage(reflog_usage);
|
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
|
test_done
|
||||||
|
|
Загрузка…
Ссылка в новой задаче