aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2009-01-19 00:04:25 -0800
committerJunio C Hamano <gitster@pobox.com>2009-01-19 15:35:21 -0800
commitc2883e62f5b9980e5402431f2261c961354d0f15 (patch)
treebe6de693adb7e9b21e95e9409dc06a7d341d9133
parent696acf45f9638b014c7132508de26d1a571c8a33 (diff)
downloadgit-c2883e62f5b9980e5402431f2261c961354d0f15.tar.gz
git-c2883e62f5b9980e5402431f2261c961354d0f15.tar.xz
interpret_nth_last_branch(): avoid traversing the reflog twice
You can have quite a many reflog entries, but you typically won't recall which branch you were on after switching branches for more than several times. Instead of reading the reflog twice, this reads the branch switching event and keeps as many entries as the user asked from the latest such entries, which is the minimum required to be able to switch back to the branch we were recently on. [jc: improvements from Dscho squashed in] Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r--sha1_name.c45
-rwxr-xr-xt/t2012-checkout-last.sh44
2 files changed, 65 insertions, 24 deletions
diff --git a/sha1_name.c b/sha1_name.c
index 9e1538e3d..d6972f2d6 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -685,8 +685,7 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1)
}
struct grab_nth_branch_switch_cbdata {
- int counting;
- int nth;
+ long cnt, alloc;
struct strbuf *buf;
};
@@ -697,6 +696,7 @@ static int grab_nth_branch_switch(unsigned char *osha1, unsigned char *nsha1,
struct grab_nth_branch_switch_cbdata *cb = cb_data;
const char *match = NULL, *target = NULL;
size_t len;
+ int nth;
if (!prefixcmp(message, "checkout: moving from ")) {
match = message + strlen("checkout: moving from ");
@@ -711,16 +711,9 @@ static int grab_nth_branch_switch(unsigned char *osha1, unsigned char *nsha1,
if (target[len] == '\n' && !strncmp(match, target, len))
return 0;
- if (cb->counting) {
- cb->nth++;
- return 0;
- }
-
- if (cb->nth-- <= 0) {
- strbuf_reset(cb->buf);
- strbuf_add(cb->buf, match, len);
- return 1;
- }
+ nth = cb->cnt++ % cb->alloc;
+ strbuf_reset(&cb->buf[nth]);
+ strbuf_add(&cb->buf[nth], match, len);
return 0;
}
@@ -737,7 +730,8 @@ static int grab_nth_branch_switch(unsigned char *osha1, unsigned char *nsha1,
*/
int interpret_nth_last_branch(const char *name, struct strbuf *buf)
{
- int nth;
+ long nth;
+ int i;
struct grab_nth_branch_switch_cbdata cb;
const char *brace;
char *num_end;
@@ -750,19 +744,22 @@ int interpret_nth_last_branch(const char *name, struct strbuf *buf)
nth = strtol(name+3, &num_end, 10);
if (num_end != brace)
return -1;
-
- cb.counting = 1;
- cb.nth = 0;
- cb.buf = buf;
+ if (nth <= 0)
+ return -1;
+ cb.alloc = nth;
+ cb.buf = xmalloc(nth * sizeof(struct strbuf));
+ for (i = 0; i < nth; i++)
+ strbuf_init(&cb.buf[i], 20);
+ cb.cnt = 0;
for_each_reflog_ent("HEAD", grab_nth_branch_switch, &cb);
-
- if (cb.nth < nth)
+ if (cb.cnt < nth)
return 0;
-
- cb.counting = 0;
- cb.nth -= nth;
- cb.buf = buf;
- for_each_reflog_ent("HEAD", grab_nth_branch_switch, &cb);
+ i = cb.cnt % nth;
+ strbuf_reset(buf);
+ strbuf_add(buf, cb.buf[i].buf, cb.buf[i].len);
+ for (i = 0; i < nth; i++)
+ strbuf_release(&cb.buf[i]);
+ free(cb.buf);
return brace-name+1;
}
diff --git a/t/t2012-checkout-last.sh b/t/t2012-checkout-last.sh
index 320f6eb2b..87b30a268 100755
--- a/t/t2012-checkout-last.sh
+++ b/t/t2012-checkout-last.sh
@@ -47,4 +47,48 @@ test_expect_success '"checkout -" detaches again' '
test_must_fail git symbolic-ref HEAD
'
+test_expect_success 'more switches' '
+ for i in 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
+ do
+ git checkout -b branch$i
+ done
+'
+
+more_switches () {
+ for i in 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
+ do
+ git checkout branch$i
+ done
+}
+
+test_expect_success 'switch to the last' '
+ more_switches &&
+ git checkout @{-1} &&
+ test "z$(git symbolic-ref HEAD)" = "zrefs/heads/branch2"
+'
+
+test_expect_success 'switch to second from the last' '
+ more_switches &&
+ git checkout @{-2} &&
+ test "z$(git symbolic-ref HEAD)" = "zrefs/heads/branch3"
+'
+
+test_expect_success 'switch to third from the last' '
+ more_switches &&
+ git checkout @{-3} &&
+ test "z$(git symbolic-ref HEAD)" = "zrefs/heads/branch4"
+'
+
+test_expect_success 'switch to fourth from the last' '
+ more_switches &&
+ git checkout @{-4} &&
+ test "z$(git symbolic-ref HEAD)" = "zrefs/heads/branch5"
+'
+
+test_expect_success 'switch to twelfth from the last' '
+ more_switches &&
+ git checkout @{-12} &&
+ test "z$(git symbolic-ref HEAD)" = "zrefs/heads/branch13"
+'
+
test_done