commit dbec59df9a61e9cea9251851a5c649ab8981e91b from: Stefan Sperling date: Sat Apr 18 21:24:54 2020 UTC add 'got log' -R option to reverse commit display order commit - 52ab795804a3c40a55a009fd869496a305611276 commit + dbec59df9a61e9cea9251851a5c649ab8981e91b blob - 39ad76b02f24d006741407cf89f9df33a179c54b blob + f0afe089450e16d23c8021535652e8be9cc16f0a --- got/got.1 +++ got/got.1 @@ -682,7 +682,7 @@ in a pattern. .It Cm st Short alias for .Cm status . -.It Cm log Oo Fl b Oc Oo Fl c Ar commit Oc Oo Fl C Ar number Oc Oo Fl l Ar N Oc Oo Fl p Oc Oo Fl s Ar search-pattern Oc Oo Fl r Ar repository-path Oc Oo Fl x Ar commit Oc Op Ar path +.It Cm log Oo Fl b Oc Oo Fl c Ar commit Oc Oo Fl C Ar number Oc Oo Fl l Ar N Oc Oo Fl p Oc Oo Fl s Ar search-pattern Oc Oo Fl r Ar repository-path Oc Oo Fl R Oc Oo Fl x Ar commit Oc Op Ar path Display history of a repository. If a .Ar path @@ -741,6 +741,9 @@ working directory. If this directory is a .Nm work tree, use the repository path associated with this work tree. +.It Fl R +Determine a set of commits to display as usual, but display these commits +in reverse order. .It Fl x Ar commit Stop traversing commit history as soon as the specified .Ar commit blob - a6905d4ca6eaa4217742da3a792e0337f1bc62d4 blob + 7163d538700ed481c6a158c6820bc7c4b7e8eaa6 --- got/got.c +++ got/got.c @@ -3135,12 +3135,17 @@ static const struct got_error * print_commits(struct got_object_id *root_id, struct got_object_id *end_id, struct got_repository *repo, const char *path, int show_patch, const char *search_pattern, int diff_context, int limit, int log_branches, - struct got_reflist_head *refs) + int reverse_display_order, struct got_reflist_head *refs) { const struct got_error *err; struct got_commit_graph *graph; regex_t regex; int have_match; + struct got_object_id_queue reversed_commits; + struct got_object_qid *qid; + struct got_commit_object *commit; + + SIMPLEQ_INIT(&reversed_commits); if (search_pattern && regcomp(®ex, search_pattern, REG_EXTENDED | REG_NOSUB | REG_NEWLINE)) @@ -3154,7 +3159,6 @@ print_commits(struct got_object_id *root_id, struct go if (err) goto done; for (;;) { - struct got_commit_object *commit; struct got_object_id *id; if (sigint_received || sigpipe_received) @@ -3186,14 +3190,41 @@ print_commits(struct got_object_id *root_id, struct go } } - err = print_commit(commit, id, repo, path, show_patch, - diff_context, refs); - got_object_commit_close(commit); - if (err || (limit && --limit == 0) || - (end_id != NULL && got_object_id_cmp(id, end_id) == 0)) + if (reverse_display_order) { + err = got_object_qid_alloc(&qid, id); + if (err) + break; + SIMPLEQ_INSERT_HEAD(&reversed_commits, qid, entry); + got_object_commit_close(commit); + } else { + err = print_commit(commit, id, repo, path, show_patch, + diff_context, refs); + got_object_commit_close(commit); + if (err) + break; + } + if ((limit && --limit == 0) || + (end_id && got_object_id_cmp(id, end_id) == 0)) break; } + if (reverse_display_order) { + SIMPLEQ_FOREACH(qid, &reversed_commits, entry) { + err = got_object_open_as_commit(&commit, repo, qid->id); + if (err) + break; + err = print_commit(commit, qid->id, repo, path, + show_patch, diff_context, refs); + got_object_commit_close(commit); + if (err) + break; + } + } done: + while (!SIMPLEQ_EMPTY(&reversed_commits)) { + qid = SIMPLEQ_FIRST(&reversed_commits); + SIMPLEQ_REMOVE_HEAD(&reversed_commits, entry); + got_object_qid_free(qid); + } if (search_pattern) regfree(®ex); got_commit_graph_close(graph); @@ -3204,7 +3235,7 @@ __dead static void usage_log(void) { fprintf(stderr, "usage: %s log [-b] [-c commit] [-C number] [ -l N ] " - "[-p] [-x commit] [-s search-pattern] [-r repository-path] " + "[-p] [-x commit] [-s search-pattern] [-r repository-path] [-R] " "[path]\n", getprogname()); exit(1); } @@ -3285,6 +3316,7 @@ cmd_log(int argc, char *argv[]) const char *search_pattern = NULL; int diff_context = -1, ch; int show_patch = 0, limit = 0, log_branches = 0; + int reverse_display_order = 0; const char *errstr; struct got_reflist_head refs; @@ -3299,7 +3331,7 @@ cmd_log(int argc, char *argv[]) limit = get_default_log_limit(); - while ((ch = getopt(argc, argv, "bpc:C:l:r:s:x:")) != -1) { + while ((ch = getopt(argc, argv, "bpc:C:l:r:Rs:x:")) != -1) { switch (ch) { case 'p': show_patch = 1; @@ -3328,6 +3360,9 @@ cmd_log(int argc, char *argv[]) optarg); got_path_strip_trailing_slashes(repo_path); break; + case 'R': + reverse_display_order = 1; + break; case 's': search_pattern = optarg; break; @@ -3451,7 +3486,8 @@ cmd_log(int argc, char *argv[]) goto done; error = print_commits(start_id, end_id, repo, path, show_patch, - search_pattern, diff_context, limit, log_branches, &refs); + search_pattern, diff_context, limit, log_branches, + reverse_display_order, &refs); done: free(path); free(repo_path); blob - 3f4c9bd9cc92924eee23f9724c484d587cab4334 blob + 6bde801a304c1c49f7f91d334825b18215ee684e --- regress/cmdline/log.sh +++ regress/cmdline/log.sh @@ -470,7 +470,83 @@ function test_log_end_at_commit { test_done "$testroot" "0" } + +function test_log_reverse_display { + local testroot=`test_init log_reverse_display` + local commit_id0=`git_show_head $testroot/repo` + + got checkout $testroot/repo $testroot/wt > /dev/null + ret="$?" + if [ "$ret" != "0" ]; then + test_done "$testroot" "$ret" + return 1 + fi + + echo "modified alpha" > $testroot/wt/alpha + (cd $testroot/wt && got commit -m 'commit1' > /dev/null) + local commit_id1=`git_show_head $testroot/repo` + + (cd $testroot/wt && got rm beta >/dev/null) + (cd $testroot/wt && got commit -m 'commit2' > /dev/null) + local commit_id2=`git_show_head $testroot/repo` + + echo "new file" > $testroot/wt/new + (cd $testroot/wt && got add new >/dev/null) + (cd $testroot/wt && got commit -m 'commit3' > /dev/null) + local commit_id3=`git_show_head $testroot/repo` + # -R alone should display all commits in reverse + echo "commit $commit_id0" > $testroot/stdout.expected + echo "commit $commit_id1" >> $testroot/stdout.expected + echo "commit $commit_id2" >> $testroot/stdout.expected + echo "commit $commit_id3 (master)" >> $testroot/stdout.expected + (cd $testroot/wt && got log -R | grep ^commit > $testroot/stdout) + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + return 1 + fi + + # -R takes effect after the -l commit traversal limit + echo "commit $commit_id2" > $testroot/stdout.expected + echo "commit $commit_id3 (master)" >> $testroot/stdout.expected + (cd $testroot/wt && got log -R -l2 | grep ^commit > $testroot/stdout) + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + return 1 + fi + + # -R works with commit ranges specified via -c and -x + echo "commit $commit_id1" > $testroot/stdout.expected + echo "commit $commit_id2" >> $testroot/stdout.expected + echo "commit $commit_id3 (master)" >> $testroot/stdout.expected + (cd $testroot/wt && got log -R -c $commit_id3 -x $commit_id1 | \ + grep ^commit > $testroot/stdout) + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + fi + + # commit matching with -s applies before -R + echo "commit $commit_id1" > $testroot/stdout.expected + echo "commit $commit_id2" >> $testroot/stdout.expected + (cd $testroot/wt && got log -R -s 'commit[12]' | \ + grep ^commit > $testroot/stdout) + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + fi + test_done "$testroot" "$ret" +} + run_test test_log_in_repo run_test test_log_in_bare_repo run_test test_log_in_worktree @@ -479,3 +555,4 @@ run_test test_log_tag run_test test_log_limit run_test test_log_nonexistent_path run_test test_log_end_at_commit +run_test test_log_reverse_display