Teach the revision walker to walk by reflogs with --walk-reflogs
When called with "--walk-reflogs", as long as there are reflogs available, the walker will take this information into account, rather than the parent information in the commit object. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <junkio@cox.net>
This commit is contained in:
parent
bcf3161876
commit
8860fd42fc
2
Makefile
2
Makefile
@ -254,7 +254,7 @@ LIB_OBJS = \
|
|||||||
interpolate.o \
|
interpolate.o \
|
||||||
lockfile.o \
|
lockfile.o \
|
||||||
object.o pack-check.o patch-delta.o path.o pkt-line.o sideband.o \
|
object.o pack-check.o patch-delta.o path.o pkt-line.o sideband.o \
|
||||||
reachable.o \
|
reachable.o reflog-walk.o \
|
||||||
quote.o read-cache.o refs.o run-command.o dir.o object-refs.o \
|
quote.o read-cache.o refs.o run-command.o dir.o object-refs.o \
|
||||||
server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
|
server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
|
||||||
tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
|
tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include "diff.h"
|
#include "diff.h"
|
||||||
#include "commit.h"
|
#include "commit.h"
|
||||||
#include "log-tree.h"
|
#include "log-tree.h"
|
||||||
|
#include "reflog-walk.h"
|
||||||
|
|
||||||
static void show_parents(struct commit *commit, int abbrev)
|
static void show_parents(struct commit *commit, int abbrev)
|
||||||
{
|
{
|
||||||
@ -223,6 +224,8 @@ void show_log(struct rev_info *opt, const char *sep)
|
|||||||
printf("%s",
|
printf("%s",
|
||||||
diff_get_color(opt->diffopt.color_diff, DIFF_RESET));
|
diff_get_color(opt->diffopt.color_diff, DIFF_RESET));
|
||||||
putchar(opt->commit_format == CMIT_FMT_ONELINE ? ' ' : '\n');
|
putchar(opt->commit_format == CMIT_FMT_ONELINE ? ' ' : '\n');
|
||||||
|
if (opt->reflog_info)
|
||||||
|
show_reflog_message(opt->reflog_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
235
reflog-walk.c
Normal file
235
reflog-walk.c
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
#include "cache.h"
|
||||||
|
#include "commit.h"
|
||||||
|
#include "refs.h"
|
||||||
|
#include "diff.h"
|
||||||
|
#include "revision.h"
|
||||||
|
#include "path-list.h"
|
||||||
|
|
||||||
|
struct complete_reflogs {
|
||||||
|
char *ref;
|
||||||
|
struct reflog_info {
|
||||||
|
unsigned char osha1[20], nsha1[20];
|
||||||
|
char *email;
|
||||||
|
unsigned long timestamp;
|
||||||
|
int tz;
|
||||||
|
char *message;
|
||||||
|
} *items;
|
||||||
|
int nr, alloc;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int read_one_reflog(unsigned char *osha1, unsigned char *nsha1,
|
||||||
|
const char *email, unsigned long timestamp, int tz,
|
||||||
|
const char *message, void *cb_data)
|
||||||
|
{
|
||||||
|
struct complete_reflogs *array = cb_data;
|
||||||
|
struct reflog_info *item;
|
||||||
|
|
||||||
|
if (array->nr >= array->alloc) {
|
||||||
|
array->alloc = alloc_nr(array->nr + 1);
|
||||||
|
array->items = xrealloc(array->items, array->alloc *
|
||||||
|
sizeof(struct reflog_info));
|
||||||
|
}
|
||||||
|
item = array->items + array->nr;
|
||||||
|
memcpy(item->osha1, osha1, 20);
|
||||||
|
memcpy(item->nsha1, nsha1, 20);
|
||||||
|
item->email = xstrdup(email);
|
||||||
|
item->timestamp = timestamp;
|
||||||
|
item->tz = tz;
|
||||||
|
item->message = xstrdup(message);
|
||||||
|
array->nr++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct complete_reflogs *read_complete_reflog(const char *ref)
|
||||||
|
{
|
||||||
|
struct complete_reflogs *reflogs =
|
||||||
|
xcalloc(sizeof(struct complete_reflogs), 1);
|
||||||
|
reflogs->ref = xstrdup(ref);
|
||||||
|
for_each_reflog_ent(ref, read_one_reflog, reflogs);
|
||||||
|
if (reflogs->nr == 0) {
|
||||||
|
unsigned char sha1[20];
|
||||||
|
const char *name = resolve_ref(ref, sha1, 1, NULL);
|
||||||
|
if (name)
|
||||||
|
for_each_reflog_ent(name, read_one_reflog, reflogs);
|
||||||
|
}
|
||||||
|
if (reflogs->nr == 0) {
|
||||||
|
int len = strlen(ref);
|
||||||
|
char *refname = xmalloc(len + 12);
|
||||||
|
sprintf(refname, "refs/%s", ref);
|
||||||
|
for_each_reflog_ent(refname, read_one_reflog, reflogs);
|
||||||
|
if (reflogs->nr == 0) {
|
||||||
|
sprintf(refname, "refs/heads/%s", ref);
|
||||||
|
for_each_reflog_ent(refname, read_one_reflog, reflogs);
|
||||||
|
}
|
||||||
|
free(refname);
|
||||||
|
}
|
||||||
|
return reflogs;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_reflog_recno_by_time(struct complete_reflogs *array,
|
||||||
|
unsigned long timestamp)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = array->nr - 1; i >= 0; i++)
|
||||||
|
if (timestamp >= array->items[i].timestamp)
|
||||||
|
return i;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct commit_info_lifo {
|
||||||
|
struct commit_info {
|
||||||
|
struct commit *commit;
|
||||||
|
void *util;
|
||||||
|
} *items;
|
||||||
|
int nr, alloc;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct commit_info *get_commit_info(struct commit *commit,
|
||||||
|
struct commit_info_lifo *lifo, int pop)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < lifo->nr; i++)
|
||||||
|
if (lifo->items[i].commit == commit) {
|
||||||
|
struct commit_info *result = &lifo->items[i];
|
||||||
|
if (pop) {
|
||||||
|
if (i + 1 < lifo->nr)
|
||||||
|
memmove(lifo->items + i,
|
||||||
|
lifo->items + i + 1,
|
||||||
|
(lifo->nr - i) *
|
||||||
|
sizeof(struct commit_info));
|
||||||
|
lifo->nr--;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_commit_info(struct commit *commit, void *util,
|
||||||
|
struct commit_info_lifo *lifo)
|
||||||
|
{
|
||||||
|
struct commit_info *info;
|
||||||
|
if (lifo->nr >= lifo->alloc) {
|
||||||
|
lifo->alloc = alloc_nr(lifo->nr + 1);
|
||||||
|
lifo->items = xrealloc(lifo->items,
|
||||||
|
lifo->alloc * sizeof(struct commit_info));
|
||||||
|
}
|
||||||
|
info = lifo->items + lifo->nr;
|
||||||
|
info->commit = commit;
|
||||||
|
info->util = util;
|
||||||
|
lifo->nr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct commit_reflog {
|
||||||
|
int flag, recno;
|
||||||
|
struct complete_reflogs *reflogs;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct reflog_walk_info {
|
||||||
|
struct commit_info_lifo reflogs;
|
||||||
|
struct path_list complete_reflogs;
|
||||||
|
struct commit_reflog *last_commit_reflog;
|
||||||
|
};
|
||||||
|
|
||||||
|
void init_reflog_walk(struct reflog_walk_info** info)
|
||||||
|
{
|
||||||
|
*info = xcalloc(sizeof(struct reflog_walk_info), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_reflog_for_walk(struct reflog_walk_info *info,
|
||||||
|
struct commit *commit, const char *name)
|
||||||
|
{
|
||||||
|
unsigned long timestamp = 0;
|
||||||
|
int recno = -1;
|
||||||
|
struct path_list_item *item;
|
||||||
|
struct complete_reflogs *reflogs;
|
||||||
|
char *branch, *at = strchr(name, '@');
|
||||||
|
struct commit_reflog *commit_reflog;
|
||||||
|
|
||||||
|
branch = xstrdup(name);
|
||||||
|
if (at && at[1] == '{') {
|
||||||
|
char *ep;
|
||||||
|
branch[at - name] = '\0';
|
||||||
|
recno = strtoul(at + 2, &ep, 10);
|
||||||
|
if (*ep != '}') {
|
||||||
|
recno = -1;
|
||||||
|
timestamp = approxidate(at + 2);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
recno = 0;
|
||||||
|
|
||||||
|
item = path_list_lookup(branch, &info->complete_reflogs);
|
||||||
|
if (item)
|
||||||
|
reflogs = item->util;
|
||||||
|
else {
|
||||||
|
reflogs = read_complete_reflog(branch);
|
||||||
|
if (!reflogs || reflogs->nr == 0)
|
||||||
|
die("No reflogs found for '%s'", branch);
|
||||||
|
path_list_insert(branch, &info->complete_reflogs)->util
|
||||||
|
= reflogs;
|
||||||
|
}
|
||||||
|
|
||||||
|
commit_reflog = xcalloc(sizeof(struct commit_reflog), 1);
|
||||||
|
if (recno < 0) {
|
||||||
|
commit_reflog->flag = 1;
|
||||||
|
commit_reflog->recno = get_reflog_recno_by_time(reflogs, timestamp);
|
||||||
|
if (commit_reflog->recno < 0) {
|
||||||
|
free(branch);
|
||||||
|
free(commit_reflog);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
commit_reflog->recno = reflogs->nr - recno - 1;
|
||||||
|
commit_reflog->reflogs = reflogs;
|
||||||
|
|
||||||
|
add_commit_info(commit, commit_reflog, &info->reflogs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fake_reflog_parent(struct reflog_walk_info *info, struct commit *commit)
|
||||||
|
{
|
||||||
|
struct commit_info *commit_info =
|
||||||
|
get_commit_info(commit, &info->reflogs, 0);
|
||||||
|
struct commit_reflog *commit_reflog;
|
||||||
|
struct reflog_info *reflog;
|
||||||
|
|
||||||
|
info->last_commit_reflog = NULL;
|
||||||
|
if (!commit_info)
|
||||||
|
return;
|
||||||
|
|
||||||
|
commit_reflog = commit_info->util;
|
||||||
|
if (commit_reflog->recno < 0) {
|
||||||
|
commit->parents = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
reflog = &commit_reflog->reflogs->items[commit_reflog->recno];
|
||||||
|
info->last_commit_reflog = commit_reflog;
|
||||||
|
commit_reflog->recno--;
|
||||||
|
commit_info->commit = (struct commit *)parse_object(reflog->osha1);
|
||||||
|
if (!commit_info->commit) {
|
||||||
|
commit->parents = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
commit->parents = xcalloc(sizeof(struct commit_list), 1);
|
||||||
|
commit->parents->item = commit_info->commit;
|
||||||
|
commit->object.flags &= ~(ADDED | SEEN | SHOWN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void show_reflog_message(struct reflog_walk_info* info)
|
||||||
|
{
|
||||||
|
if (info && info->last_commit_reflog) {
|
||||||
|
struct commit_reflog *commit_reflog = info->last_commit_reflog;
|
||||||
|
struct reflog_info *info;
|
||||||
|
|
||||||
|
printf("Reflog: %s@{", commit_reflog->reflogs->ref);
|
||||||
|
info = &commit_reflog->reflogs->items[commit_reflog->recno + 1];
|
||||||
|
if (commit_reflog->flag)
|
||||||
|
printf("%s", show_rfc2822_date(info->timestamp,
|
||||||
|
info->tz));
|
||||||
|
else
|
||||||
|
printf("%d", commit_reflog->reflogs->nr
|
||||||
|
- 2 - commit_reflog->recno);
|
||||||
|
printf("} (%s)\nReflog message: %s",
|
||||||
|
info->email, info->message);
|
||||||
|
}
|
||||||
|
}
|
11
reflog-walk.h
Normal file
11
reflog-walk.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef REFLOG_WALK_H
|
||||||
|
#define REFLOG_WALK_H
|
||||||
|
|
||||||
|
extern void init_reflog_walk(struct reflog_walk_info** info);
|
||||||
|
extern void add_reflog_for_walk(struct reflog_walk_info *info,
|
||||||
|
struct commit *commit, const char *name);
|
||||||
|
extern void fake_reflog_parent(struct reflog_walk_info *info,
|
||||||
|
struct commit *commit);
|
||||||
|
extern void show_reflog_message(struct reflog_walk_info* info);
|
||||||
|
|
||||||
|
#endif
|
11
revision.c
11
revision.c
@ -7,6 +7,7 @@
|
|||||||
#include "refs.h"
|
#include "refs.h"
|
||||||
#include "revision.h"
|
#include "revision.h"
|
||||||
#include "grep.h"
|
#include "grep.h"
|
||||||
|
#include "reflog-walk.h"
|
||||||
|
|
||||||
static char *path_name(struct name_path *path, const char *name)
|
static char *path_name(struct name_path *path, const char *name)
|
||||||
{
|
{
|
||||||
@ -116,6 +117,9 @@ void mark_parents_uninteresting(struct commit *commit)
|
|||||||
void add_pending_object(struct rev_info *revs, struct object *obj, const char *name)
|
void add_pending_object(struct rev_info *revs, struct object *obj, const char *name)
|
||||||
{
|
{
|
||||||
add_object_array(obj, name, &revs->pending);
|
add_object_array(obj, name, &revs->pending);
|
||||||
|
if (revs->reflog_info && obj->type == OBJ_COMMIT)
|
||||||
|
add_reflog_for_walk(revs->reflog_info,
|
||||||
|
(struct commit *)obj, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct object *get_reference(struct rev_info *revs, const char *name, const unsigned char *sha1, unsigned int flags)
|
static struct object *get_reference(struct rev_info *revs, const char *name, const unsigned char *sha1, unsigned int flags)
|
||||||
@ -864,6 +868,10 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
|
|||||||
handle_reflog(revs, flags);
|
handle_reflog(revs, flags);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (!strcmp(arg, "--walk-reflogs")) {
|
||||||
|
init_reflog_walk(&revs->reflog_info);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (!strcmp(arg, "--not")) {
|
if (!strcmp(arg, "--not")) {
|
||||||
flags ^= UNINTERESTING;
|
flags ^= UNINTERESTING;
|
||||||
continue;
|
continue;
|
||||||
@ -1210,6 +1218,9 @@ static struct commit *get_revision_1(struct rev_info *revs)
|
|||||||
revs->commits = entry->next;
|
revs->commits = entry->next;
|
||||||
free(entry);
|
free(entry);
|
||||||
|
|
||||||
|
if (revs->reflog_info)
|
||||||
|
fake_reflog_parent(revs->reflog_info, commit);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we haven't done the list limiting, we need to look at
|
* If we haven't done the list limiting, we need to look at
|
||||||
* the parents here. We also need to do the date-based limiting
|
* the parents here. We also need to do the date-based limiting
|
||||||
|
@ -89,6 +89,8 @@ struct rev_info {
|
|||||||
|
|
||||||
topo_sort_set_fn_t topo_setter;
|
topo_sort_set_fn_t topo_setter;
|
||||||
topo_sort_get_fn_t topo_getter;
|
topo_sort_get_fn_t topo_getter;
|
||||||
|
|
||||||
|
struct reflog_walk_info *reflog_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define REV_TREE_SAME 0
|
#define REV_TREE_SAME 0
|
||||||
|
Loading…
Reference in New Issue
Block a user