間にコミットなしで2つのコミット間の変更を確認するにはどうすればよいですか?


643

git diff間にある他のコミットを除いて、2つのコミットの違いのみをどのように表示しますか?


15
"git diff"は常に 2つのコミット(またはコミットと作業ディレクトリなど)の違いを示します。
JakubNarębski、2009

21
@JakubNarębski、彼は、あるコマンドによって導入された変更と別のコミットによって導入された変更との違いをどのように確認するかを尋ねています。つまり、diffの差分または相互差分です。
psusi

1
そして、--dirstat = filesパラメーターをdiffコマンドに追加すると、変更の割合とともに、変更されたプロジェクトとファイルの正確なスクリーンショットを撮ることができます。gitのdiffの[コミット数]を[コミット番号] --dirstat =ファイル:このような
オスカー・イバニェス・フェルナンデス・

回答:


606

あなたは単純に2つのコミットをgit diffに渡すことができます:

-> git diff 0da94be  59ff30c > my.patch
-> git apply my.patch

1
それは私にとってはうまくいきましたが、今、my.patch他のブランチにどのように申請できますか?
nacho4d 2011年

2
@ nacho4d:git checkout other-branch && git apply my.patch && git add。&& git commit -am "Message"
Felix Rabe

1
git applyとpatchを使用する利点は、gitに固有の名前変更やその他の変更を含めることができることです。git format-patchとgit amを使うのが好きです。
ラッセル

58
この答えはまったく問題に対処できないため、なぜこれほど多くの賛成票があるのか​​はわかりません。OPは、最初のコマンドを取得しない方法を具体的に要求しており、2番目のコマンドは何の関係もありません。
psusi

3
この答えはまったく何にも答えません。それは完全に動作します。問題の2つのコミットのうちの遅い方から分岐し、この差分をその新しい分岐に適用すると、断続的なコミットの問題なしに2つのコミット間の変更が表示されます。
Craig Labenz、2015年

142

間にコミットを含めずに/ between / 2つのコミットの違いを求めることはほとんど意味がありません。コミットは、リポジトリのコンテンツの単なるスナップショットです。2つの違いを求めるには必ずそれらが含まれます。それで問題は、あなたが本当に何を探しているのですか?

ウィリアムが示唆したように、チェリーピッキングは、単一のコミットのデルタを別のコミットの上にリベースすることができます。あれは:

$ git checkout 012345
$ git cherry-pick -n abcdef
$ git diff --cached

これは、コミット 'abcdef'を取り、それをその直接の祖先と比較し、その違いを '012345'に適用ます。次に、この新しい違いが表示されます-唯一の変更点は、コンテキストが「abcdef」の直接の祖先ではなく「012345」からのものであることです。もちろん、競合などが発生する可能性があるため、ほとんどの場合、これはあまり有用なプロセスではありません。

あなただけのabcdef自体に興味があるなら、あなたはすることができます:

$ git log -u -1 abcdef

これは、abcdefとその直接の祖先を単独で比較したものであり、通常はこれで十分です。

そしてもちろん

$ git diff 012345..abcdef

これら2つのコミットの間のすべての違いを提供します。

それはあなたが達成しようとしていることをよりよく理解するのに役立ちます-私が述べたように、間に何もないのに2つのコミットの違いを求めることは実際には意味がありません。


41
一般に、2つのコミットを比較することはあまり意味がないことに同意します。しかし、gitはあなたがどう考えるべきかをあなたに言わないのが本当に得意です。2つのブランチがあり、それぞれが同じファイルのセットに同じ変更を加えているように見える個別のコミットがあるとします。私の目を信頼する必要なく、これら2つのパッチが同じかどうかをgitを使用して教えたいと思います。これには実用性があると思います。
クリスクリーランド

9
@ChrisCleelandの場合、interdiffユーティリティが便利です。git diffを使用して、直接の親に対する各コミットの差分を取得し、次にinterdiffを使用して差分を比較します。
bdonlan 2012

3
@ ChrisCleeland、gitはパッチを保存しません。ファイルの内容を格納します。デルタを使用する圧縮スキームはありますが、デルタソースは必ずしもファイルの実際の履歴と関連付けられていません。
bdonlan 2012

11
それぞれのブランチ上の他のコミットを除く2つのコミット間の差分は完全に理にかなっています。一方のコミットは他方から適切に選択されていますが、微妙な違いがある場合があります。あなたは、2つのブランチ間で異なる他のすべての無関係ながらくたで乱雑になることなく、それらが何であるかを確認したいと考えています。
psusi

2
または、マスターを機能ブランチにリベースし、競合を解決する必要があると言います。その後、と比較origin/featurebranch#HEADするlocal/featurebranch#HEADことで、競合解決中に何も変更しなかったことを確認できます。
lefnire 2016

91

2つのgit commit 12345とabcdefをパッチとして比較するには、次のようにdiffコマンドを使用できます。

diff <(git show 123456) <(git show abcdef)

8
なぜあなたはgitでGNU diffを使うのですか?
OneOfOne 2014

7
@OneOfOne git diff <(git show 123456) <(git show abcdef)は機能しません。diff <(...) <(...)します。(私はそれを試しました)。
Menachem

@Menachem git diff 123456 abcdef
OneOfOne

15
@OneOfOneそれは同じことをしません。あなたが提案したものは、各コミットのツリーを比較し、単一のパッチを示します。私(および@plexoos)が行っているのは、2つのパッチを比較することです。それぞれのパッチは、別々のコミットによって導入されたものです。つまり、diff2つdiffのs からの出力を使用しています。これには、2つの入力ストリームの読み取りと比較が含まれます。 diff(GNU、またはUnix、diff)はそれを行うことができますが、git diffできません。なぜそんなことをしたいのかと思う人もいるでしょう。私は今それを行っている最中です。うまくいかなかったマージをクリーンアップしています。
Menachem

1
これにはgit diffのすべてのメタデータのgnu diffが含まれませんか?
joelb

61
git diff <a-commit> <another-commit> path

例:

git diff commit1 commit2 config/routes.rb

それらのコミット間のそのファイルの違いを示しています。


24

完全な変更を確認するには:

  git diff <commit_Id_1> <commit_Id_2>

変更/追加/削除されたファイルのみをチェックするには:

  git diff <commit_Id_1> <commit_Id_2> --name-only

:コミットせずに差分を確認する場合は、コミットIDを入力する必要はありません。


20

これを持っているとしましょう

A
|
B    A0
|    |
C    D
\   /
  |
 ...

そしてA、それがと同じであることを確認したいとしA0ます。

これはトリックを行います:

$ git diff B A > B-A.diff
$ git diff D A0 > D-A0.diff
$ diff B-A.diff D-A0.diff

3
@plexoosによる回答diff <(git diff B A) <(git diff D A0)と同じように、ワンライナーとして短縮することもできます:(git showと同じ結果)
pogosama

14

コミット012345とabcdefの違いを見たいとしましょう。以下はあなたが望むことをするはずです:

$ gitチェックアウト012345
$ git cherry-pick -n abcdef
$ git diff --cached

おかげで、コミットを破棄した後に結果を確認することをお勧めします。たとえば、非圧縮コミットでブランチをチェックアウトし、圧縮コミットをチェリーピックして、インタラクティブなリベースですべてがスムーズに行われたかどうかを確認できます。さらに、マスターがブランチを先に進んだとき。
akostadinov 2013


6

Git 2.19以降、次のように簡単に使用できます。

git range-diff rev1...rev2 -共通の祖先から始めて、2つのコミットツリーを比較する

または git range-diff rev1~..rev1 rev2~..rev2 -2つの特定のコミットによって導入された変更の比較


4

ファイルの私のalias設定:~/.bashrcgit diff

alias gdca='git diff --cached' # diff between your staged file and the last commit
alias gdcc='git diff HEAD{,^}' # diff between your latest two commits

2

ファイルの私のalias設定:~/.zshrcgit diff

alias gdf='git diff HEAD{'^',}' # diff between your recent tow commits

ありがとう@Jinmiao Luo


git diff HEAD~2 HEAD

最新の2番目のコミットと現在のコミットの間の完全な変更。

HEAD 便利です


1

私は2つのコミットの差分を表示するスクリプトを書き、Ubuntuでうまく動作します。

https://gist.github.com/jacobabrahamb4/a60624d6274ece7a0bd2d141b53407bc

#!/usr/bin/env python
import sys, subprocess, os

TOOLS = ['bcompare', 'meld']

def getTool():
    for tool in TOOLS:
        try:
            out = subprocess.check_output(['which', tool]).strip()
            if tool in out:
                return tool
        except subprocess.CalledProcessError:
            pass
    return None

def printUsageAndExit():
    print 'Usage: python bdiff.py <project> <commit_one> <commit_two>'
    print 'Example: python bdiff.py <project> 0 1'
    print 'Example: python bdiff.py <project> fhejk7fe d78ewg9we'
    print 'Example: python bdiff.py <project> 0 d78ewg9we'
    sys.exit(0)

def getCommitIds(name, first, second):
    commit1 = None
    commit2 = None
    try:
        first_index = int(first) - 1
        second_index = int(second) - 1
        if int(first) < 0 or int(second) < 0:
            print "Cannot handle negative values: "
            sys.exit(0)
        logs = subprocess.check_output(['git', '-C', name, 'log', '--oneline', '--reverse']).split('\n')
        if first_index >= 0:
            commit1 = logs[first_index].split(' ')[0]
        if second_index >= 0:
            commit2 = logs[second_index].split(' ')[0]
    except ValueError:
        if first != '0':
            commit1 = first
        if second != '0':
            commit2 = second
    return commit1, commit2

def validateCommitIds(name, commit1, commit2):
    if commit1 == None and commit2 == None:
        print "Nothing to do, exit!"
        return False
    try:
        if commit1 != None:
            subprocess.check_output(['git', '-C', name, 'cat-file', '-t', commit1]).strip()
        if commit2 != None:
            subprocess.check_output(['git', '-C', name, 'cat-file', '-t', commit2]).strip()
    except subprocess.CalledProcessError:
        return False
    return True

def cleanup(commit1, commit2):
        subprocess.check_output(['rm', '-rf', '/tmp/'+(commit1 if commit1 != None else '0'), '/tmp/'+(commit2 if commit2 != None else '0')])

def checkoutCommit(name, commit):
    if commit != None:
        subprocess.check_output(['git', 'clone', name, '/tmp/'+commit])
        subprocess.check_output(['git', '-C', '/tmp/'+commit, 'checkout', commit])
    else:
        subprocess.check_output(['mkdir', '/tmp/0'])

def compare(tool, commit1, commit2):
        subprocess.check_output([tool, '/tmp/'+(commit1 if commit1 != None else '0'), '/tmp/'+(commit2 if commit2 != None else '0')])

if __name__=='__main__':
    tool = getTool()
    if tool == None:
        print "No GUI diff tools"
        sys.exit(0)
    if len(sys.argv) != 4:
        printUsageAndExit()

    name, first, second = None, 0, 0
    try:
        name, first, second = sys.argv[1], sys.argv[2], sys.argv[3]
    except IndexError:
        printUsageAndExit()

    commit1, commit2 = getCommitIds(name, first, second)

    if not validateCommitIds(name, commit1, commit2):
        sys.exit(0)

    cleanup(commit1, commit2)
    checkoutCommit(name, commit1)
    checkoutCommit(name, commit2)

    try:
        compare(tool, commit1, commit2)
    except KeyboardInterrupt:
        pass
    finally:
        cleanup(commit1, commit2)
    sys.exit(0)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.