Let git-checkout save the old branch as a symref in LAST_HEAD, and make 'git checkout -' switch back to LAST_HEAD, like 'cd -' does in the shell. Signed-off-by: Thomas Rast <trast@xxxxxxxxxxxxxxx> --- I really wished I had this earlier today. I'm just not sure if it's a good idea, or even possible, to reserve the '-'. I can't seem to check out a branch '-foo' with git-checkout, but it's easy to create one with 'git branch -- -foo'. git-check-ref-format(1) doesn't forbid it either, although the actual 'git check-ref-format -foo' exits with status 1. Documentation/git-checkout.txt | 3 +++ Documentation/gitrepository-layout.txt | 4 ++++ builtin-checkout.c | 26 +++++++++++++++++++++++++- 3 files changed, 32 insertions(+), 1 deletions(-) diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt index 9cd5151..1397745 100644 --- a/Documentation/git-checkout.txt +++ b/Documentation/git-checkout.txt @@ -133,6 +133,9 @@ the conflicted merge in the specified paths. + When this parameter names a non-branch (but still a valid commit object), your HEAD becomes 'detached'. ++ +You may also specify "`-`", which denotes the last branch you were on +before the current HEAD. Detached HEAD diff --git a/Documentation/gitrepository-layout.txt b/Documentation/gitrepository-layout.txt index 1befca9..f506c98 100644 --- a/Documentation/gitrepository-layout.txt +++ b/Documentation/gitrepository-layout.txt @@ -123,6 +123,10 @@ is often called 'detached HEAD', and almost all commands work identically as normal. See linkgit:git-checkout[1] for details. +LAST_HEAD:: + A symref that holds the value of HEAD before the last + branch switch. + branches:: A slightly deprecated way to store shorthands to be used to specify URL to 'git-fetch', 'git-pull' and 'git-push' diff --git a/builtin-checkout.c b/builtin-checkout.c index b5dd9c0..356ad6c 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -480,6 +480,15 @@ static void report_tracking(struct branch_info *new) strbuf_release(&sb); } +static void save_old_branch(struct branch_info *old, char *msg) +{ + if (old->path) { + create_symref("LAST_HEAD", old->path, msg); + } else + update_ref(msg, "LAST_HEAD", old->commit->object.sha1, NULL, + REF_NODEREF, DIE_ON_ERR); +} + static void update_refs_for_switch(struct checkout_opts *opts, struct branch_info *old, struct branch_info *new) @@ -505,12 +514,15 @@ static void update_refs_for_switch(struct checkout_opts *opts, if (old->path && !strcmp(new->path, old->path)) fprintf(stderr, "Already on \"%s\"\n", new->name); - else + else { fprintf(stderr, "Switched to%s branch \"%s\"\n", opts->new_branch ? " a new" : "", new->name); + save_old_branch(old, msg.buf); + } } } else if (strcmp(new->name, "HEAD")) { + save_old_branch(old, msg.buf); update_ref(msg.buf, "HEAD", new->commit->object.sha1, NULL, REF_NODEREF, DIE_ON_ERR); if (!opts->quiet) { @@ -533,6 +545,8 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new) int flag; memset(&old, 0, sizeof(old)); old.path = resolve_ref("HEAD", rev, 0, &flag); + if (old.path) + old.path = strdup(old.path); old.commit = lookup_commit_reference_gently(rev, 1); if (!(flag & REF_ISSYMREF)) old.path = NULL; @@ -604,6 +618,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) OPT_END(), }; int has_dash_dash; + int flag; memset(&opts, 0, sizeof(opts)); memset(&new, 0, sizeof(new)); @@ -671,6 +686,15 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) arg = argv[0]; has_dash_dash = (argc > 1) && !strcmp(argv[1], "--"); + if (!strcmp(arg, "-")) { + arg = resolve_ref("LAST_HEAD", rev, 0, &flag); + if (!arg) + die("No last branch saved."); + if(!prefixcmp(arg, "refs/heads/")) + arg += 11; + arg = strdup(arg); + } + if (get_sha1(arg, rev)) { if (has_dash_dash) /* case (1) */ die("invalid reference: %s", arg); -- 1.6.1.282.gae4091.dirty -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html