Skip to content

Paths matching a pathlist entry are skipped by diff, status and checkout (DISABLE_PATHSPEC_MATCH) #7391

Description

@yerseg

Reproduction steps

Two trees with foo-bar/c and foo/y, both files changed between them. Diff them with a pathlist:

char *paths[] = { "foo", "foo-bar/b" };

opts.flags = GIT_DIFF_DISABLE_PATHSPEC_MATCH;
opts.pathspec.strings = paths;
opts.pathspec.count = 2;

git_diff_tree_to_tree(&diff, repo, old_tree, new_tree, &opts);

Expected behavior

M foo/y, same as git diff-tree -r <old> <new> -- foo foo-bar/b.

Actual behavior

The diff is empty.

It looks like the problem is in iterator_pathlist_next_is. It bumps pathlist_walk_idx whenever some pathlist entry sorts before the path, even if that entry isn't the one at pathlist_walk_idx. At foo-bar/c, foo-bar/b sorts before it, so the index moves past foo, and foo/y never matches after that.

Tree and index iterators both go through this code, so it's not only diff. With the same two paths and pathlist:

  • git_status_list with GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH, after changing both files in the workdir, reports foo/ as untracked. git status -- foo foo-bar/b shows M foo/y.
  • git_checkout_tree of the new tree with paths and GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH doesn't update foo/y. With GIT_CHECKOUT_FORCE it deletes foo/y from the workdir.

Version of libgit2 (release number or SHA1)

main (0551dfd)

Operating system(s) tested

Linux

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions