git/t/t6000-rev-list-misc.sh

187 lines
4.9 KiB
Bash
Raw Permalink Normal View History

#!/bin/sh
test_description='miscellaneous rev-list tests'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
tests: mark tests relying on the current default for `init.defaultBranch` In addition to the manual adjustment to let the `linux-gcc` CI job run the test suite with `master` and then with `main`, this patch makes sure that GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME is set in all test scripts that currently rely on the initial branch name being `master by default. To determine which test scripts to mark up, the first step was to force-set the default branch name to `master` in - all test scripts that contain the keyword `master`, - t4211, which expects `t/t4211/history.export` with a hard-coded ref to initialize the default branch, - t5560 because it sources `t/t556x_common` which uses `master`, - t8002 and t8012 because both source `t/annotate-tests.sh` which also uses `master`) This trick was performed by this command: $ sed -i '/^ *\. \.\/\(test-lib\|lib-\(bash\|cvs\|git-svn\)\|gitweb-lib\)\.sh$/i\ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master\ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\ ' $(git grep -l master t/t[0-9]*.sh) \ t/t4211*.sh t/t5560*.sh t/t8002*.sh t/t8012*.sh After that, careful, manual inspection revealed that some of the test scripts containing the needle `master` do not actually rely on a specific default branch name: either they mention `master` only in a comment, or they initialize that branch specificially, or they do not actually refer to the current default branch. Therefore, the aforementioned modification was undone in those test scripts thusly: $ git checkout HEAD -- \ t/t0027-auto-crlf.sh t/t0060-path-utils.sh \ t/t1011-read-tree-sparse-checkout.sh \ t/t1305-config-include.sh t/t1309-early-config.sh \ t/t1402-check-ref-format.sh t/t1450-fsck.sh \ t/t2024-checkout-dwim.sh \ t/t2106-update-index-assume-unchanged.sh \ t/t3040-subprojects-basic.sh t/t3301-notes.sh \ t/t3308-notes-merge.sh t/t3423-rebase-reword.sh \ t/t3436-rebase-more-options.sh \ t/t4015-diff-whitespace.sh t/t4257-am-interactive.sh \ t/t5323-pack-redundant.sh t/t5401-update-hooks.sh \ t/t5511-refspec.sh t/t5526-fetch-submodules.sh \ t/t5529-push-errors.sh t/t5530-upload-pack-error.sh \ t/t5548-push-porcelain.sh \ t/t5552-skipping-fetch-negotiator.sh \ t/t5572-pull-submodule.sh t/t5608-clone-2gb.sh \ t/t5614-clone-submodules-shallow.sh \ t/t7508-status.sh t/t7606-merge-custom.sh \ t/t9302-fast-import-unpack-limit.sh We excluded one set of test scripts in these commands, though: the range of `git p4` tests. The reason? `git p4` stores the (foreign) remote branch in the branch called `p4/master`, which is obviously not the default branch. Manual analysis revealed that only five of these tests actually require a specific default branch name to pass; They were modified thusly: $ sed -i '/^ *\. \.\/lib-git-p4\.sh$/i\ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master\ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\ ' t/t980[0167]*.sh t/t9811*.sh Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-11-18 23:44:19 +00:00
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
echo content1 >wanted_file &&
echo content2 >unwanted_file &&
git add wanted_file unwanted_file &&
2020-07-07 21:41:51 +00:00
test_tick &&
git commit -m one
'
test_expect_success 'rev-list --objects heeds pathspecs' '
git rev-list --objects HEAD -- wanted_file >output &&
grep wanted_file output &&
! grep unwanted_file output
'
test_expect_success 'rev-list --objects with pathspecs and deeper paths' '
mkdir foo &&
>foo/file &&
git add foo/file &&
2020-07-07 21:41:51 +00:00
test_tick &&
git commit -m two &&
git rev-list --objects HEAD -- foo >output &&
grep foo/file output &&
git rev-list --objects HEAD -- foo/file >output &&
grep foo/file output &&
! grep unwanted_file output
'
test_expect_success 'rev-list --objects with pathspecs and copied files' '
git checkout --orphan junio-testcase &&
git rm -rf . &&
mkdir two &&
echo frotz >one &&
cp one two/three &&
git add one two/three &&
test_tick &&
git commit -m that &&
ONE=$(git rev-parse HEAD:one) &&
git rev-list --objects HEAD two >output &&
grep "$ONE two/three" output &&
! grep one output
'
test_expect_success 'rev-list --objects --no-object-names has no space/names' '
git rev-list --objects --no-object-names HEAD >output &&
! grep wanted_file output &&
! grep unwanted_file output &&
! grep " " output
'
test_expect_success 'rev-list --objects --no-object-names works with cat-file' '
git rev-list --objects --no-object-names --all >list-output &&
git cat-file --batch-check <list-output >cat-output &&
! grep missing cat-output
'
test_expect_success '--no-object-names and --object-names are last-one-wins' '
git rev-list --objects --no-object-names --object-names --all >output &&
grep wanted_file output &&
git rev-list --objects --object-names --no-object-names --all >output &&
! grep wanted_file output
'
test_expect_success 'rev-list A..B and rev-list ^A B are the same' '
2020-07-07 21:41:51 +00:00
test_tick &&
git commit --allow-empty -m another &&
git tag -a -m "annotated" v1.0 &&
git rev-list --objects ^v1.0^ v1.0 >expect &&
git rev-list --objects v1.0^..v1.0 >actual &&
test_cmp expect actual
'
revision: mark contents of an uninteresting tree uninteresting "git rev-list --objects ^A^{tree} B^{tree}" ought to mean "I want a list of objects inside B's tree, but please exclude the objects that appear inside A's tree". we see the top-level tree marked as uninteresting (i.e. ^A^{tree} in the above example) and call mark_tree_uninteresting() on it; this unfortunately prevents us from recursing into the tree and marking the objects in the tree as uninteresting. The reason why "git log ^A A" yields an empty set of commits, i.e. we do not have a similar issue for commits, is because we call mark_parents_uninteresting() after seeing an uninteresting commit. The uninteresting-ness of the commit itself does not prevent its parents from being marked as uninteresting. Introduce mark_tree_contents_uninteresting() and structure the code in handle_commit() in such a way that it makes it the responsibility of the callchain leading to this function to mark commits, trees and blobs as uninteresting, and also make it the responsibility of the helpers called from this function to mark objects that are reachable from them. Note that this is a very old bug that probably dates back to the day when "rev-list --objects" was introduced. The line to clear tree->object.parsed at the end of mark_tree_contents_uninteresting() can be removed when this fix is merged to the codebase after 6e454b9a (clear parsed flag when we free tree buffers, 2013-06-05). Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-01-15 23:38:01 +00:00
test_expect_success 'propagate uninteresting flag down correctly' '
git rev-list --objects ^HEAD^{tree} HEAD^{tree} >actual &&
test_must_be_empty actual
revision: mark contents of an uninteresting tree uninteresting "git rev-list --objects ^A^{tree} B^{tree}" ought to mean "I want a list of objects inside B's tree, but please exclude the objects that appear inside A's tree". we see the top-level tree marked as uninteresting (i.e. ^A^{tree} in the above example) and call mark_tree_uninteresting() on it; this unfortunately prevents us from recursing into the tree and marking the objects in the tree as uninteresting. The reason why "git log ^A A" yields an empty set of commits, i.e. we do not have a similar issue for commits, is because we call mark_parents_uninteresting() after seeing an uninteresting commit. The uninteresting-ness of the commit itself does not prevent its parents from being marked as uninteresting. Introduce mark_tree_contents_uninteresting() and structure the code in handle_commit() in such a way that it makes it the responsibility of the callchain leading to this function to mark commits, trees and blobs as uninteresting, and also make it the responsibility of the helpers called from this function to mark objects that are reachable from them. Note that this is a very old bug that probably dates back to the day when "rev-list --objects" was introduced. The line to clear tree->object.parsed at the end of mark_tree_contents_uninteresting() can be removed when this fix is merged to the codebase after 6e454b9a (clear parsed flag when we free tree buffers, 2013-06-05). Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-01-15 23:38:01 +00:00
'
test_expect_success 'symleft flag bit is propagated down from tag' '
git log --format="%m %s" --left-right v1.0...main >actual &&
cat >expect <<-\EOF &&
< another
< that
2020-07-07 21:41:51 +00:00
> two
> one
EOF
test_cmp expect actual
'
test_expect_success 'rev-list can show index objects' '
# Of the blobs and trees in the index, note:
#
# - we do not show two/three, because it is the
# same blob as "one", and we show objects only once
#
# - we do show the tree "two", because it has a valid cache tree
# from the last commit
#
# - we do not show the root tree; since we updated the index, it
# does not have a valid cache tree
#
echo only-in-index >only-in-index &&
test_when_finished "git reset --hard" &&
rev1=$(git rev-parse HEAD:one) &&
rev2=$(git rev-parse HEAD:two) &&
revi=$(git hash-object only-in-index) &&
cat >expect <<-EOF &&
$rev1 one
$revi only-in-index
$rev2 two
EOF
git add only-in-index &&
git rev-list --objects --indexed-objects >actual &&
test_cmp expect actual
'
test_expect_success 'rev-list can negate index objects' '
git rev-parse HEAD >expect &&
git rev-list -1 --objects HEAD --not --indexed-objects >actual &&
test_cmp expect actual
'
test_expect_success '--bisect and --first-parent can be combined' '
git rev-list --bisect --first-parent HEAD
'
test_expect_success '--header shows a NUL after each commit' '
# We know that there is no Q in the true payload; names and
# addresses of the authors and the committers do not have
# any, and object names or header names do not, either.
git rev-list --header --max-count=2 HEAD |
nul_to_q |
grep "^Q" >actual &&
cat >expect <<-EOF &&
Q$(git rev-parse HEAD~1)
Q
EOF
test_cmp expect actual
'
revision: allow --end-of-options to end option parsing There's currently no robust way to tell Git that a particular option is meant to be a revision, and not an option. So if you have a branch "refs/heads/--foo", you cannot just say: git rev-list --foo You can say: git rev-list refs/heads/--foo But that breaks down if you don't know the refname, and in particular if you're a script passing along a value from elsewhere. In most programs, you can use "--" to end option parsing, like this: some-prog -- "$revision" But that doesn't work for the revision parser, because "--" is already meaningful there: it separates revisions from pathspecs. So we need some other marker to separate options from revisions. This patch introduces "--end-of-options", which serves that purpose: git rev-list --oneline --end-of-options "$revision" will work regardless of what's in "$revision" (well, if you say "--" it may fail, but it won't do something dangerous, like triggering an unexpected option). The name is verbose, but that's probably a good thing; this is meant to be used for scripted invocations where readability is more important than terseness. One alternative would be to introduce an explicit option to mark a revision, like: git rev-list --oneline --revision="$revision" That's slightly _more_ informative than this commit (because it makes even something silly like "--" unambiguous). But the pattern of using a separator like "--" is well established in git and in other commands, and it makes some scripting tasks simpler like: git rev-list --end-of-options "$@" There's no documentation in this patch, because it will make sense to describe the feature once it is available everywhere (and support will be added in further patches). Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-08-06 14:39:58 +00:00
test_expect_success 'rev-list --end-of-options' '
git update-ref refs/heads/--output=yikes HEAD &&
git rev-list --end-of-options --output=yikes >actual &&
test_path_is_missing yikes &&
git rev-list HEAD >expect &&
test_cmp expect actual
'
test_expect_success 'rev-list --count' '
count=$(git rev-list --count HEAD) &&
git rev-list HEAD >actual &&
test_line_count = $count actual
'
test_expect_success 'rev-list --count --objects' '
count=$(git rev-list --count --objects HEAD) &&
git rev-list --objects HEAD >actual &&
test_line_count = $count actual
'
list-objects: drop --unpacked non-commit objects from results In git-rev-list(1), we describe the `--unpacked` option as: Only useful with `--objects`; print the object IDs that are not in packs. This is true of commits, which we discard via get_commit_action(), but not of the objects they reach. So if we ask for an --objects traversal with --unpacked, we may get arbitrarily many objects which are indeed packed. I am nearly certain this behavior dates back to the introduction of `--unpacked` via 12d2a18780 ("git rev-list --unpacked" shows only unpacked commits, 2005-07-03), but I couldn't get that revision of Git to compile for me. At least as early as v2.0.0 this has been subtly broken: $ git.compile --version git version 2.0.0 $ git.compile rev-list --objects --all --unpacked 72791fe96c93f9ec5c311b8bc966ab349b3b5bbe 05713d991c18bbeef7e154f99660005311b5004d v1.0 153ed8b7719c6f5a68ce7ffc43133e95a6ac0fdb 8e4020bb5a8d8c873b25de15933e75cc0fc275df one 9200b628cf9dc883a85a7abc8d6e6730baee589c two 3e6b46e1b7e3b91acce99f6a823104c28aae0b58 unpacked.t There, only the first, third, and sixth entries are loose, with the remaining set of objects belonging to at least one pack. The implications for this are relatively benign: bare 'git repack' invocations which invoke pack-objects with --unpacked are impacted, and at worst we'll store a few extra objects that should have been excluded. Arguably changing this behavior is a backwards-incompatible change, since it alters the set of objects emitted from rev-list queries with `--objects` and `--unpacked`. But I argue that this change is still sensible, since the existing implementation deviates from clearly-written documentation. The fix here is straightforward: avoid showing any non-commit objects which are contained in packs by discarding them within list-objects.c, before they are shown to the user. Note that similar treatment for `list-objects.c::show_commit()` is not needed, since that case is already handled by `revision.c::get_commit_action()`. Co-authored-by: Jeff King <peff@peff.net> Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2023-11-06 22:56:30 +00:00
test_expect_success 'rev-list --unpacked' '
git repack -ad &&
test_commit unpacked &&
git rev-list --objects --no-object-names unpacked^.. >expect.raw &&
sort expect.raw >expect &&
git rev-list --all --objects --unpacked --no-object-names >actual.raw &&
sort actual.raw >actual &&
test_cmp expect actual
'
test_done