2

I'm using git diff to get the differences between a commit and his parent for a specific file. I'm using this command :

git diff parent-sha child-sha -- file/to/path 

Here is my problem : with this command I can get added, deleted and modified files for a specific commit. But when I try it on my current commit, I can only get modified/deleted files. I'm looking for a way to get deleted and added files for the current commit (comparing to his parent).

For instance here's my uncommitted changes : enter image description here

If I run git diff HEAD -- yarn.lock

I get this

diff --git a/yarn.lock b/yarn.lock deleted file mode 100644 index c06acb9..0000000 --- a/yarn.lock +++ /dev/null @@ -1,10383 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"7zip-bin@~4.1.0": - version "4.1.0" - resolved "https://registry.yarnpkg.com/7zip-bin/-/7zip-bin-4.1.0.tgz#33eff662a5c39c0c2061170cc003c5120743fff0" - integrity sha512-AsnBZN3a8/JcNt+KPkGGODaA4c7l3W5+WpeKgGSbstSLxqWtTXqd1ieJGBQ8IFCtRg8DmmKUcSkIkUc0A4p3YA== - -"@angular-devkit/[email protected]": - version "0.11.4" - resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.11.4.tgz#f0cc3b4f1dd0128f6b41d3bb760bcf4c324cd063" - integrity sha512-2zi6S9tPlk52vyqN67IvFoeNgd0uxtrPlwl3TdvJ3wrH7sYGJnkQ+EzAE7cKUGWAV989BbNtx2YxhRDHnN21Fg== 

But nothing on git diff -- src/app/models/DiffFileInformation.ts

5
  • Did you run git diff HEAD^ HEAD? Commented Apr 1, 2019 at 10:31
  • No, diff has the same behaviour with HEAD or any other ref. Maybe there are no deleted/added files here? Commented Apr 1, 2019 at 10:32
  • @ElpieKay (or even just git diff HEAD^) Commented Apr 1, 2019 at 10:33
  • Ok I think I misunderstood. I'm looking for a way to get differences between current commit and his parent. Maybe HEAD is not the current commit. I mean, if I delete a file right now and try to get the output of git diff (without committing changes), what should I run? Commented Apr 1, 2019 at 10:35
  • Yes I tried with both commands and I only get the modified files (I'll edit for example) Commented Apr 1, 2019 at 10:37

4 Answers 4

4

ElpieKay's answer is correct (and I've upvoted it) but it might help you think about the problem if you take a step back and think about commits and how Git works.

Every commit holds several things, which we can break up into two major categories, data and metadata. The data in a commit is the source code snapshot, and the metadata is extra information about the data, such as who made the snapshot, when, and so on (and importantly, the parent hash ID for the parent of this commit, or if it's a merge commit, all of its parent hash IDs, but I think you have that part well under control now). Note that everything inside the commit is frozen for all time. You cannot change any part of either the data or the metadata.

In fact, this is the case for all of Git's internal objects. The hash ID of the Git object is a cryptographic checksum of the contents of that object. This is great for archival—every commit, once made, can never be changed—but it's completely useless for getting any new work done. To do new work, Git must provide some place(s) where files can be modified.

Every version control system has this problem, and in general, they all solve it the same way: the place where you work on your file is your work-tree. Files in the work-tree are malleable. Files in commits are not. That means there's something fundamentally different about a work-tree than there is about a commit. The work-tree could be a proposed commit, but it's still malleable, so it's not an actual commit. (It doesn't have any metadata, either.)

So, in Git, a work-tree does not have a hash ID. But for some reason, Git takes this even further. Instead of just having the work-tree be the proposed next commit, Git adds a third entity, sitting between HEAD—the current commit—and the work-tree. This third entity is called the index, or the staging area, or even sometimes the cache. (You'll see all three names in Git documentation. They all refer to the same thing.) This index is where Git stores the proposed next commit. Git then provides commands like git add that copy from the work-tree (where you have your files and can work on them) to the index (to update the proposed next commit).

This means git diff needs to be able to:

  • compare commit vs commit
  • compare commit vs index
  • compare commit vs work-tree
  • compare index vs work-tree

It provides four different ways to do this, depending on the arguments and --cached flag you pass to git diff:

  • git diff hash1 hash2 compares commit vs commit
  • git diff --cached hash compares commit vs index
  • git diff hash compares commit vs work-tree
  • git diff compares index vs work-tree

Pick which one you want, add -- <path> to restrict the diff output, and you're all set.

Sign up to request clarification or add additional context in comments.

Comments

2

The following 3 commands are not the same:

git diff git diff HEAD git diff HEAD^ HEAD 

Suppose we have initialized a repo and made two commits and some extra uncommitted changes.

git init foo cd foo touch a.txt b.txt git add . git commit -m 'first commit' echo hello >> a.txt echo hello >> b.txt git commit -m 'hello' echo world >> a.txt echo world >> b.txt # stage a.txt and leave b.txt alone git add a.txt 
  1. What does git diff return?

git diff compares the working tree and the index. The working tree has the modified version of a.txt and b.txt, and the index has only the modified version of a.txt. So the difference lies between the working tree's b.txt and the index's b.txt:

hello world 

VS

hello 

git diff returns:

diff --git a/b.txt b/b.txt index ce01362..94954ab 100644 --- a/b.txt +++ b/b.txt @@ -1 +1,2 @@ hello +world 
  1. What does git diff HEAD return?

It compares the files in the revision of HEAD with the files in the working tree. a.txt in HEAD is

hello 

a.txt in the working tree is

hello world 

b.txt is the same with a.txt, so git diff HEAD returns:

diff --git a/a.txt b/a.txt index ce01362..94954ab 100644 --- a/a.txt +++ b/a.txt @@ -1 +1,2 @@ hello +world diff --git a/b.txt b/b.txt index ce01362..94954ab 100644 --- a/b.txt +++ b/b.txt @@ -1 +1,2 @@ hello +world 
  1. What does git diff HEAD^ HEAD return?

It compares the files of the former revision with the files of the latter. In HEAD^, both a.txt and b.txt are empty. In HEAD, both are:

hello 

So we get the output of git diff HEAD^ HEAD as:

diff --git a/a.txt b/a.txt index e69de29..ce01362 100644 --- a/a.txt +++ b/a.txt @@ -0,0 +1 @@ +hello diff --git a/b.txt b/b.txt index e69de29..ce01362 100644 --- a/b.txt +++ b/b.txt @@ -0,0 +1 @@ +hello 

If we swap HEAD^ and HEAD, git diff HEAD HEAD^ returns:

diff --git a/a.txt b/a.txt index ce01362..e69de29 100644 --- a/a.txt +++ b/a.txt @@ -1 +0,0 @@ -hello diff --git a/b.txt b/b.txt index ce01362..e69de29 100644 --- a/b.txt +++ b/b.txt @@ -1 +0,0 @@ -hello 

HEAD and HEAD^ could be any commits reachable in the repository. Instead of swapping the revisions, we can also get the reversed diff with the option -R, git diff -R HEAD^ HEAD.

Not sure what your purpose exactly is. Maybe you can find the solution here. More syntaxes of git diff are described.

Comments

1

git diff HEAD -- path will show you your local modifications.

The file src/app/models/DiffFileInformation.ts is untracked and unstaged, so it won't appear in your diff.

To see it in the diff, you will need to stage it (add it) first.

2 Comments

There is no way I can get it with options?
No, not as far as I know. Basically, the diff of the file is the whole file itself. What exactly are you trying achieve? Stage something specific from the file?
0

I figured out that for new files added to git which are not staged yet, you could try:

git diff /dev/null "src/app/models/DiffFileInformation.ts" 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.