1#!/bin/sh
2
3test_description='various tests of reflog walk (log -g) behavior'
4GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
5export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
6
7. ./test-lib.sh
8
9test_expect_success 'set up some reflog entries' '
10	test_commit one &&
11	test_commit two &&
12	git checkout -b side HEAD^ &&
13	test_commit three &&
14	git merge --no-commit main &&
15	echo evil-merge-content >>one.t &&
16	test_tick &&
17	git commit --no-edit -a
18'
19
20do_walk () {
21	git log -g --format="%gd %gs" "$@"
22}
23
24test_expect_success 'set up expected reflog' '
25	cat >expect.all <<-EOF
26	HEAD@{0} commit (merge): Merge branch ${SQ}main${SQ} into side
27	HEAD@{1} commit: three
28	HEAD@{2} checkout: moving from main to side
29	HEAD@{3} commit: two
30	HEAD@{4} commit (initial): one
31	EOF
32'
33
34test_expect_success 'reflog walk shows expected logs' '
35	do_walk >actual &&
36	test_cmp expect.all actual
37'
38
39test_expect_success 'reflog can limit with --no-merges' '
40	grep -v merge expect.all >expect &&
41	do_walk --no-merges >actual &&
42	test_cmp expect actual
43'
44
45test_expect_success 'reflog can limit with pathspecs' '
46	grep two expect.all >expect &&
47	do_walk -- two.t >actual &&
48	test_cmp expect actual
49'
50
51test_expect_success 'pathspec limiting handles merges' '
52	# we pick up:
53	#   - the initial commit of one
54	#   - the checkout back to commit one
55	#   - the evil merge which touched one
56	sed -n "1p;3p;5p" expect.all >expect &&
57	do_walk -- one.t >actual &&
58	test_cmp expect actual
59'
60
61test_expect_success '--parents shows true parents' '
62	# convert newlines to spaces
63	echo $(git rev-parse HEAD HEAD^1 HEAD^2) >expect &&
64	git rev-list -g --parents -1 HEAD >actual &&
65	test_cmp expect actual
66'
67
68test_expect_success 'walking multiple reflogs shows all' '
69	# We expect to see all entries for all reflogs, but interleaved by
70	# date, with order on the command line breaking ties. We
71	# can use "sort" on the separate lists to generate this,
72	# but note two tricks:
73	#
74	#   1. We use "{" as the delimiter, which lets us skip to the reflog
75	#      date specifier as our second field, and then our "-n" numeric
76	#      sort ignores the bits after the timestamp.
77	#
78	#   2. POSIX leaves undefined whether this is a stable sort or not. So
79	#      we use "-k 1" to ensure that we see HEAD before main before
80	#      side when breaking ties.
81	{
82		do_walk --date=unix HEAD &&
83		do_walk --date=unix side &&
84		do_walk --date=unix main
85	} >expect.raw &&
86	sort -t "{" -k 2nr -k 1 <expect.raw >expect &&
87	do_walk --date=unix HEAD main side >actual &&
88	test_cmp expect actual
89'
90
91test_expect_success 'date-limiting does not interfere with other logs' '
92	do_walk HEAD@{1979-01-01} HEAD >actual &&
93	test_cmp expect.all actual
94'
95
96test_expect_success 'min/max age uses entry date to limit' '
97	# Flip between commits one and two so each ref update actually
98	# does something (and does not get optimized out). We know
99	# that the timestamps of those commits will be before our "min".
100
101	git update-ref -m before refs/heads/minmax one &&
102
103	test_tick &&
104	min=$test_tick &&
105	git update-ref -m min refs/heads/minmax two &&
106
107	test_tick &&
108	max=$test_tick &&
109	git update-ref -m max refs/heads/minmax one &&
110
111	test_tick &&
112	git update-ref -m after refs/heads/minmax two &&
113
114	cat >expect <<-\EOF &&
115	max
116	min
117	EOF
118	git log -g --since=$min --until=$max --format=%gs minmax >actual &&
119	test_cmp expect actual
120'
121
122# Create a situation where the reflog and ref database disagree about the latest
123# state of HEAD.
124test_expect_success REFFILES 'walk prefers reflog to ref tip' '
125	head=$(git rev-parse HEAD) &&
126	one=$(git rev-parse one) &&
127	ident="$GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE" &&
128	echo "$head $one $ident	broken reflog entry" >>.git/logs/HEAD &&
129
130	echo $one >expect &&
131	git log -g --format=%H -1 >actual &&
132	test_cmp expect actual
133'
134
135test_expect_success 'rev-list -g complains when there are no reflogs' '
136	test_must_fail git rev-list -g
137'
138
139test_done
140