Home > Mobile >  Get the --no-index diff of files in two directories, but ignore pattern(s)
Get the --no-index diff of files in two directories, but ignore pattern(s)

Time:06-28

I have two directories with files that are similar and I want to see the diff of any files that are different. This works:

git diff --no-index ./dir1 ./dir2

However, there are files in those directories that I want to ignore in the diff. It apparently doesn't matter whether those files are included in a .gitignore which I think makes sense.

Is this possible?

More context, this is for a workshop and each directory is a step in the workshop. I want to have a way to show the needed changes in each step of the workshop. The directories have some generated files and I don't want to show those generated files in the output. Additionally, I've got some node_modules in there which would not be desirable in the output.

Also, I like the paging functionality of git diff. Also, most people going through the workshop are used to git diff. so I do want to use this rather than some other tool.

CodePudding user response:

Here's one way to go at it. Temporarily make a commit for each directory, then diff the changesets between those two commits for those directories.

git add dir1
git commit -m "this is dir1"
git add dir2
git commit -m "this is dir2"

And for the final trick

git diff HEAD~1:dir1 HEAD:dir2

CodePudding user response:

Here is a variation on @Marteen Bicknese's answer, which doesn't create new commits nor modifies your index, but which still writes the content of all files to compare in your local git storage :

# in a script file :

export GIT_INDEX_FILE=.git/my.tmp.index

git add dir1 dir2
CMP_TREE=$(git write-tree)
git diff $CMP_TREE:dir1 $CMP_TREE:dir2

rm $GIT_INDEX_FILE

if you're really into one liners, you can cheat and put the above commands between parentheses :

(export GIT_INDEX_FILE=.git/my.tmp.index; git add dir1 dir2; \
    CMP_TREE=$(git write-tree); \
    git diff $CMP_TREE:dir1 $CMP_TREE:dir2; rm $GIT_INDEX_FILE)

(note : parenthese start a subshell, so variables defined inside will not interfere with your current shell)


Turning it into a reusable script :

# in script file named git-dir-diff :
#!/bin/bash

path1=$1
path2=$2

export GIT_INDEX_FILE=`mktemp -u .git/my.XXXXXX.index`

git add "$path1" "$path2"
CMP_TREE=$(git write-tree)
git diff "$CMP_TREE:$path1" "$CMP_TREE:$path2"

rm $GIT_INDEX_FILE

if you put git-dir-diff in your path, you can then type :

git dir-diff dir1 dir2

additionally : if you want a more visual diff view of your directories, you can use git difftool -d in the script instead of git diff.

CodePudding user response:

My idea is to get the diff output first and then remove the diff hunks of the files you want to ignore. Here's a demo mydiff.py in Python(>=3.6). Disclaimer, the script is not fully tested.

#!/usr/bin/env python

import subprocess
import glob
import re
import sys

# the patterns of the ignored files
IGNORED_PATTERNS = [
    # regex, starting with ^
    '^. /c\.txt$',
    # glob, starting with *. The first * is removed before being consumed.
    '***/f.txt',
    # plain, others
    'foo/a.txt',
]


def ignored(path):
    matched = False
    for pattern in IGNORED_PATTERNS:
        if pattern.startswith('^') and re.findall(pattern, path):
            matched = True
            break
        elif pattern.startswith('*'):
            globs = [
                g.replace('\\', '/')
                for g in glob.glob(pattern[1:], recursive=True)
            ]
            if path in globs:
                matched = True
                break
        elif pattern == path:
            matched = True
            break
    return matched


_local = sys.argv[1]
_remote = sys.argv[2]
cmd = 'git diff --no-index %s %s' % (_local, _remote)
o = subprocess.getoutput(cmd)
lines = []
ignore = False
for line in o.split('\n'):
    if line.startswith('diff --git'):
        _, _, local_path, remote_path = line.strip().split()
        local_path = '/'.join(local_path.split('/')[1:])
        remote_path = '/'.join(remote_path.split('/')[1:])
        if ignored(local_path) or ignored(remote_path):
            ignore = True
            continue
        else:
            ignore = False
            lines.append(line)
    else:
        if ignore:
            continue
        else:
            lines.append(line)
print('\n'.join(lines))

You could edit IGNORED_PATTERNS or modify the script to read the patterns from a config file.

Usage, python mydiff.py dir1 dir2 | less. In Git-Bash for windows, use python.exe mydiff.py dir1 dir2 | less to avoid the error stdout is not a tty, or make mydiff.py executable and run ./mydiff.py dir1 dir2 | less.

  • Related