3

I know that a git commit changed multiple files in the directory src/java/task

It want to list all files in that directory that were not changed as part of that commit.

Real world context: I'm reviewing changes by someone and believe they should have made a similar change to every file in that directory. I want to know any files they didn't change in their commit (that may have been missed, or actually didn't need changing but I want to examine why).

Chris R
  • 2,464
  • 3
  • 25
  • 31
  • Sounds like you want a command which lists all files in a repo then filters out changed files in the commit? – evolutionxbox Jul 05 '19 at 10:45
  • I found something like `git diff-tree --no-commit-id --name-only -r HEAD | xargs -n1 -I % sh -c 'tree -fia . | grep -v %', but I don't see how useful this is. – evolutionxbox Jul 05 '19 at 11:00
  • @evolutionxbox yes although actually I only care about a specific sub-directory of the repo in this case. – Chris R Jul 05 '19 at 13:38

2 Answers2

2

If you can use bash:

comm -23 <(find src/java/task | sort) <(git diff-tree --no-commit-id --name-only -r $COMMIT_HASH | sort)

comm takes two files and generate an output with three columns, first column are lines unique to file1, second column are lines unique to file2 and third column are lines that appear in both files.

We take as the first file a list of all files in directory src/java/task:

find src/java/task | sort

As a second file, the files that were changed since last commit

git diff-tree --no-commit-id --name-only -r $COMMIT_HASH | sort

We need the files unique in the first file (files not changed) so we only need the first column. Using -23 as a parameter of comm will supress column 2 and 3, so we only get the first column.

Notice that you need need to sort the results of every file.

You may need to tweak this a bit but more or less that's a way to do it.

phd
  • 82,685
  • 13
  • 120
  • 165
ordago
  • 377
  • 3
  • 20
  • 1
    `find .src/java/task` didn't work as all lines then started with `.src` whereas the lines from git started `src` (no .) so all lines were show as different. Instead I used `find src/java/task` – Chris R Jul 05 '19 at 11:20
  • 1
    Also for the second file I used this to get the list of files changed in the commit: `git diff-tree --no-commit-id --name-only -r` _`commit-hash`_ as recommended here: https://stackoverflow.com/a/424142/184325 – Chris R Jul 05 '19 at 11:23
1
#!/bin/bash

commit=$1

# all files under src/java/task/, excluding subfolders
all=$(git ls-tree ${commit}:src/java/task | awk '/ blob /{print "src/java/task/"$4}')

# files changed by the commit
changed=$(git show ${commit} --pretty= --name-only)

# files not changed by the commit
for f in ${all} ${changed} ${changed};do
    echo ${f}
done | sort | uniq -u

Suppose the script is foo.sh, the repository is at /path/to/foo/, and the commit is HEAD. To run the script,

GIT_DIR=/path/to/foo/.git bash foo.sh HEAD

There may be a git command with some magic options to do the job, but I can't find any yet.

ElpieKay
  • 27,194
  • 6
  • 32
  • 53
  • I haven't tried this to know if it would have worked how I wanted since I was already testing the other answer before this was posted. – Chris R Jul 05 '19 at 11:50