Search code examples
gitgit-diff

Exclude directories from git diff on two separate repositories


I am trying to do a git diff between two separate repositories. Using git diff ProjectA ProjectB alone works, but I have to scroll through all the differences in the .git directory.

I've tried git diff ProjectA ProjectB -- . ':!.git' to exclude the .git directory, but I get the following error.

Not a git repository
To compare two paths outside a working tree:
usage: git diff [--no-index] <path> <path>

I've also tried git diff --no-index ProjectA ProjectB -- . ':!.git' but simply receive the message:

usage: git diff --no-index <path> <path>

What is the correct way to git diff two different repositories while excluding certain directories?


Solution

  • Much of what I have to say here is in other answers and their comments, but to fill in a few blanks, emphasize a few points, and generally provide what I hope is a single, organized, useful answer:


    Most forms of git diff expect to be run within a repository work tree, to compare two versions of a file (or of each of a set of files). For each file to be compared, maybe you're comparing the work tree version against the index version, or the version in commit A against the version in commit B.

    In these cases, though, you can't compare against something outside your repository (e.g., a path outside the work tree). If you try to refer to something outside your current repository work tree, and Git thinks you're using one of these forms, then it will raise an error.

    There is one specific form of git diff that lifts this restriction:

    git diff [--no-index] path1 path2
    

    where either: (a) you include the --no-index option, or (b) one of the paths is outside the current repository's work tree. In that case, Git will compare two arbitrary paths on your filesystem. But, various features of Git that are tied to a repository - like comparing with historical versions - aren't accessible when using this form.

    So, when you say

    git diff projectA projectB
    

    since that paths you've given are not both in a single repository work tree, Git figures it has to switch to this one special form, and so it works.

    But:

    That one special form is pretty limited. You only get to list the two root paths - not an arbitrary number of path specs, like when you compare versions of a file within a repository. When you start trying to give more general git diff syntax, then git says "well, this isn't the filesystem-to-filesystem comparison syntax, so I can't have this path outside the work tree"... and you get your error message.

    So you have two choices.

    You can use a tool other than Git to compare the directories. Such a tool might have functionality for path-based exclusions.

    Or, you can use Git, but do the comparison within a single repository.

    mkdir compare
    cd compare
    git init
    git remote add ProjectA ../ProjectA
    git remote add ProjectB ../ProjectB
    git fetch ProjectA
    git fetch ProjectB
    git diff ProjectA/master ProjectB/master
    

    Now Git understands that you're comparing two content versions.

    You can also do this by just making ProjectB a remote of ProjectA (or vice versa) and fetching so that one of the two repositories has both sets of objects. The thing to watch for is, just deleting the remote doesn't necessarily remove all of the objects fetched from the other repository. (It definitely doesn't remove them right away.)