commit - df6221c7df42758252c508006201c3f66e6ae831
commit + c4df265ebabf6993a1c217bb2bb59d5aeb3fe5e5
blob - 93c8f6f920ce4b2013710cddd1e94d1b83b0a7ad
blob + a329dca28bf36978b73b04fe71d37578bfbc712f
--- regress/tog/blame.sh
+++ regress/tog/blame.sh
test_done "$testroot" "$ret"
}
+test_blame_commit_keywords()
+{
+ test_init blame_commit_keywords 80 10
+ local repo="$testroot/repo"
+ local wt="$testroot/wt"
+ local id=$(git_show_head "$repo")
+ local author_time=$(git_show_author_time "$repo")
+ local ymd=$(date -u -r $author_time +"%G-%m-%d")
+
+ set -A ids "$id"
+ set -A short_ids "$(trim_obj_id 32 $id)"
+
+ cat <<-EOF >$TOG_TEST_SCRIPT
+ WAIT_FOR_UI wait for blame to finish
+ SCREENDUMP
+ EOF
+
+ # :base requires work tree
+ echo "tog: '-c :base' requires work tree" > "$testroot/stderr.expected"
+ tog blame -r "$repo" -c:base alpha 2> "$testroot/stderr"
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ echo "blame command succeeded unexpectedly" >&2
+ test_done "$testroot" "1"
+ return 1
+ fi
+
+ cmp -s "$testroot/stderr.expected" "$testroot/stderr"
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u "$testroot/stderr.expected" "$testroot/stderr"
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ # :head keyword in repo
+ cat <<-EOF >$testroot/view.expected
+ commit $id
+ [1/1] /alpha
+ $(pop_id 1 $short_ids) alpha
+
+
+
+
+
+
+
+ EOF
+
+ tog blame -r "$repo" -c:head alpha
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "blame command failed unexpectedly" >&2
+ test_done "$testroot" "1"
+ return 1
+ fi
+
+ cmp -s $testroot/view.expected $testroot/view
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u $testroot/view.expected $testroot/view
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ got checkout "$repo" "$wt" > /dev/null
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "got checkout failed unexpectedly"
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ # move into the work tree (test is run in a subshell)
+ cd "$wt"
+ echo -n > alpha
+
+ for i in $(seq 8); do
+ echo "alpha $i" >> alpha
+
+ got ci -m "commit $i" > /dev/null
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "commit failed unexpectedly" >&2
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ id=$(git_show_head "$repo")
+ set -- "$ids" "$id"
+ ids=$*
+ set -- "$short_ids" "$(trim_obj_id 32 $id)"
+ short_ids=$*
+ done
+
+ author_time=$(git_show_author_time "$repo")
+ ymd=$(date -u -r $author_time +"%G-%m-%d")
+
+ # :base:- keyword in work tree
+ cat <<-EOF >$testroot/view.expected
+ commit $(pop_id 8 $ids)
+ [1/7] /alpha
+ $(pop_id 2 $short_ids) alpha 1
+ $(pop_id 3 $short_ids) alpha 2
+ $(pop_id 4 $short_ids) alpha 3
+ $(pop_id 5 $short_ids) alpha 4
+ $(pop_id 6 $short_ids) alpha 5
+ $(pop_id 7 $short_ids) alpha 6
+ $(pop_id 8 $short_ids) alpha 7
+
+ EOF
+
+ tog blame -c:base:- alpha
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "blame command failed unexpectedly" >&2
+ test_done "$testroot" "1"
+ return 1
+ fi
+
+ cmp -s $testroot/view.expected $testroot/view
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u $testroot/view.expected $testroot/view
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ # :head:-4 keyword in work tree
+ cat <<-EOF >$testroot/view.expected
+ commit $(pop_id 5 $ids)
+ [1/4] /alpha
+ $(pop_id 2 $short_ids) alpha 1
+ $(pop_id 3 $short_ids) alpha 2
+ $(pop_id 4 $short_ids) alpha 3
+ $(pop_id 5 $short_ids) alpha 4
+
+
+
+
+ EOF
+
+ tog blame -c:head:-4 alpha
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "blame command failed unexpectedly" >&2
+ test_done "$testroot" "1"
+ return 1
+ fi
+
+ cmp -s $testroot/view.expected $testroot/view
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u $testroot/view.expected $testroot/view
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ # :base:+2 keyword in work tree
+ cat <<-EOF >$testroot/view.expected
+ commit $(pop_id 5 $ids)
+ [1/4] /alpha
+ $(pop_id 2 $short_ids) alpha 1
+ $(pop_id 3 $short_ids) alpha 2
+ $(pop_id 4 $short_ids) alpha 3
+ $(pop_id 5 $short_ids) alpha 4
+
+
+
+
+ EOF
+
+ got up -c:head:-6 > /dev/null
+ if [ $ret -ne 0 ]; then
+ echo "update command failed unexpectedly" >&2
+ test_done "$testroot" "1"
+ return 1
+ fi
+
+ tog blame -c:base:+2 alpha
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "blame command failed unexpectedly" >&2
+ test_done "$testroot" "1"
+ return 1
+ fi
+
+ cmp -s $testroot/view.expected $testroot/view
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u $testroot/view.expected $testroot/view
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ # master:-99 keyword in work tree
+ cat <<-EOF >$testroot/view.expected
+ commit $(pop_id 1 $ids)
+ [1/1] /alpha
+ $(pop_id 1 $short_ids) alpha
+
+
+
+
+
+
+
+ EOF
+
+ tog blame -cmaster:-99 alpha
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "blame command failed unexpectedly" >&2
+ test_done "$testroot" "1"
+ return 1
+ fi
+
+ cmp -s $testroot/view.expected $testroot/view
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u $testroot/view.expected $testroot/view
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ test_done "$testroot" "$ret"
+}
+
test_parseargs "$@"
run_test test_blame_basic
+run_test test_blame_commit_keywords
blob - 53edc5c3c79e0951bfdaf8315a353c3430a7b579
blob + 6ab39dc440fb2afb20ecaabc0425b545530d6c6d
--- regress/tog/diff.sh
+++ regress/tog/diff.sh
test_done "$testroot" "$ret"
}
+test_diff_commit_keywords()
+{
+ test_init diff_commit_keywords 120 24
+ local repo="$testroot/repo"
+ local wt="$testroot/wt"
+ local id=$(git_show_head "$repo")
+ local author_time=$(git_show_author_time "$repo")
+ local date=$(date -u -r $author_time +"%a %b %e %X %Y UTC")
+
+ set -A ids "$id"
+ set -A alpha_ids $(get_blob_id "$repo" "" alpha)
+
+ got checkout "$repo" "$wt" > /dev/null
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "got checkout failed unexpectedly"
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ # move into the work tree (test is run in a subshell)
+ cd "$wt"
+
+ for i in $(seq 8); do
+ echo "alpha $i" > alpha
+
+ got ci -m "commit $i" > /dev/null
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "commit failed unexpectedly" >&2
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ id=$(git_show_head "$repo")
+ set -- "$ids" "$id"
+ ids=$*
+ set -- "$alpha_ids" "$(get_blob_id "$repo" "" alpha)"
+ alpha_ids=$*
+ done
+
+ cat <<-EOF >$TOG_TEST_SCRIPT
+ SCREENDUMP
+ EOF
+
+ # diff consecutive commits with keywords
+ local lhs_id=$(pop_id 1 $ids)
+ local rhs_id=$(pop_id 2 $ids)
+
+ cat <<-EOF >$testroot/view.expected
+ [1/20] diff $lhs_id $rhs_id
+ commit $rhs_id
+ from: Flan Hacker <flan_hacker@openbsd.org>
+ date: $date
+
+ commit 1
+
+ M alpha | 1+ 1-
+
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+ commit - $lhs_id
+ commit + $rhs_id
+ blob - $(pop_id 1 $alpha_ids)
+ blob + $(pop_id 2 $alpha_ids)
+ --- alpha
+ +++ alpha
+ @@ -1 +1 @@
+ -alpha
+ +alpha 1
+
+
+
+ (END)
+ EOF
+
+ tog diff :base:-99 :head:-7
+ cmp -s "$testroot/view.expected" "$testroot/view"
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u "$testroot/view.expected" "$testroot/view"
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ # diff arbitrary commits with keywords
+ lhs_id=$(pop_id 5 $ids)
+ rhs_id=$(pop_id 8 $ids)
+
+ cat <<-EOF >$testroot/view.expected
+ [1/10] diff $lhs_id $rhs_id
+ commit - $lhs_id
+ commit + $rhs_id
+ blob - $(pop_id 5 $alpha_ids)
+ blob + $(pop_id 8 $alpha_ids)
+ --- alpha
+ +++ alpha
+ @@ -1 +1 @@
+ -alpha 4
+ +alpha 7
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (END)
+ EOF
+
+ tog diff master:-4 :head:-
+ cmp -s "$testroot/view.expected" "$testroot/view"
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u "$testroot/view.expected" "$testroot/view"
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ # diff consecutive commits using keywords with -r repository
+ lhs_id=$(pop_id 8 $ids)
+ rhs_id=$(pop_id 9 $ids)
+ author_time=$(git_show_author_time "$repo")
+ date=$(date -u -r $author_time +"%a %b %e %X %Y UTC")
+
+ cat <<-EOF >$testroot/view.expected
+ [1/20] diff $lhs_id refs/heads/master
+ commit $rhs_id (master)
+ from: Flan Hacker <flan_hacker@openbsd.org>
+ date: $date
+
+ commit 8
+
+ M alpha | 1+ 1-
+
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+ commit - $lhs_id
+ commit + $rhs_id
+ blob - $(pop_id 8 $alpha_ids)
+ blob + $(pop_id 9 $alpha_ids)
+ --- alpha
+ +++ alpha
+ @@ -1 +1 @@
+ -alpha 7
+ +alpha 8
+
+
+
+ (END)
+ EOF
+
+ tog diff -r "$repo" :head:- master
+ cmp -s "$testroot/view.expected" "$testroot/view"
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u "$testroot/view.expected" "$testroot/view"
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ test_done "$testroot" "$ret"
+}
+
test_parseargs "$@"
run_test test_diff_contiguous_commits
run_test test_diff_arbitrary_commits
run_test test_diff_J_keymap_on_last_loaded_commit
+run_test test_diff_commit_keywords
blob - 67469c1eae523eaf0c2b46922e300c93c42a323f
blob + 2a28c65c9bf9e227cba943ce259438976ac67c02
--- regress/tog/log.sh
+++ regress/tog/log.sh
ret=$?
if [ $ret -ne 0 ]; then
diff -u $testroot/view.expected $testroot/view
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ test_done "$testroot" "$ret"
+}
+
+test_log_commit_keywords()
+{
+ test_init log_commit_keywords 120 10
+ local repo="$testroot/repo"
+ local wt="$testroot/wt"
+ local id=$(git_show_head "$repo")
+ local author_time=$(git_show_author_time "$repo")
+ local ymd=$(date -u -r $author_time +"%G-%m-%d")
+
+ set -A ids "$id"
+ set -A short_ids "$(trim_obj_id 32 $id)"
+
+ got checkout "$repo" "$wt" > /dev/null
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "got checkout failed unexpectedly"
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ # move into the work tree (test is run in a subshell)
+ cd "$wt"
+ echo -n > alpha
+
+ for i in $(seq 8); do
+ echo "alpha $i" >> alpha
+
+ got ci -m "commit $i" > /dev/null
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "commit failed unexpectedly" >&2
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ id=$(git_show_head "$repo")
+ set -- "$ids" "$id"
+ ids=$*
+ set -- "$short_ids" "$(trim_obj_id 32 $id)"
+ short_ids=$*
+ done
+
+ cat <<-EOF >$TOG_TEST_SCRIPT
+ SCREENDUMP
+ EOF
+
+ cat <<-EOF >$testroot/view.expected
+ commit $(pop_id 5 $ids) [1/5]
+ $ymd $(pop_id 5 $short_ids) flan_hacker commit 4
+ $ymd $(pop_id 4 $short_ids) flan_hacker commit 3
+ $ymd $(pop_id 3 $short_ids) flan_hacker commit 2
+ $ymd $(pop_id 2 $short_ids) flan_hacker commit 1
+ $ymd $(pop_id 1 $short_ids) flan_hacker adding the test tree
+
+
+
+
+ EOF
+
+ tog log -c:base:-4
+ cmp -s "$testroot/view.expected" "$testroot/view"
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u "$testroot/view.expected" "$testroot/view"
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ cat <<-EOF >$testroot/view.expected
+ commit $(pop_id 7 $ids) [1/7]
+ $ymd $(pop_id 7 $short_ids) flan_hacker commit 6
+ $ymd $(pop_id 6 $short_ids) flan_hacker commit 5
+ $ymd $(pop_id 5 $short_ids) flan_hacker commit 4
+ $ymd $(pop_id 4 $short_ids) flan_hacker commit 3
+ $ymd $(pop_id 3 $short_ids) flan_hacker commit 2
+ $ymd $(pop_id 2 $short_ids) flan_hacker commit 1
+ $ymd $(pop_id 1 $short_ids) flan_hacker adding the test tree
+
+
+ EOF
+
+ tog log -r "$repo" -c:head:-2
+ cmp -s "$testroot/view.expected" "$testroot/view"
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u "$testroot/view.expected" "$testroot/view"
test_done "$testroot" "$ret"
return 1
fi
+ cat <<-EOF >$testroot/view.expected
+ commit $(pop_id 5 $ids) [1/5]
+ $ymd $(pop_id 5 $short_ids) flan_hacker commit 4
+ $ymd $(pop_id 4 $short_ids) flan_hacker commit 3
+ $ymd $(pop_id 3 $short_ids) flan_hacker commit 2
+ $ymd $(pop_id 2 $short_ids) flan_hacker commit 1
+ $ymd $(pop_id 1 $short_ids) flan_hacker adding the test tree
+
+
+
+
+ EOF
+
+ got up -c:base:-6 > /dev/null
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "got update failed unexpectedly"
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ tog log -c:base:+2
+ cmp -s "$testroot/view.expected" "$testroot/view"
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u "$testroot/view.expected" "$testroot/view"
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ cat <<-EOF >$testroot/view.expected
+ commit $(pop_id 1 $ids) [1/1]
+ $ymd $(pop_id 1 $short_ids) flan_hacker adding the test tree
+
+
+
+
+
+
+
+
+ EOF
+
+ tog log -c:base:-99
+ cmp -s "$testroot/view.expected" "$testroot/view"
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u "$testroot/view.expected" "$testroot/view"
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
test_done "$testroot" "$ret"
}
run_test test_log_hsplit_ref
run_test test_log_hsplit_tree
run_test test_log_logmsg_widechar
+run_test test_log_commit_keywords
blob - c26b425e144352ef6828dcd4df36836b60aee6c9
blob + ab5481d9ca9da400e86ac14e7511cf21b1e24863
--- regress/tog/tree.sh
+++ regress/tog/tree.sh
test_done "$testroot" "$ret"
}
+test_tree_commit_keywords()
+{
+ test_init tree_commit_keywords 48 11
+ local repo="$testroot/repo"
+ local wt="$testroot/wt"
+ local id=$(git_show_head "$repo")
+
+ set -A ids "$id"
+
+ got checkout "$repo" "$wt" > /dev/null
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "got checkout failed unexpectedly"
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ # move into the work tree (test is run in a subshell)
+ cd "$wt"
+
+ for i in $(seq 8); do
+ if [ $(( i % 2 )) -eq 0 ]; then
+ echo "file${i}" > "file${i}"
+ got add "file${i}" > /dev/null
+ else
+ echo "alpha $i" > alpha
+ fi
+
+ got ci -m "commit $i" > /dev/null
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "commit failed unexpectedly" >&2
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ id=$(git_show_head "$repo")
+ set -- "$ids" "$id"
+ ids=$*
+ done
+
+
+ cat <<-EOF >$TOG_TEST_SCRIPT
+ SCREENDUMP
+ EOF
+
+ cat <<-EOF >$testroot/view.expected
+ commit $(pop_id 8 $ids)
+ [1/7] /
+
+ alpha
+ beta
+ epsilon/
+ file2
+ file4
+ file6
+ gamma/
+
+ EOF
+
+ tog tree -c:base:-
+ cmp -s $testroot/view.expected $testroot/view
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u $testroot/view.expected $testroot/view
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ cat <<-EOF >$testroot/view.expected
+ commit $(pop_id 6 $ids)
+ [1/6] /
+
+ alpha
+ beta
+ epsilon/
+ file2
+ file4
+ gamma/
+
+
+ EOF
+
+ tog tree -cmaster:-3
+ cmp -s $testroot/view.expected $testroot/view
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u $testroot/view.expected $testroot/view
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ cat <<-EOF >$testroot/view.expected
+ commit $(pop_id 9 $ids)
+ [1/8] /
+
+ alpha
+ beta
+ epsilon/
+ file2
+ file4
+ file6
+ file8
+ gamma/
+ EOF
+
+ got up -c:head:-99 > /dev/null
+ tog tree -c:base:+99
+ cmp -s $testroot/view.expected $testroot/view
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u $testroot/view.expected $testroot/view
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ cat <<-EOF >$testroot/view.expected
+ commit $(pop_id 4 $ids)
+ [1/5] /
+
+ alpha
+ beta
+ epsilon/
+ file2
+ gamma/
+
+
+
+ EOF
+
+ tog tree -c:head:-5
+ cmp -s $testroot/view.expected $testroot/view
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u $testroot/view.expected $testroot/view
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ cat <<-EOF >$testroot/view.expected
+ commit $(pop_id 1 $ids)
+ [1/4] /
+
+ alpha
+ beta
+ epsilon/
+ gamma/
+
+
+
+
+ EOF
+
+ tog tree -r "$repo" -cmaster:-99
+ cmp -s $testroot/view.expected $testroot/view
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u $testroot/view.expected $testroot/view
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+ test_done "$testroot" "$ret"
+}
+
test_parseargs "$@"
run_test test_tree_basic
run_test test_tree_vsplit_blame
run_test test_tree_hsplit_blame
run_test test_tree_symlink
+run_test test_tree_commit_keywords
blob - e809641a54d987c934b5802c084bde5ad86dfc09
blob + f6118fb46d796b824e8f3299f780ac15cbedc117
--- tog/Makefile
+++ tog/Makefile
diff_patience.c bloom.c murmurhash2.c sigs.c date.c \
object_open_privsep.c read_gitconfig_privsep.c \
read_gotconfig_privsep.c pollfd.c reference_parse.c \
- object_qid.c
+ object_qid.c keyword.c
MAN = ${PROG}.1
CPPFLAGS = -I${.CURDIR}/../include -I${.CURDIR}/../lib
blob - 667bfe283076f37b6cb5690da6b2a98d9aae516a
blob + 816fab05d74cd0ab51f96eb3cad17d26d95b56e3
--- tog/tog.1
+++ tog/tog.1
.It Fl c Ar commit
Start traversing history at the specified
.Ar commit .
-The expected argument is the name of a branch or a commit ID SHA1 hash.
+The expected argument is a commit ID SHA1 hash, or a reference name or keyword
+which will be resolved to a commit ID.
An abbreviated hash argument will be expanded to a full SHA1 hash
automatically, provided the abbreviation is unique.
-If this option is not specified, default to the work tree's current branch
-if invoked in a work tree, or to the repository's HEAD reference.
+The keywords
+.Qq :base
+and
+.Qq :head
+resolve to the work tree's base commit and branch head, respectively.
+The former is only valid if invoked in a work tree, while the latter will
+resolve to the tip of the work tree's current branch if invoked in a
+work tree, otherwise it will resolve to the repository's HEAD reference.
+Keywords and references may be appended with
+.Qq :+
+or
+.Qq :-
+modifiers and an optional integer N to denote the
+Nth descendant or antecedent by first parent traversal, respectively;
+for example,
+.Sy :head:-2
+denotes the work tree branch head's 2nd generation ancestor, and
+.Sy :base:+4
+denotes the 4th generation descendant of the work tree's base commit.
+Similarly,
+.Sy foobar:+3
+will denote the 3rd generation descendant of the commit resolved by the
+.Qq foobar
+reference.
+A
+.Qq :+
+or
+.Qq :-
+modifier without a trailing integer has an implicit
+.Qq 1
+appended
+.Po e.g.,
+.Sy :base:+
+is equivalent to
+.Sy :base:+1
+.Pc .
.It Fl r Ar repository-path
Use the repository at the specified path.
If not specified, assume the repository is located at or above the current
.Ar object2
.Xc
Display the differences between two objects in the repository.
-Treat each of the two arguments as a reference, a tag name, or an object
-ID SHA1 hash, and display differences between the corresponding objects.
+Treat each of the two arguments as a reference, a tag name, an object
+ID SHA1 hash, or a keyword and display differences between the corresponding
+objects.
Both objects must be of the same type (blobs, trees, or commits).
An abbreviated hash argument will be expanded to a full SHA1 hash
automatically, provided the abbreviation is unique.
+The keywords
+.Qq :base
+and
+.Qq :head
+resolve to the work tree's base commit and branch head, respectively.
+The former is only valid if invoked in a work tree, while the latter will
+resolve to the tip of the work tree's current branch if invoked in a
+work tree, otherwise it will resolve to the repository's HEAD reference.
+Keywords and references may be appended with
+.Qq :+
+or
+.Qq :-
+modifiers and an optional integer N to denote the
+Nth descendant or antecedent by first parent traversal, respectively;
+for example,
+.Sy :head:-2
+denotes the work tree branch head's 2nd generation ancestor, and
+.Sy :base:+4
+denotes the 4th generation descendant of the work tree's base commit.
+Similarly,
+.Sy foobar:+3
+will denote the 3rd generation descendant of the commit resolved by the
+.Qq foobar
+reference.
+A
+.Qq :+
+or
+.Qq :-
+modifier without a trailing integer has an implicit
+.Qq 1
+appended
+.Po e.g.,
+.Sy :base:+
+is equivalent to
+.Sy :base:+1
+.Pc .
.Pp
The key bindings for
.Cm tog diff
.It Fl c Ar commit
Start traversing history at the specified
.Ar commit .
-The expected argument is the name of a branch or a commit ID SHA1 hash.
+The expected argument is a commit ID SHA1 hash, or a reference name or keyword
+which will be resolved to a commit ID.
An abbreviated hash argument will be expanded to a full SHA1 hash
automatically, provided the abbreviation is unique.
+The keywords
+.Qq :base
+and
+.Qq :head
+resolve to the work tree's base commit and branch head, respectively.
+The former is only valid if invoked in a work tree, while the latter will
+resolve to the tip of the work tree's current branch if invoked in a
+work tree, otherwise it will resolve to the repository's HEAD reference.
+Keywords and references may be appended with
+.Qq :+
+or
+.Qq :-
+modifiers and an optional integer N to denote the
+Nth descendant or antecedent by first parent traversal, respectively;
+for example,
+.Sy :head:-2
+denotes the work tree branch head's 2nd generation ancestor, and
+.Sy :base:+4
+denotes the 4th generation descendant of the work tree's base commit.
+Similarly,
+.Sy foobar:+3
+will denote the 3rd generation descendant of the commit resolved by the
+.Qq foobar
+reference.
+A
+.Qq :+
+or
+.Qq :-
+modifier without a trailing integer has an implicit
+.Qq 1
+appended
+.Po e.g.,
+.Sy :base:+
+is equivalent to
+.Sy :base:+1
+.Pc .
.It Fl r Ar repository-path
Use the repository at the specified path.
If not specified, assume the repository is located at or above the current
.It Fl c Ar commit
Start traversing history at the specified
.Ar commit .
-The expected argument is the name of a branch or a commit ID SHA1 hash.
+The expected argument is a commit ID SHA1 hash, or a reference name or keyword
+which will be resolved to a commit ID.
An abbreviated hash argument will be expanded to a full SHA1 hash
automatically, provided the abbreviation is unique.
+The keywords
+.Qq :base
+and
+.Qq :head
+resolve to the work tree's base commit and branch head, respectively.
+The former is only valid if invoked in a work tree, while the latter will
+resolve to the tip of the work tree's current branch if invoked in a
+work tree, otherwise it will resolve to the repository's HEAD reference.
+Keywords and references may be appended with
+.Qq :+
+or
+.Qq :-
+modifiers and an optional integer N to denote the
+Nth descendant or antecedent by first parent traversal, respectively;
+for example,
+.Sy :head:-2
+denotes the work tree branch head's 2nd generation ancestor, and
+.Sy :base:+4
+denotes the 4th generation descendant of the work tree's base commit.
+Similarly,
+.Sy foobar:+3
+will denote the 3rd generation descendant of the commit resolved by the
+.Qq foobar
+reference.
+A
+.Qq :+
+or
+.Qq :-
+modifier without a trailing integer has an implicit
+.Qq 1
+appended
+.Po e.g.,
+.Sy :base:+
+is equivalent to
+.Sy :base:+1
+.Pc .
.It Fl r Ar repository-path
Use the repository at the specified path.
If not specified, assume the repository is located at or above the current
blob - 9479ad1b9a79971165d3eaf5e113e8d1b6ff0ff7
blob + 55201d879df128d62d2a76ec797059af85649fa8
--- tog/tog.c
+++ tog/tog.c
#include "got_privsep.h"
#include "got_path.h"
#include "got_worktree.h"
+#include "got_keyword.h"
#ifndef MIN
#define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
screen_dump_path = getenv("TOG_SCR_DUMP");
if (screen_dump_path == NULL || *screen_dump_path == '\0')
return got_error_msg(GOT_ERR_IO, "TOG_SCR_DUMP not defined");
- tog_io.sdump = fopen(screen_dump_path, "wex");
+ tog_io.sdump = fopen(screen_dump_path, "we");
if (tog_io.sdump == NULL) {
err = got_error_from_errno2("fopen", screen_dump_path);
goto done;
struct got_worktree *worktree = NULL;
struct got_object_id *start_id = NULL;
char *in_repo_path = NULL, *repo_path = NULL, *cwd = NULL;
- char *start_commit = NULL, *label = NULL;
+ char *keyword_idstr = NULL, *start_commit = NULL, *label = NULL;
struct got_reference *ref = NULL;
const char *head_ref_name = NULL;
int ch, log_branches = 0;
goto done;
head_ref_name = label;
} else {
+ error = got_keyword_to_idstr(&keyword_idstr, start_commit,
+ repo, worktree);
+ if (error != NULL)
+ goto done;
+ if (keyword_idstr != NULL)
+ start_commit = keyword_idstr;
+
error = got_ref_open(&ref, repo, start_commit, 0);
if (error == NULL)
head_ref_name = got_ref_get_name(ref);
}
error = view_loop(view);
done:
+ free(keyword_idstr);
free(in_repo_path);
free(repo_path);
free(cwd);
struct got_object_id *id1 = NULL, *id2 = NULL;
char *repo_path = NULL, *cwd = NULL;
char *id_str1 = NULL, *id_str2 = NULL;
+ char *keyword_idstr1 = NULL, *keyword_idstr2 = NULL;
char *label1 = NULL, *label2 = NULL;
int diff_context = 3, ignore_whitespace = 0;
int ch, force_text_diff = 0;
if (error)
goto done;
+ if (id_str1 != NULL) {
+ error = got_keyword_to_idstr(&keyword_idstr1, id_str1,
+ repo, worktree);
+ if (error != NULL)
+ goto done;
+ if (keyword_idstr1 != NULL)
+ id_str1 = keyword_idstr1;
+ }
+ if (id_str2 != NULL) {
+ error = got_keyword_to_idstr(&keyword_idstr2, id_str2,
+ repo, worktree);
+ if (error != NULL)
+ goto done;
+ if (keyword_idstr2 != NULL)
+ id_str2 = keyword_idstr2;
+ }
+
error = got_repo_match_object_id(&id1, &label1, id_str1,
GOT_OBJ_TYPE_ANY, &tog_refs, repo);
if (error)
goto done;
error = view_loop(view);
done:
+ free(keyword_idstr1);
+ free(keyword_idstr2);
free(label1);
free(label2);
free(repo_path);
char *link_target = NULL;
struct got_object_id *commit_id = NULL;
struct got_commit_object *commit = NULL;
- char *commit_id_str = NULL;
+ char *keyword_idstr = NULL, *commit_id_str = NULL;
int ch;
struct tog_view *view = NULL;
int *pack_fds = NULL;
error = got_ref_resolve(&commit_id, repo, head_ref);
got_ref_close(head_ref);
} else {
+ error = got_keyword_to_idstr(&keyword_idstr, commit_id_str,
+ repo, worktree);
+ if (error != NULL)
+ goto done;
+ if (keyword_idstr != NULL)
+ commit_id_str = keyword_idstr;
+
error = got_repo_match_object_id(&commit_id, NULL,
commit_id_str, GOT_OBJ_TYPE_COMMIT, &tog_refs, repo);
}
free(link_target);
free(cwd);
free(commit_id);
+ free(keyword_idstr);
if (commit)
got_object_commit_close(commit);
if (worktree)
struct got_object_id *commit_id = NULL;
struct got_commit_object *commit = NULL;
const char *commit_id_arg = NULL;
- char *label = NULL;
+ char *keyword_idstr = NULL, *label = NULL;
struct got_reference *ref = NULL;
const char *head_ref_name = NULL;
int ch;
goto done;
head_ref_name = label;
} else {
+ error = got_keyword_to_idstr(&keyword_idstr, commit_id_arg,
+ repo, worktree);
+ if (error != NULL)
+ goto done;
+ if (keyword_idstr != NULL)
+ commit_id_arg = keyword_idstr;
+
error = got_ref_open(&ref, repo, commit_id_arg, 0);
if (error == NULL)
head_ref_name = got_ref_get_name(ref);
}
error = view_loop(view);
done:
+ free(keyword_idstr);
free(repo_path);
free(cwd);
free(commit_id);
error->code != GOT_ERR_EOF &&
error->code != GOT_ERR_PRIVSEP_EXIT &&
error->code != GOT_ERR_PRIVSEP_PIPE &&
- !(error->code == GOT_ERR_ERRNO && errno == EINTR))
+ !(error->code == GOT_ERR_ERRNO && errno == EINTR)) {
fprintf(stderr, "%s: %s\n", getprogname(), error->msg);
+ return 1;
+ }
return 0;
}