From 3615bdee4c3d1a0c719fc6b24f25f5745a6f2d92 Mon Sep 17 00:00:00 2001 From: Jonas Fonseca Date: Sat, 1 Nov 2014 23:19:23 -0400 Subject: [PATCH] Fix and improve status on-branch information Add a test for the different on-branch "modes" based on whether git-rebase, git-am or git-merge is in progress or whether a detached head has been checked out. This also changes status view refreshing to only reload the current branch information and not all refs as suggested in #341. Note that it actually reloads all repo information to get both the symbolic ref pointed to by HEAD as well as the HEAD id. --- NEWS.adoc | 1 + include/tig/repo.h | 2 + src/repo.c | 32 +++++++--- src/status.c | 32 +++++----- test/status/on-branch-test | 143 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 189 insertions(+), 21 deletions(-) create mode 100755 test/status/on-branch-test diff --git a/NEWS.adoc b/NEWS.adoc index c70d9c7..2dbe15d 100644 --- a/NEWS.adoc +++ b/NEWS.adoc @@ -17,6 +17,7 @@ Bug fixes: - Update manual to reflect default keybinding changes. (GH #325) - Fix graph support for `--first-parent`. (GH #326) - Fix off-by-one error when opening editor from the grep view. + - Fix status on-branch information. tig-2.0.3 --------- diff --git a/include/tig/repo.h b/include/tig/repo.h index 55d5f1e..e483e38 100644 --- a/include/tig/repo.h +++ b/include/tig/repo.h @@ -18,6 +18,7 @@ struct repo_info { char head[SIZEOF_REF]; + char head_id[SIZEOF_REV]; char remote[SIZEOF_REF]; char cdup[SIZEOF_STR]; char prefix[SIZEOF_STR]; @@ -28,6 +29,7 @@ struct repo_info { extern struct repo_info repo; int load_repo_info(void); +int load_repo_head(void); struct index_diff { int staged; diff --git a/src/repo.c b/src/repo.c index 967c3b4..f666f5f 100644 --- a/src/repo.c +++ b/src/repo.c @@ -26,7 +26,6 @@ struct repo_info_state { const char **argv; - char head_id[SIZEOF_REV]; }; static int @@ -61,21 +60,28 @@ read_repo_info(char *name, size_t namelen, char *value, size_t valuelen, void *d string_ncopy(repo.prefix, name, namelen); } else if (!strcmp(arg, REPO_INFO_RESOLVED_HEAD)) { - string_ncopy(state->head_id, name, namelen); + string_ncopy(repo.head_id, name, namelen); } else if (!strcmp(arg, REPO_INFO_SYMBOLIC_HEAD)) { if (!prefixcmp(name, "refs/heads/")) { - char *offset = name + STRING_SIZE("refs/heads/"); - - string_ncopy(repo.head, offset, strlen(offset) + 1); - add_ref(state->head_id, name, repo.remote, repo.head); + add_ref(repo.head_id, name, repo.remote, repo.head); + name += STRING_SIZE("refs/heads/"); } + string_ncopy(repo.head, name, strlen(name) + 1); state->argv++; } return OK; } +static int +reload_repo_info(const char **rev_parse_argv) +{ + struct repo_info_state state = { rev_parse_argv + 2 }; + + return io_run_load(rev_parse_argv, "=", read_repo_info, &state); +} + int load_repo_info(void) { @@ -85,9 +91,19 @@ load_repo_info(void) REPO_INFO_RESOLVED_HEAD, REPO_INFO_SYMBOLIC_HEAD, "HEAD", NULL }; - struct repo_info_state state = { rev_parse_argv + 2 }; - return io_run_load(rev_parse_argv, "=", read_repo_info, &state); + return reload_repo_info(rev_parse_argv); +} + +int +load_repo_head(void) +{ + const char *rev_parse_argv[] = { + "git", "rev-parse", REPO_INFO_RESOLVED_HEAD, + REPO_INFO_SYMBOLIC_HEAD, "HEAD", NULL + }; + + return reload_repo_info(rev_parse_argv); } struct repo_info repo; diff --git a/src/status.c b/src/status.c index 442f464..54cc019 100644 --- a/src/status.c +++ b/src/status.c @@ -201,15 +201,15 @@ status_restore(struct view *view) static void status_update_onbranch(void) { - static const char *paths[][2] = { - { "rebase-apply/rebasing", "Rebasing" }, - { "rebase-apply/applying", "Applying mailbox" }, - { "rebase-apply/", "Rebasing mailbox" }, - { "rebase-merge/interactive", "Interactive rebase" }, - { "rebase-merge/", "Rebase merge" }, - { "MERGE_HEAD", "Merging" }, - { "BISECT_LOG", "Bisecting" }, - { "HEAD", "On branch" }, + static const char *paths[][3] = { + { "rebase-apply/rebasing", "rebase-apply/head-name", "Rebasing" }, + { "rebase-apply/applying", "rebase-apply/head-name", "Applying mailbox to" }, + { "rebase-apply/", "rebase-apply/head-name", "Rebasing mailbox onto" }, + { "rebase-merge/interactive", "rebase-merge/head-name", "Interactive rebase" }, + { "rebase-merge/", "rebase-merge/head-name", "Rebase merge" }, + { "MERGE_HEAD", NULL, "Merging" }, + { "BISECT_LOG", NULL, "Bisecting" }, + { "HEAD", NULL, "On branch" }, }; char buf[SIZEOF_STR]; struct stat stat; @@ -221,16 +221,17 @@ status_update_onbranch(void) } for (i = 0; i < ARRAY_SIZE(paths); i++) { + const char *prefix = paths[i][2]; char *head = repo.head; if (!string_format(buf, "%s/%s", repo.git_dir, paths[i][0]) || lstat(buf, &stat) < 0) continue; - if (!*repo.head) { + if (paths[i][1]) { struct io io; - if (io_open(&io, "%s/rebase-merge/head-name", repo.git_dir) && + if (io_open(&io, "%s/%s", repo.git_dir, paths[i][1]) && io_read_buf(&io, buf, sizeof(buf))) { head = buf; if (!prefixcmp(head, "refs/heads/")) @@ -238,7 +239,12 @@ status_update_onbranch(void) } } - if (!string_format(status_onbranch, "%s %s", paths[i][1], head)) + if (!strcmp(head, "HEAD") && !strcmp(paths[i][0], "HEAD") && *repo.head_id) { + prefix = "On detached head"; + head = repo.head_id; + } + + if (!string_format(status_onbranch, "%s %s", prefix, head)) string_copy(status_onbranch, repo.head); return; } @@ -633,7 +639,7 @@ status_request(struct view *view, enum request request, struct line *line) case REQ_REFRESH: /* Load the current branch information and then the view. */ - load_refs(TRUE); + load_repo_head(); break; default: diff --git a/test/status/on-branch-test b/test/status/on-branch-test new file mode 100755 index 0000000..3b40efa --- /dev/null +++ b/test/status/on-branch-test @@ -0,0 +1,143 @@ +#!/bin/sh + +. libtest.sh +. libgit.sh + +export LINES=10 + +steps " + :save-display on-branch-master.screen + + :exec @git bisect start master + :save-display bisecting-master.screen + :exec @git bisect reset + + :exec @git checkout HEAD~10 + :save-display on-detached-head.screen + :exec @git checkout master + + :exec @git merge conflict-branch + :save-display merging-master.screen + :exec @git reset --hard + + :exec @git checkout conflict-branch + :exec @git rebase master + :save-display rebasing-master.screen + :exec @git rebase --abort + :exec @git checkout master + + :exec @git am $HOME/mailbox + :save-display applying-mailbox-to-master.screen + :exec @git am --abort + + :exec @git checkout conflict-branch + :exec @git rebase -i master + :save-display interactive-rebase-of-branch.screen + :exec @git rebase --abort + :exec @git checkout master +" + +prepare_repo() +{ + git checkout -b topic-branch HEAD~4 + echo "Topic branch" >> README.md + git add README.md + git_commit -m "Topic branch" + git checkout master + + git checkout -b conflict-branch HEAD~4 + git rm -f run.sh + git_commit -m "Conflict branch" + git checkout master + + git format-patch -1 conflict-branch --stdout > "$HOME/mailbox" +} + +in_work_dir create_repo_from_tgz "$base_dir/files/scala-js-benchmarks.tgz" +in_work_dir prepare_repo 1>>"$HOME/prepare-repo.log" 2>>"$HOME/prepare-repo.log" + +test_tig status + +assert_equals 'on-branch-master.screen' <