From: Stefan Sperling Subject: implement sort by date in tog ref To: gameoftrees@openbsd.org Date: Tue, 16 Nov 2021 15:43:21 +0100 I tend to get lost between changes that are stacked on top of each other sometimes. Often, each change in the stack will have a branch reference pointing at it so I can keep track of things more easily. However, finding the top of this stack (i.e. the most recently modified branc) is not trivial with our current UI. It essentially requires jumping between references and comparing their commit date manually. This patch adds an easy way: Press 's' in the tog ref view and all references will be sorted by their commit timestamp. In the weird case where a ref does not point at a commit or tag we use the last modification time of the on-disk reference file as a fallback. ok? Perhaps later we could add new options to allow 'got ref -l' and 'got branch -l' to sort by date as well? diff f8306a31050978f1e7ff99ae008c68c4edf0678f c272759fa2c91227825d4eba4d9df8e784a56b25 blob - 23650d4ec25dae858e6e634a02dd5735b0ac0b9d blob + 3d4dadc8459f1d8ea2df85a31273afae7074548f --- lib/reference.c +++ lib/reference.c @@ -769,50 +769,76 @@ done: return err; } +static const struct got_error * +get_committer_time(struct got_reference *ref, struct got_repository *repo) +{ + const struct got_error *err = NULL; + int obj_type; + struct got_commit_object *commit = NULL; + struct got_tag_object *tag = NULL; + struct got_object_id *id = NULL; + + err = got_ref_resolve(&id, repo, ref); + if (err) + return err; + + err = got_object_get_type(&obj_type, repo, id); + if (err) + goto done; + + switch (obj_type) { + case GOT_OBJ_TYPE_COMMIT: + err = got_object_open_as_commit(&commit, repo, id); + if (err) + goto done; + ref->committer_time = + got_object_commit_get_committer_time(commit); + break; + case GOT_OBJ_TYPE_TAG: + err = got_object_open_as_tag(&tag, repo, id); + if (err) + goto done; + ref->committer_time = got_object_tag_get_tagger_time(tag); + break; + default: + /* best effort for other object types */ + ref->committer_time = got_ref_get_mtime(ref); + break; + } +done: + free(id); + if (commit) + got_object_commit_close(commit); + if (tag) + got_object_tag_close(tag); + return err; +} + const struct got_error * got_ref_cmp_by_commit_timestamp_descending(void *arg, int *cmp, struct got_reference *ref1, struct got_reference *ref2) { const struct got_error *err; struct got_repository *repo = arg; - struct got_object_id *id1 = NULL, *id2 = NULL; - struct got_commit_object *commit1 = NULL, *commit2 = NULL; *cmp = 0; if (ref1->committer_time == 0) { - err = got_ref_resolve(&id1, repo, ref1); + err = get_committer_time(ref1, repo); if (err) return err; - err = got_object_open_as_commit(&commit1, repo, id1); - if (err) - goto done; - ref1->committer_time = - got_object_commit_get_committer_time(commit1); } - if (ref2->committer_time == 0) { - err = got_ref_resolve(&id2, repo, ref2); + err = get_committer_time(ref2, repo); if (err) return err; - err = got_object_open_as_commit(&commit2, repo, id2); - if (err) - goto done; - ref2->committer_time = - got_object_commit_get_committer_time(commit2); } if (ref1->committer_time < ref2->committer_time) *cmp = 1; else if (ref2->committer_time < ref1->committer_time) *cmp = -1; -done: - free(id1); - free(id2); - if (commit1) - got_object_commit_close(commit1); - if (commit2) - got_object_commit_close(commit2); + return err; } blob - 0e414ba8af3db6bb003ec9b35d7e1510d7c18632 blob + 838d2ac721da6d2d566440db6d4fe96c55d79cec --- tog/tog.1 +++ tog/tog.1 @@ -452,6 +452,8 @@ view showing the tree resolved via the currently selec Show object IDs for all non-symbolic references displayed in the .Cm ref view. +.It Cm s +Toggle display order of references between sort by name and sort by timestamp. .It Cm / Prompt for a search pattern and start searching for matching references. The search pattern is an extended regular expression which is matched blob - 74c66761f4e9c5685b0a4c978e74ba94fe3579ca blob + deb6c22c2d7e0b2eb805d71560f1aff83c2315cc --- tog/tog.c +++ tog/tog.c @@ -129,11 +129,13 @@ static struct got_reflist_head tog_refs = TAILQ_HEAD_I static struct got_reflist_object_id_map *tog_refs_idmap; static const struct got_error * -tog_load_refs(struct got_repository *repo) +tog_load_refs(struct got_repository *repo, int sort_by_date) { const struct got_error *err; - err = got_ref_list(&tog_refs, repo, NULL, got_ref_cmp_by_name, NULL); + err = got_ref_list(&tog_refs, repo, NULL, sort_by_date ? + got_ref_cmp_by_commit_timestamp_descending : got_ref_cmp_by_name, + repo); if (err) return err; @@ -439,7 +441,7 @@ struct tog_ref_view_state { struct tog_reflist_entry *first_displayed_entry; struct tog_reflist_entry *last_displayed_entry; struct tog_reflist_entry *selected_entry; - int nrefs, ndisplayed, selected, show_ids; + int nrefs, ndisplayed, selected, show_ids, sort_by_date; struct got_repository *repo; struct tog_reflist_entry *matched_entry; struct tog_colors colors; @@ -2586,7 +2588,7 @@ input_log_view(struct tog_view **new_view, struct tog_ if (err) return err; tog_free_refs(); - err = tog_load_refs(s->repo); + err = tog_load_refs(s->repo, 0); if (err) return err; err = got_commit_graph_open(&s->thread_args.graph, @@ -2793,7 +2795,7 @@ cmd_log(int argc, char *argv[]) /* already loaded by tog_log_with_path()? */ if (TAILQ_EMPTY(&tog_refs)) { - error = tog_load_refs(repo); + error = tog_load_refs(repo, 0); if (error) goto done; } @@ -3914,7 +3916,7 @@ cmd_diff(int argc, char *argv[]) if (error) goto done; - error = tog_load_refs(repo); + error = tog_load_refs(repo, 0); if (error) goto done; @@ -4842,7 +4844,7 @@ cmd_blame(int argc, char *argv[]) if (error) goto done; - error = tog_load_refs(repo); + error = tog_load_refs(repo, 0); if (error) goto done; @@ -5695,7 +5697,7 @@ cmd_tree(int argc, char *argv[]) if (error) goto done; - error = tog_load_refs(repo); + error = tog_load_refs(repo, 0); if (error) goto done; @@ -6230,6 +6232,15 @@ input_ref_view(struct tog_view **new_view, struct tog_ case 'i': s->show_ids = !s->show_ids; break; + case 's': + s->sort_by_date = !s->sort_by_date; + tog_free_refs(); + err = tog_load_refs(s->repo, s->sort_by_date); + if (err) + break; + ref_view_free_refs(s); + err = ref_view_load_refs(s); + break; case KEY_ENTER: case '\r': if (!s->selected_entry) @@ -6326,7 +6337,7 @@ input_ref_view(struct tog_view **new_view, struct tog_ break; case CTRL('l'): tog_free_refs(); - err = tog_load_refs(s->repo); + err = tog_load_refs(s->repo, s->sort_by_date); if (err) break; ref_view_free_refs(s); @@ -6410,7 +6421,7 @@ cmd_ref(int argc, char *argv[]) if (error) goto done; - error = tog_load_refs(repo); + error = tog_load_refs(repo, 0); if (error) goto done; @@ -6535,7 +6546,7 @@ tog_log_with_path(int argc, char *argv[]) if (error) goto done; - error = tog_load_refs(repo); + error = tog_load_refs(repo, 0); if (error) goto done; error = got_repo_match_object_id(&commit_id, NULL, worktree ?