mirror of
https://github.com/git/git
synced 2024-08-25 10:45:59 +00:00
![Derrick Stolee](/assets/img/avatar_default.png)
The previous change implemented the ahead_behind() method, including an algorithm to compute the ahead/behind values for a number of commit tips relative to a number of commit bases. Now, integrate that algorithm as part of 'git for-each-ref' hidden behind a new format atom, ahead-behind. This naturally extends to 'git branch' and 'git tag' builtins, as well. This format allows specifying multiple bases, if so desired, and all matching references are compared against all of those bases. For this reason, failing to read a reference provided from these atoms results in an error. In order to translate the ahead_behind() method information to the format output code in ref-filter.c, we must populate arrays of ahead_behind_count structs. In struct ref_array, we store the full array that will be passed to ahead_behind(). In struct ref_array_item, we store an array of pointers that point to the relvant items within the full array. In this way, we can pull all relevant ahead/behind values directly when formatting output for a specific item. It also ensures the lifetime of the ahead_behind_count structs matches the time that the array is being used. Add specific tests of the ahead/behind counts in t6600-test-reach.sh, as it has an interesting repository shape. In particular, its merging strategy and its use of different commit-graphs would demonstrate over- counting if the ahead_behind() method did not already account for that possibility. Also add tests for the specific for-each-ref, branch, and tag builtins. In the case of 'git tag', there are intersting cases that happen when some of the selected tips are not commits. This requires careful logic around commits_nr in the second loop of filter_ahead_behind(). Also, the test in t7004 is carefully located to avoid being dependent on the GPG prereq. It also avoids using the test_commit helper, as that will add ticks to the time and disrupt the expected timestamps in later tag tests. Also add performance tests in a new p1300-graph-walks.sh script. This will be useful for more uses in the future, but for now compare the ahead-behind counting algorithm in 'git for-each-ref' to the naive implementation by running 'git rev-list --count' processes for each input. For the Git source code repository, the improvement is already obvious: Test this tree --------------------------------------------------------------- 1500.2: ahead-behind counts: git for-each-ref 0.07(0.07+0.00) 1500.3: ahead-behind counts: git branch 0.07(0.06+0.00) 1500.4: ahead-behind counts: git tag 0.07(0.06+0.00) 1500.5: ahead-behind counts: git rev-list 1.32(1.04+0.27) But the standard performance benchmark is the Linux kernel repository, which demosntrates a significant improvement: Test this tree --------------------------------------------------------------- 1500.2: ahead-behind counts: git for-each-ref 0.27(0.24+0.02) 1500.3: ahead-behind counts: git branch 0.27(0.24+0.03) 1500.4: ahead-behind counts: git tag 0.28(0.27+0.01) 1500.5: ahead-behind counts: git rev-list 4.57(4.03+0.54) The 'git rev-list' test exists in this change as a demonstration, but it will be removed in the next change to avoid wasting time on this comparison. Signed-off-by: Derrick Stolee <derrickstolee@github.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
72 lines
2 KiB
Bash
Executable file
72 lines
2 KiB
Bash
Executable file
#!/bin/sh
|
|
|
|
test_description='for-each-ref errors for broken refs'
|
|
|
|
TEST_PASSES_SANITIZE_LEAK=true
|
|
. ./test-lib.sh
|
|
|
|
ZEROS=$ZERO_OID
|
|
|
|
test_expect_success setup '
|
|
MISSING=$(test_oid deadbeef) &&
|
|
git commit --allow-empty -m "Initial" &&
|
|
git tag testtag &&
|
|
git for-each-ref >full-list &&
|
|
git for-each-ref --format="%(objectname) %(refname)" >brief-list
|
|
'
|
|
|
|
test_expect_success 'Broken refs are reported correctly' '
|
|
r=refs/heads/bogus &&
|
|
: >.git/$r &&
|
|
test_when_finished "rm -f .git/$r" &&
|
|
echo "warning: ignoring broken ref $r" >broken-err &&
|
|
git for-each-ref >out 2>err &&
|
|
test_cmp full-list out &&
|
|
test_cmp broken-err err
|
|
'
|
|
|
|
test_expect_success 'NULL_SHA1 refs are reported correctly' '
|
|
r=refs/heads/zeros &&
|
|
echo $ZEROS >.git/$r &&
|
|
test_when_finished "rm -f .git/$r" &&
|
|
echo "warning: ignoring broken ref $r" >zeros-err &&
|
|
git for-each-ref >out 2>err &&
|
|
test_cmp full-list out &&
|
|
test_cmp zeros-err err &&
|
|
git for-each-ref --format="%(objectname) %(refname)" >brief-out 2>brief-err &&
|
|
test_cmp brief-list brief-out &&
|
|
test_cmp zeros-err brief-err
|
|
'
|
|
|
|
test_expect_success 'Missing objects are reported correctly' '
|
|
r=refs/heads/missing &&
|
|
echo $MISSING >.git/$r &&
|
|
test_when_finished "rm -f .git/$r" &&
|
|
echo "fatal: missing object $MISSING for $r" >missing-err &&
|
|
test_must_fail git for-each-ref 2>err &&
|
|
test_cmp missing-err err &&
|
|
(
|
|
cat brief-list &&
|
|
echo "$MISSING $r"
|
|
) | sort -k 2 >missing-brief-expected &&
|
|
git for-each-ref --format="%(objectname) %(refname)" >brief-out 2>brief-err &&
|
|
test_cmp missing-brief-expected brief-out &&
|
|
test_must_be_empty brief-err
|
|
'
|
|
|
|
test_expect_success 'ahead-behind requires an argument' '
|
|
test_must_fail git for-each-ref \
|
|
--format="%(ahead-behind)" 2>err &&
|
|
echo "fatal: expected format: %(ahead-behind:<committish>)" >expect &&
|
|
test_cmp expect err
|
|
'
|
|
|
|
test_expect_success 'missing ahead-behind base' '
|
|
test_must_fail git for-each-ref \
|
|
--format="%(ahead-behind:refs/heads/missing)" 2>err &&
|
|
echo "fatal: failed to find '\''refs/heads/missing'\''" >expect &&
|
|
test_cmp expect err
|
|
'
|
|
|
|
test_done
|