I need to list commits that touch one path in the source tree but not another.
D - head
C - touched foo and bar
B - touched foo
A - baseline
Between A and D I want a list of all commits touching folder foo unless they also touch folder bar, in other words, in the example above I would expect to see B but not C.
I tried git rev-list A..D --exclude='bar' -- foo
but that gives me both B and C still.
Please advise.
There is nothing built into Git to do this. However, it's easy to construct with a small shell script using the
comm
command. Simply get a list of all commits that affect interesting files, and a second list of all commits that affect files that make the commit uninteresting, then usecomm
to extract the interesting items (those that appear in the first list, but not in both the first and second list).Hence:
Note that the "sorted" requirement for
comm
is deliberately violate-able (and is violated here); if your particularcomm
insists on it, you may need to write your own variation.Edit: I tested VonC's suggestion, in Git 2.8.1, by making a new repository with an initial commit with files A/a and B/b:
Adding
-- A
correctly discards theB only
commit:However, adding
:(exclude):B
has no effect on the selected commits:Commit
731a059
, which touches files A/a and B/b, still appears in the output, as does initial commitf134515
. The difference is that when the two commits that also affect B/b are selected, the file B/b is omitted. The original question calls for the entire commit to be excluded.Edit 2 (using
comm
and bash's<(...)
syntax, to omit the temp files):This is the desired output, since only commit
b4bb2
affects only theA
directory.Since Git 1.9, and the introduction pathspec magic
:(exclude)
and its short form:!
, the syntax should be:However, this would still list C, even though the files displayed for that commit would not include files with
bar
in its path:The pathspec exclusion works, but
C
is still listed.