git - list of all changed but not deleted files in a commit
Asked Answered
S

3

19

I am investigating git repositories. I want to get the list of changed files in each commit.

So, what I did is I visited each commit through the command

git reset --hard <commitId>

Then, I used

git show --pretty="format:" --name-only #{commitId}

The problem with this one is that it gives the deleted files in that commitId which I don't want. I tried also:

git ls-files 

it doesn't return deleted files, however, it returns a list of all existing files that are new or were created in previous commit.

Example:

>commit 1
add "file1"
add "file2"

>commit 2
change "file1"

>commit 3
add "file3"
delete "file2"

so in this case, I will visit each commit. And, if I am in commit 1, I want to get a list of "file1" and "file2". If I am in commit 2, I will get "file1", and "file3" if I am in commit 3.

Any thought?

Switzerland answered 18/6, 2015 at 1:29 Comment(1)
A
25

Try using this command:

git show --diff-filter=AM --pretty="format:" --name-only #{commitId}

It is what you mentioned in your original problem with a --diff-filter flag added to restrict to only files which were added (A) or modified (M). For a complete list of the types of files to which you can restrict, have a look at the documentation for git show.

As @MauricioTrajano mentioned in his answer, you don't need to reset to a commit to investigate it using git show. All you need to know is the SHA-1 hash of the commit, which you can find by simply using git log on the branch in question.

Amadoamador answered 18/6, 2015 at 1:54 Comment(2)
The reason why I am resetting is that I want see these files at that time.Switzerland
Maybe you want to add R as an option to --diff-filter, so you also get renamed files.Seine
S
10

You don't have to reset HEAD to an earlier commit in order to do this, i.e. you don't have to lose your local changes, git diff allows you to compare between any two commits as long as you privide the commit hashes. In your case you can do:

git diff {COMMIT_1_HASH} {COMMIT_2_HASH} --name-only --diff-filter=AM

This can be used to see the files added and changed between any number of commits.

If you want to get the files added and modified for only one commit then just use the commit hash that comes right after the one you are trying to look at.

Surtax answered 18/6, 2015 at 2:3 Comment(0)
C
7

How to use git diff filters via --diff-filter=

To get a list of all changed files, excluding all deleted (via lower-case d filter) files, use the --diff-filter=d, like this:

# 1. see list of changed, but NOT 'd'eleted files since `from_commit_hash` to
# now
git diff --name-only --diff-filter=d from_commit_hash

# 2. specifying a range of commits:
git diff --name-only --diff-filter=d from_commit_hash to_commit_hash
# or (same thing)
git diff --name-only --diff-filter=d from_commit_hash..to_commit_hash

# 3. use the 3-dot syntax to look at just the changes since the common ancestor
# between `from_commit_hash` and `to_commit_hash`
# See: https://mcmap.net/q/11932/-what-are-the-differences-between-double-dot-quot-quot-and-triple-dot-quot-quot-in-git-diff-commit-ranges
git diff --name-only --diff-filter=d from_commit_hash...to_commit_hash
# or (same thing)
git diff --name-only --diff-filter=d \
    $(git merge-base from_commit_hash to_commit_hash) to_commit_hash

# 4. looking at all changes in `commit2` which are NOT in `commit1`
git diff --name-only --diff-filter=d ^commit1 commit2

You can confirm this against the full list of changed files by looking at both the file names and their changed statuses with --name-status:

# 1. 
git diff --name-status from_commit_hash

# 2. specifying a range of commits
git diff --name-status from_commit_hash to_commit_hash
# or (same thing)
git diff --name-status from_commit_hash..to_commit_hash

# etc. etc.

Note that I consider --diff-filter=d to be better than --diff-filter=AM because the former includes everything except 'd'eleted files, whereas the latter excludes everything (including deleted files) except 'A'dded and 'M'odified files. The former is therefore more-inclusive, excluding only what you really want to exclude, making it better in my opinion.

In --diff-filter=, CAPITAL filter letters INCLUDE vs lower-case filter letters exclude

Use CAPITAL letters, such as D, A, or M, etc., to include that type of file, and lower-case letters, such as d, a, or m, etc., respectively, to exclude that type of file.

Hence, the following is true:

--diff-filter=AM  # INCLUDE only Added and Modified files
# vs
--diff-filter=am  # EXCLUDE all added and modified files

From man git diff (emphasis added):

--diff-filter=[(A|C|D|M|R|T|U|X|B)...[*]]

Select only files that are Added (A), Copied (C), Deleted (D), Modified (M), Renamed (R), have their type (i.e. regular file, symlink, submodule, ...) changed (T), are Unmerged (U), are Unknown (X), or have had their pairing Broken (B). Any combination of the filter characters (including none) can be used. When * (All-or-none) is added to the combination, all paths are selected if there is any file that matches other criteria in the comparison; if there is no file that matches other criteria, nothing is selected.

Also, these upper-case letters can be downcased to exclude. E.g. --diff-filter=ad excludes added and deleted paths.

Note that not all diffs can feature all types. For instance, copied and renamed entries cannot appear if detection for those types is disabled.

References

  1. See the git diff --diff-filter= documentation here or with man git diff.
  2. See also this particular answer: How to get a list of all files that changed between two Git commits?
Chronic answered 16/3, 2021 at 5:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.