Jellicle
Jellicle

Reputation: 30206

Why is output from 'git diff' different than 'git show'?

I expected git show <commit> and git diff <commit>^ <commit> to show the all changes that took place in a given commit, but I see that their list of changes differs. (See example below.) What's the correct understanding of their function, then?

Yes, I've read the man pages

git show

For commits it shows the log message and textual diff. It also presents the
   merge commit in a special format as produced by git diff-tree --cc.

git diff

git diff [--options] <commit> <commit> [--] [<path>...]
       This is to view the changes between two arbitrary <commit>.

E.g.

$ MY_COMMIT=7c95d118c9837f801f4e314732c593e25feba3b1

git show and its output:

$ git show --name-only $MY_COMMIT
commit 7c95d118c9837f801f4e314732c593e25feba3b1
Merge: 5f308b4 9ef9bd7
Author: Me <[email protected]>
Date:   Thu Apr 23 14:14:58 2015 -0700

    Merge branch 'develop' of github.com:pic-development/dataraptor into develop

    Conflicts:
        app/controllers/application_controller.rb
        app/controllers/usage/staff_assignment_controller.rb
        app/views/crm/connections/_show.html.erb
        app/views/crm/task_builders/_task_builders.html.haml
        spec/controllers/contacts_controller_spec.rb
        spec/controllers/crm/connections_controller_spec.rb

app/controllers/application_controller.rb
app/controllers/usage/staff_assignment_controller.rb
app/views/crm/connections/_show.html.erb

git diff and its output:

$ git diff --name-only $MY_COMMIT^ $MY_COMMIT
app/assets/javascripts/application/quoting/ng-new-quote.js
app/assets/stylesheets/application-layout.css.scss
app/assets/stylesheets/application.css
app/controllers/application_controller.rb
app/controllers/crm/connections_controller.rb
app/controllers/usage/staff_assignment_controller.rb
app/models/crm/connection.rb
app/models/usage/permissions.rb
app/views/crm/connections/_show.html.erb
app/views/crm/task_builders/_task_builder.html.erb
app/views/layouts/application.html.erb
app/views/marketing/campaigns/_index.html.haml
app/views/marketing/campaigns/_task_builders.html.haml
app/views/shared/tab/_agency_management.html.erb
app/views/shared/tab/_contracts.html.erb
app/views/shared/tab/_help.html.erb
app/views/shared/tab/_marketing.html.erb
app/views/shared/tab/_my_account.html.erb
app/views/shared/tab/_reporting.html.erb
app/views/shared/tab/_sales_tools.html.erb
app/views/shared/tab/_system_management.html.erb
app/views/shared/tab/_underwriting_suitability.html.erb
app/views/usage/agent_field_sets/_new_submission_option.html.erb
app/views/usage/users/_personal.html.erb
vendor/assets/stylesheets/bootstrap-combined.min.css
vendor/assets/stylesheets/bootstrap.css
vendor/assets/stylesheets/pixel-admin.css
vendor/assets/stylesheets/themes.css

Upvotes: 2

Views: 118

Answers (2)

torek
torek

Reputation: 488003

By default, for a merge commit, git show produces (as the documentation says) a "combined diff". Using git diff directly with only two of the three or more commits involved1 produces a regular (non-combined) diff.

The documentation on combined diffs is a bit buried, and for some reason this sentence:

Note that combined diff lists only files which were modified from all parents.

is in another section entirely. And, the section linked here refers to git diff when you can't tell git diff to look at all of the merge's parents simultaneously (you have to use git diff-tree or git show for that).


1A merge commit is one with at least two parents, so the three or more commits here are the commit you're git show-ing, its first parent ($MY_COMMIT^1), its second parent ($MY_COMMIT^2), and any additional parents ($MY_COMMIT^3, etc., for "octopus merges").

Upvotes: 0

helmbert
helmbert

Reputation: 37964

You are displaying the diff of a merge commit.

Consider an example with the following commits (F being the newest one), and you're doing a git show F and a git diff F^ F (which is effectively a git diff C F).

A--B--C--F
 \      /
  D----E
  1. git show shows only the files that were changed in the merge commit itself. This may include files that had merge conflicts which were manually fixed. It will not show files that were modified in one of the merged branches (so B,C or D,E) and could be merged cleanly. To quote the man page (emphasis mine):

    For commits [git show] shows the log message and textual diff. It also presents the merge commit in a special format as produced by git diff-tree --cc.

    [git diff-tree --cc] further compresses the patch output by omitting uninteresting hunks whose the contents in the parents have only two variants and the merge result picks one of them without modification.

  2. git diff <commit>^ <commit> shows the diff of the merge commit's first parent and the merge commit. Since the merge commit contains all changes from both the first and second parent, you're effectively shown the diff of the entire branch (so in my example, commit D and E) that was merged in that commit.

Upvotes: 2

Related Questions