Skip to content

Commit cdd76db

Browse files
committed
Merge branch 'jc/reflog-reverse-walk' into nd/branch-show-rebase-bisect-state
* jc/reflog-reverse-walk: reflog: add for_each_reflog_ent_reverse() API for_each_recent_reflog_ent(): simplify opening of a reflog file for_each_reflog_ent(): extract a helper to process a single entry
2 parents 0722c80 + 98f85ff commit cdd76db

File tree

3 files changed

+134
-77
lines changed

3 files changed

+134
-77
lines changed

refs.c

Lines changed: 115 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2292,69 +2292,138 @@ int read_ref_at(const char *refname, unsigned long at_time, int cnt,
22922292
return 1;
22932293
}
22942294

2295-
int for_each_recent_reflog_ent(const char *refname, each_reflog_ent_fn fn, long ofs, void *cb_data)
2295+
static int show_one_reflog_ent(struct strbuf *sb, each_reflog_ent_fn fn, void *cb_data)
2296+
{
2297+
unsigned char osha1[20], nsha1[20];
2298+
char *email_end, *message;
2299+
unsigned long timestamp;
2300+
int tz;
2301+
2302+
/* old SP new SP name <email> SP time TAB msg LF */
2303+
if (sb->len < 83 || sb->buf[sb->len - 1] != '\n' ||
2304+
get_sha1_hex(sb->buf, osha1) || sb->buf[40] != ' ' ||
2305+
get_sha1_hex(sb->buf + 41, nsha1) || sb->buf[81] != ' ' ||
2306+
!(email_end = strchr(sb->buf + 82, '>')) ||
2307+
email_end[1] != ' ' ||
2308+
!(timestamp = strtoul(email_end + 2, &message, 10)) ||
2309+
!message || message[0] != ' ' ||
2310+
(message[1] != '+' && message[1] != '-') ||
2311+
!isdigit(message[2]) || !isdigit(message[3]) ||
2312+
!isdigit(message[4]) || !isdigit(message[5]))
2313+
return 0; /* corrupt? */
2314+
email_end[1] = '\0';
2315+
tz = strtol(message + 1, NULL, 10);
2316+
if (message[6] != '\t')
2317+
message += 6;
2318+
else
2319+
message += 7;
2320+
return fn(osha1, nsha1, sb->buf + 82, timestamp, tz, message, cb_data);
2321+
}
2322+
2323+
static char *find_beginning_of_line(char *bob, char *scan)
2324+
{
2325+
while (bob < scan && *(--scan) != '\n')
2326+
; /* keep scanning backwards */
2327+
/*
2328+
* Return either beginning of the buffer, or LF at the end of
2329+
* the previous line.
2330+
*/
2331+
return scan;
2332+
}
2333+
2334+
int for_each_reflog_ent_reverse(const char *refname, each_reflog_ent_fn fn, void *cb_data)
22962335
{
2297-
const char *logfile;
2298-
FILE *logfp;
22992336
struct strbuf sb = STRBUF_INIT;
2300-
int ret = 0;
2337+
FILE *logfp;
2338+
long pos;
2339+
int ret = 0, at_tail = 1;
23012340

2302-
logfile = git_path("logs/%s", refname);
2303-
logfp = fopen(logfile, "r");
2341+
logfp = fopen(git_path("logs/%s", refname), "r");
23042342
if (!logfp)
23052343
return -1;
23062344

2307-
if (ofs) {
2308-
struct stat statbuf;
2309-
if (fstat(fileno(logfp), &statbuf) ||
2310-
statbuf.st_size < ofs ||
2311-
fseek(logfp, -ofs, SEEK_END) ||
2312-
strbuf_getwholeline(&sb, logfp, '\n')) {
2313-
fclose(logfp);
2314-
strbuf_release(&sb);
2315-
return -1;
2345+
/* Jump to the end */
2346+
if (fseek(logfp, 0, SEEK_END) < 0)
2347+
return error("cannot seek back reflog for %s: %s",
2348+
refname, strerror(errno));
2349+
pos = ftell(logfp);
2350+
while (!ret && 0 < pos) {
2351+
int cnt;
2352+
size_t nread;
2353+
char buf[BUFSIZ];
2354+
char *endp, *scanp;
2355+
2356+
/* Fill next block from the end */
2357+
cnt = (sizeof(buf) < pos) ? sizeof(buf) : pos;
2358+
if (fseek(logfp, pos - cnt, SEEK_SET))
2359+
return error("cannot seek back reflog for %s: %s",
2360+
refname, strerror(errno));
2361+
nread = fread(buf, cnt, 1, logfp);
2362+
if (nread < 0)
2363+
return error("cannot read %d bytes from reflog for %s: %s",
2364+
cnt, refname, strerror(errno));
2365+
pos -= cnt;
2366+
2367+
scanp = endp = buf + cnt;
2368+
if (at_tail && scanp[-1] == '\n')
2369+
/* Looking at the final LF at the end of the file */
2370+
scanp--;
2371+
at_tail = 0;
2372+
2373+
while (buf < scanp) {
2374+
/*
2375+
* terminating LF of the previous line, or the beginning
2376+
* of the buffer.
2377+
*/
2378+
char *bp;
2379+
2380+
bp = find_beginning_of_line(buf, scanp);
2381+
2382+
if (*bp != '\n') {
2383+
strbuf_splice(&sb, 0, 0, buf, endp - buf);
2384+
if (pos)
2385+
break; /* need to fill another block */
2386+
scanp = buf - 1; /* leave loop */
2387+
} else {
2388+
/*
2389+
* (bp + 1) thru endp is the beginning of the
2390+
* current line we have in sb
2391+
*/
2392+
strbuf_splice(&sb, 0, 0, bp + 1, endp - (bp + 1));
2393+
scanp = bp;
2394+
endp = bp + 1;
2395+
}
2396+
ret = show_one_reflog_ent(&sb, fn, cb_data);
2397+
strbuf_reset(&sb);
2398+
if (ret)
2399+
break;
23162400
}
2317-
}
23182401

2319-
while (!strbuf_getwholeline(&sb, logfp, '\n')) {
2320-
unsigned char osha1[20], nsha1[20];
2321-
char *email_end, *message;
2322-
unsigned long timestamp;
2323-
int tz;
2324-
2325-
/* old SP new SP name <email> SP time TAB msg LF */
2326-
if (sb.len < 83 || sb.buf[sb.len - 1] != '\n' ||
2327-
get_sha1_hex(sb.buf, osha1) || sb.buf[40] != ' ' ||
2328-
get_sha1_hex(sb.buf + 41, nsha1) || sb.buf[81] != ' ' ||
2329-
!(email_end = strchr(sb.buf + 82, '>')) ||
2330-
email_end[1] != ' ' ||
2331-
!(timestamp = strtoul(email_end + 2, &message, 10)) ||
2332-
!message || message[0] != ' ' ||
2333-
(message[1] != '+' && message[1] != '-') ||
2334-
!isdigit(message[2]) || !isdigit(message[3]) ||
2335-
!isdigit(message[4]) || !isdigit(message[5]))
2336-
continue; /* corrupt? */
2337-
email_end[1] = '\0';
2338-
tz = strtol(message + 1, NULL, 10);
2339-
if (message[6] != '\t')
2340-
message += 6;
2341-
else
2342-
message += 7;
2343-
ret = fn(osha1, nsha1, sb.buf + 82, timestamp, tz, message,
2344-
cb_data);
2345-
if (ret)
2346-
break;
23472402
}
2403+
if (!ret && sb.len)
2404+
ret = show_one_reflog_ent(&sb, fn, cb_data);
2405+
23482406
fclose(logfp);
23492407
strbuf_release(&sb);
23502408
return ret;
23512409
}
23522410

23532411
int for_each_reflog_ent(const char *refname, each_reflog_ent_fn fn, void *cb_data)
23542412
{
2355-
return for_each_recent_reflog_ent(refname, fn, 0, cb_data);
2356-
}
2413+
FILE *logfp;
2414+
struct strbuf sb = STRBUF_INIT;
2415+
int ret = 0;
2416+
2417+
logfp = fopen(git_path("logs/%s", refname), "r");
2418+
if (!logfp)
2419+
return -1;
23572420

2421+
while (!ret && !strbuf_getwholeline(&sb, logfp, '\n'))
2422+
ret = show_one_reflog_ent(&sb, fn, cb_data);
2423+
fclose(logfp);
2424+
strbuf_release(&sb);
2425+
return ret;
2426+
}
23582427
/*
23592428
* Call fn for each reflog in the namespace indicated by name. name
23602429
* must be empty or end with '/'. Name will be used as a scratch

refs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ extern int read_ref_at(const char *refname, unsigned long at_time, int cnt,
103103
/* iterate over reflog entries */
104104
typedef int each_reflog_ent_fn(unsigned char *osha1, unsigned char *nsha1, const char *, unsigned long, int, const char *, void *);
105105
int for_each_reflog_ent(const char *refname, each_reflog_ent_fn fn, void *cb_data);
106-
int for_each_recent_reflog_ent(const char *refname, each_reflog_ent_fn fn, long, void *cb_data);
106+
int for_each_reflog_ent_reverse(const char *refname, each_reflog_ent_fn fn, void *cb_data);
107107

108108
/*
109109
* Calls the specified function for each reflog file until it returns nonzero,

sha1_name.c

Lines changed: 18 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -856,8 +856,8 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1,
856856
}
857857

858858
struct grab_nth_branch_switch_cbdata {
859-
long cnt, alloc;
860-
struct strbuf *buf;
859+
int remaining;
860+
struct strbuf buf;
861861
};
862862

863863
static int grab_nth_branch_switch(unsigned char *osha1, unsigned char *nsha1,
@@ -867,7 +867,6 @@ static int grab_nth_branch_switch(unsigned char *osha1, unsigned char *nsha1,
867867
struct grab_nth_branch_switch_cbdata *cb = cb_data;
868868
const char *match = NULL, *target = NULL;
869869
size_t len;
870-
int nth;
871870

872871
if (!prefixcmp(message, "checkout: moving from ")) {
873872
match = message + strlen("checkout: moving from ");
@@ -876,11 +875,12 @@ static int grab_nth_branch_switch(unsigned char *osha1, unsigned char *nsha1,
876875

877876
if (!match || !target)
878877
return 0;
879-
880-
len = target - match;
881-
nth = cb->cnt++ % cb->alloc;
882-
strbuf_reset(&cb->buf[nth]);
883-
strbuf_add(&cb->buf[nth], match, len);
878+
if (--(cb->remaining) == 0) {
879+
len = target - match;
880+
strbuf_reset(&cb->buf);
881+
strbuf_add(&cb->buf, match, len);
882+
return 1; /* we are done */
883+
}
884884
return 0;
885885
}
886886

@@ -891,7 +891,7 @@ static int grab_nth_branch_switch(unsigned char *osha1, unsigned char *nsha1,
891891
static int interpret_nth_prior_checkout(const char *name, struct strbuf *buf)
892892
{
893893
long nth;
894-
int i, retval;
894+
int retval;
895895
struct grab_nth_branch_switch_cbdata cb;
896896
const char *brace;
897897
char *num_end;
@@ -901,34 +901,22 @@ static int interpret_nth_prior_checkout(const char *name, struct strbuf *buf)
901901
brace = strchr(name, '}');
902902
if (!brace)
903903
return -1;
904-
nth = strtol(name+3, &num_end, 10);
904+
nth = strtol(name + 3, &num_end, 10);
905905
if (num_end != brace)
906906
return -1;
907907
if (nth <= 0)
908908
return -1;
909-
cb.alloc = nth;
910-
cb.buf = xmalloc(nth * sizeof(struct strbuf));
911-
for (i = 0; i < nth; i++)
912-
strbuf_init(&cb.buf[i], 20);
913-
cb.cnt = 0;
909+
cb.remaining = nth;
910+
strbuf_init(&cb.buf, 20);
911+
914912
retval = 0;
915-
for_each_recent_reflog_ent("HEAD", grab_nth_branch_switch, 40960, &cb);
916-
if (cb.cnt < nth) {
917-
cb.cnt = 0;
918-
for_each_reflog_ent("HEAD", grab_nth_branch_switch, &cb);
913+
if (0 < for_each_reflog_ent_reverse("HEAD", grab_nth_branch_switch, &cb)) {
914+
strbuf_reset(buf);
915+
strbuf_add(buf, cb.buf.buf, cb.buf.len);
916+
retval = brace - name + 1;
919917
}
920-
if (cb.cnt < nth)
921-
goto release_return;
922-
i = cb.cnt % nth;
923-
strbuf_reset(buf);
924-
strbuf_add(buf, cb.buf[i].buf, cb.buf[i].len);
925-
retval = brace-name+1;
926-
927-
release_return:
928-
for (i = 0; i < nth; i++)
929-
strbuf_release(&cb.buf[i]);
930-
free(cb.buf);
931918

919+
strbuf_release(&cb.buf);
932920
return retval;
933921
}
934922

0 commit comments

Comments
 (0)