"GOT", but the "O" is a cute, smiling pufferfish. Index | Thread | Search

From:
Stefan Sperling <stsp@stsp.name>
Subject:
implement sort by date in tog ref
To:
gameoftrees@openbsd.org
Date:
Tue, 16 Nov 2021 15:43:21 +0100

Download raw body.

Thread
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 ?