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
.