summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--reflog-walk.c137
-rw-r--r--reflog-walk.h4
-rw-r--r--revision.c27
-rwxr-xr-xt/t1414-reflog-walk.sh12
-rwxr-xr-xt/t3200-branch.sh3
5 files changed, 75 insertions, 108 deletions
diff --git a/reflog-walk.c b/reflog-walk.c
index 98c2f42de9..fbee9e0126 100644
--- a/reflog-walk.c
+++ b/reflog-walk.c
@@ -94,45 +94,6 @@ static int get_reflog_recno_by_time(struct complete_reflogs *array,
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;
- ALLOC_GROW(lifo->items, lifo->nr + 1, lifo->alloc);
- info = lifo->items + lifo->nr;
- info->commit = commit;
- info->util = util;
- lifo->nr++;
-}
-
struct commit_reflog {
int recno;
enum selector_type {
@@ -144,7 +105,8 @@ struct commit_reflog {
};
struct reflog_walk_info {
- struct commit_info_lifo reflogs;
+ struct commit_reflog **logs;
+ size_t nr, alloc;
struct string_list complete_reflogs;
struct commit_reflog *last_commit_reflog;
};
@@ -233,52 +195,10 @@ int add_reflog_for_walk(struct reflog_walk_info *info,
commit_reflog->selector = selector;
commit_reflog->reflogs = reflogs;
- add_commit_info(commit, commit_reflog, &info->reflogs);
- return 0;
-}
-
-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 object *logobj;
- 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;
- }
- info->last_commit_reflog = commit_reflog;
-
- do {
- reflog = &commit_reflog->reflogs->items[commit_reflog->recno];
- commit_reflog->recno--;
- logobj = parse_object(&reflog->ooid);
- } while (commit_reflog->recno && (logobj && logobj->type != OBJ_COMMIT));
-
- if (!logobj && commit_reflog->recno >= 0 && is_null_oid(&reflog->ooid)) {
- /* a root commit, but there are still more entries to show */
- reflog = &commit_reflog->reflogs->items[commit_reflog->recno];
- logobj = parse_object(&reflog->noid);
- if (!logobj)
- logobj = parse_object(&reflog->ooid);
- }
-
- if (!logobj || logobj->type != OBJ_COMMIT) {
- commit_info->commit = NULL;
- commit->parents = NULL;
- return;
- }
- commit_info->commit = (struct commit *)logobj;
+ ALLOC_GROW(info->logs, info->nr + 1, info->alloc);
+ info->logs[info->nr++] = commit_reflog;
- commit->parents = xcalloc(1, sizeof(struct commit_list));
- commit->parents->item = commit_info->commit;
+ return 0;
}
void get_reflog_selector(struct strbuf *sb,
@@ -368,5 +288,50 @@ void show_reflog_message(struct reflog_walk_info *reflog_info, int oneline,
int reflog_walk_empty(struct reflog_walk_info *info)
{
- return !info || !info->reflogs.nr;
+ return !info || !info->nr;
+}
+
+static struct commit *next_reflog_commit(struct commit_reflog *log)
+{
+ for (; log->recno >= 0; log->recno--) {
+ struct reflog_info *entry = &log->reflogs->items[log->recno];
+ struct object *obj = parse_object(&entry->noid);
+
+ if (obj && obj->type == OBJ_COMMIT)
+ return (struct commit *)obj;
+ }
+ return NULL;
+}
+
+static timestamp_t log_timestamp(struct commit_reflog *log)
+{
+ return log->reflogs->items[log->recno].timestamp;
+}
+
+struct commit *next_reflog_entry(struct reflog_walk_info *walk)
+{
+ struct commit_reflog *best = NULL;
+ struct commit *best_commit = NULL;
+ size_t i;
+
+ for (i = 0; i < walk->nr; i++) {
+ struct commit_reflog *log = walk->logs[i];
+ struct commit *commit = next_reflog_commit(log);
+
+ if (!commit)
+ continue;
+
+ if (!best || log_timestamp(log) > log_timestamp(best)) {
+ best = log;
+ best_commit = commit;
+ }
+ }
+
+ if (best) {
+ best->recno--;
+ walk->last_commit_reflog = best;
+ return best_commit;
+ }
+
+ return NULL;
}
diff --git a/reflog-walk.h b/reflog-walk.h
index af32361072..373388cd14 100644
--- a/reflog-walk.h
+++ b/reflog-walk.h
@@ -8,8 +8,6 @@ struct reflog_walk_info;
extern void init_reflog_walk(struct reflog_walk_info **info);
extern int 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, int,
const struct date_mode *, int force_date);
extern void get_reflog_message(struct strbuf *sb,
@@ -22,4 +20,6 @@ extern void get_reflog_selector(struct strbuf *sb,
extern int reflog_walk_empty(struct reflog_walk_info *walk);
+struct commit *next_reflog_entry(struct reflog_walk_info *reflog_info);
+
#endif
diff --git a/revision.c b/revision.c
index 4019e8cf23..587199739a 100644
--- a/revision.c
+++ b/revision.c
@@ -148,16 +148,14 @@ static void add_pending_object_with_path(struct rev_info *revs,
if (revs->reflog_info && obj->type == OBJ_COMMIT) {
struct strbuf buf = STRBUF_INIT;
int len = interpret_branch_name(name, 0, &buf, 0);
- int st;
if (0 < len && name[len] && buf.len)
strbuf_addstr(&buf, name + len);
- st = add_reflog_for_walk(revs->reflog_info,
- (struct commit *)obj,
- buf.buf[0] ? buf.buf: name);
+ add_reflog_for_walk(revs->reflog_info,
+ (struct commit *)obj,
+ buf.buf[0] ? buf.buf: name);
strbuf_release(&buf);
- if (st)
- return;
+ return; /* do not add the commit itself */
}
add_object_array_with_path(obj, name, &revs->pending, mode, path);
}
@@ -3112,16 +3110,18 @@ static void track_linear(struct rev_info *revs, struct commit *commit)
static struct commit *get_revision_1(struct rev_info *revs)
{
while (1) {
- struct commit *commit = pop_commit(&revs->commits);
+ struct commit *commit;
+
+ if (revs->reflog_info)
+ commit = next_reflog_entry(revs->reflog_info);
+ else
+ commit = pop_commit(&revs->commits);
if (!commit)
return NULL;
- if (revs->reflog_info) {
- save_parents(revs, commit);
- fake_reflog_parent(revs->reflog_info, commit);
+ if (revs->reflog_info)
commit->object.flags &= ~(ADDED | SEEN | SHOWN);
- }
/*
* If we haven't done the list limiting, we need to look at
@@ -3132,7 +3132,10 @@ static struct commit *get_revision_1(struct rev_info *revs)
if (revs->max_age != -1 &&
(commit->date < revs->max_age))
continue;
- if (add_parents_to_list(revs, commit, &revs->commits, NULL) < 0) {
+
+ if (revs->reflog_info)
+ try_to_simplify_commit(revs, commit);
+ else if (add_parents_to_list(revs, commit, &revs->commits, NULL) < 0) {
if (!revs->ignore_missing_links)
die("Failed to traverse parents of commit %s",
oid_to_hex(&commit->object.oid));
diff --git a/t/t1414-reflog-walk.sh b/t/t1414-reflog-walk.sh
index 8bda862ca7..eb10fefd40 100755
--- a/t/t1414-reflog-walk.sh
+++ b/t/t1414-reflog-walk.sh
@@ -34,19 +34,19 @@ test_expect_success 'reflog walk shows expected logs' '
test_cmp expect.all actual
'
-test_expect_failure 'reflog can limit with --no-merges' '
+test_expect_success 'reflog can limit with --no-merges' '
grep -v merge expect.all >expect &&
do_walk --no-merges >actual &&
test_cmp expect actual
'
-test_expect_failure 'reflog can limit with pathspecs' '
+test_expect_success 'reflog can limit with pathspecs' '
grep two expect.all >expect &&
do_walk -- two.t >actual &&
test_cmp expect actual
'
-test_expect_failure 'pathspec limiting handles merges' '
+test_expect_success 'pathspec limiting handles merges' '
# we pick up:
# - the initial commit of one
# - the checkout back to commit one
@@ -56,14 +56,14 @@ test_expect_failure 'pathspec limiting handles merges' '
test_cmp expect actual
'
-test_expect_failure '--parents shows true parents' '
+test_expect_success '--parents shows true parents' '
# convert newlines to spaces
echo $(git rev-parse HEAD HEAD^1 HEAD^2) >expect &&
git rev-list -g --parents -1 HEAD >actual &&
test_cmp expect actual
'
-test_expect_failure 'walking multiple reflogs shows all' '
+test_expect_success 'walking multiple reflogs shows all' '
# We expect to see all entries for all reflogs, but interleaved by
# date, with order on the command line breaking ties. We
# can use "sort" on the separate lists to generate this,
@@ -91,7 +91,7 @@ test_expect_success 'date-limiting does not interfere with other logs' '
test_cmp expect.all actual
'
-test_expect_failure 'walk prefers reflog to ref tip' '
+test_expect_success 'walk prefers reflog to ref tip' '
head=$(git rev-parse HEAD) &&
one=$(git rev-parse one) &&
ident="$GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE" &&
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index dd37ac47c5..9d707d2a40 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -166,10 +166,9 @@ test_expect_success 'resulting reflog can be shown by log -g' '
oid=$(git rev-parse HEAD) &&
cat >expect <<-EOF &&
HEAD@{0} $oid $msg
- HEAD@{1} $oid $msg
HEAD@{2} $oid checkout: moving from foo to baz
EOF
- git log -g --format="%gd %H %gs" -3 HEAD >actual &&
+ git log -g --format="%gd %H %gs" -2 HEAD >actual &&
test_cmp expect actual
'