【问题标题】:How to see the changes between two commits without commits in-between?如何在没有中间提交的情况下查看两个提交之间的更改?
【发布时间】:2010-11-14 13:05:46
【问题描述】:

你如何让git diff 只显示两个提交之间的差异,不包括中间的其他提交?

【问题讨论】:

  • "git diff" always 显示两次提交(或提交和工作目录等)之间的差异。
  • @JakubNarębski,他在询问如何查看一个命令引入的更改与另一个提交引入的更改之间的区别。换句话说,diffs 或 interdiff 的 diff。
  • 如果您在 diff 命令中添加 --dirstat=files 参数,您将在更改的确切项目和文件以及更改百分比上截取非常漂亮的屏幕截图。像这样: git diff [commit-number] [commit-number] --dirstat=files
  • 如果您可以添加示例 git history ascii art 并解释您想要从该图中准确区分/排除哪些提交,这个问题会更清楚。
  • 这可能会直接回答您的问题,但请尝试使用 Meld 或 kdiff3 或其他图形工具

标签: git diff


【解决方案1】:

您可以简单地将 2 个提交传递给 git diff,例如:

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

【讨论】:

  • 这对我有用,但是现在,我如何将my.patch 应用到其他分支?
  • @nacho4d: git checkout other-branch && git apply my.patch && git add 。 && git commit -am "消息"
  • 这个答案完全无法解决这个问题,所以我不知道为什么它有这么多的赞成票。 OP专门询问如何不获取您给出的第一个命令,而第二个与任何内容无关。
  • 这个答案并没有完全不能回答任何问题。它完美地工作。如果你从两个提交中的后面一个分支,然后将这个差异应用到那个新分支,你将看到两个提交之间的变化,而不会因为间歇性提交而头疼。
  • @Mr.Hyde 我不确定我是否完全理解,使用它将包括 2 次提交之间的所有更改。
【解决方案2】:

在不包括中间提交的情况下询问 /between/ 两个提交的区别是没有意义的。提交只是存储库内容的快照;要求两者之间的差异必然包括它们。那么问题来了,你真正在寻找什么?

正如威廉建议的那样,挑选樱桃可以为您提供基于另一个提交的单个提交的增量。那就是:

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

这需要提交“abcdef”,将其与其直接祖先进行比较,然后在“012345”之上应用差异。然后显示了这个新的差异 - 唯一的变化是上下文来自“012345”而不是“abcdef 的直接祖先”。当然,您可能会遇到冲突等,因此在大多数情况下这不是一个非常有用的过程。

如果你只是对 abcdef 本身感兴趣,你可以这样做:

$ git log -u -1 abcdef

这会将 abcdef 与其直接祖先单独进行比较,通常是您想要的。

当然

$ git diff 012345..abcdef

为您提供这两个提交之间的所有差异。

这将有助于更好地了解您想要实现的目标 - 正如我所提到的,询问两次提交之间的差异而没有两者之间的内容实际上是没有意义的。

【讨论】:

  • 我同意,一般来说,比较两个提交没有多大意义。但是 git 真的很擅长不告诉你应该怎么想。假设您有两个分支,每个分支都有不同的提交,看起来它们正在对同一组文件进行相同的更改。我希望能够使用 git 告诉我这两个补丁是否相同,而不必相信我的眼睛。我认为这里面有实用性。
  • @ChrisCleeland,在这种情况下 interdiff 实用程序可以派上用场。使用 git diff 获取每个提交与其直接父项的差异,然后使用 interdiff 比较差异。
  • @ChrisCleeland,git 不存储补丁。它存储文件内容。它确实有一个使用增量的压缩方案,但增量源不一定与文件的实际历史相关。
  • 两个提交之间的差异(不包括各自分支上的其他提交)非常有意义:一个提交是从另一个提交中挑选出来的,但可能有一些细微的差异。你想看看它们是什么,而不会被两个分支之间不同的所有其他不相关的废话弄得一团糟。
  • 或者说你将 master 重新定位到一个特性分支上,并且必须解决冲突。之后比较 origin/featurebranch#HEADlocal/featurebranch#HEAD 可以帮助您确保在解决冲突期间没有搞砸任何事情。
【解决方案3】:

要将两个 git 提交 12345 和 abcdef 作为补丁进行比较,可以使用 diff 命令作为

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

【讨论】:

  • 为什么要在 git 中使用 GNU diff?
  • @OneOfOne git diff &lt;(git show 123456) &lt;(git show abcdef) 不起作用; diff &lt;(...) &lt;(...) 确实如此。 (我刚试过)。
  • @OneOfOne 这不一样。您的建议是比较每个提交的,显示一个单个补丁。我(和@plexoos)正在比较两个补丁,每个补丁都是由单独的提交引入的——换句话说,diffing 来自两个diffs 的输出。这涉及读取和比较两个输入流。 diff(GNU 或 Unix,diff)可以做到这一点,而 git diff 不能。有些人可能想知道为什么要这样做。我现在正在这样做,清理一个坏掉的合并。
  • 这不包括git diff中所有元数据的gnu diff吗?
  • 这应该是 OP 问题的公认答案!
【解决方案4】:
git diff <a-commit> <another-commit> path

例子:

git diff commit1 commit2 config/routes.rb

它显示了这些提交之间该文件的差异。

【讨论】:

    【解决方案5】:

    检查完整的更改:

      git diff <commit_Id_1> <commit_Id_2>
    

    仅检查更改/添加/删除的文件:

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

    注意:为了检查 diff 而没有在两者之间提交,您不需要输入提交 ID。

    【讨论】:

      【解决方案6】:

      假设你有这个

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

      您要确保AA0 相同。

      这样就可以了:

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

      【讨论】:

      • 也可以像@plexoos的答案一样缩短为单行:diff &lt;(git diff B A) &lt;(git diff D A0)(与 git show 的结果相同)
      • 那么你想要的是git range-diff B..A D..A0
      • 这就是我要找的东西
      【解决方案7】:

      假设您想查看提交 012345 和 abcdef 之间的区别。以下应该做你想做的事:

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

      【讨论】:

      • 谢谢,在压缩提交后检查你的结果是个好主意。例如,您可以使用未压缩的提交检查您的分支,然后挑选您的压缩提交以查看交互式 rebase 是否一切顺利。此外,当 master 领先于分支时。
      【解决方案8】:

      从 Git 2.19 开始,您可以简单地使用:

      git range-diff rev1...rev2 - 比较两个提交树,从它们的共同祖先开始

      git range-diff rev1~..rev1 rev2~..rev2 - 比较 2 个给定提交引入的更改

      【讨论】:

        【解决方案9】:

        这个呢:

        git diff abcdef 123456 | less
        

        如果您想即时比较许多不同的差异,只需将其管道化为 less 会很方便。

        【讨论】:

          【解决方案10】:

          我在~/.zshrc 文件中的alias 设置git diff

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

          谢谢 @罗金淼


          git diff HEAD~2 HEAD

          最新的第二次提交和当前提交之间的完整更改。

          HEAD方便

          【讨论】:

            【解决方案11】:

            我在~/.bashrc 文件中的alias 设置git 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
            

            【讨论】:

              【解决方案12】:

              我写了一个脚本,显示两次提交之间的差异,在 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)
              

              【讨论】:

                【解决方案13】:

                $git 日志

                commit-1(new/latest/recent commit)
                commit-2
                commit-3
                commit-4
                *
                *
                commit-n(first commit)
                

                $git diff commit-2 commit-1

                显示 commit-2 到 commit-1 之间的所有更改(仅 commit-1 的补丁 & 相当于 git diff HEAD~1 HEAD

                类似地 $git diff commit-4 commit-1

                显示 commit-4 到 commit-1 之间的所有更改(commit-1 的补丁, commit-2 和 commit-3 一起。相当于git diff HEAD~3 HEAD)

                $git diff commit-1 commit-2

                通过更改订单提交 ID,可以获得 revert patch 。 ("$git diff commit-1 commit-2 > revert_patch_of_commit-1.diff")

                【讨论】:

                  【解决方案14】:

                  让我介绍一下您可以在这些情况下采取的简单的 GUI/白痴证明方法。

                  1. 将您的 repo 的另一个副本克隆到新文件夹,例如 myRepo_temp
                  2. 在原始存储库 (myRepo_original) 中签出您希望与提交进行比较的提交/分支。
                  3. 现在您可以对这两个文件夹(myRepo_tempmyRepo_original)使用差异工具(如 Beyond Compare 等)

                  这很有用,例如,如果您想部分撤销某些更改,因为您可以将内容从一个文件夹复制到另一个文件夹。

                  【讨论】:

                    【解决方案15】:

                    查看 GitHub 上的差异;你可以 - https://github.com/&lt;username&gt;/&lt;reponame&gt;/compare/&lt;commit1&gt;..&lt;commit2&gt;

                    阅读更多Comparing Commits

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 2023-03-15
                      • 2014-10-23
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2020-07-28
                      • 2011-07-09
                      相关资源
                      最近更新 更多