有没有从点或分支原点到 "git diff" 的快速方法?

Is there a quick way to "git diff" from the point or branch origin?

我已经查看了关于使用 git diff 和 git 修订版(HEAD、ORIG_HEAD、FETCH_HEAD 等)的各种 SO 答案,但我仍然没有找到了一种简单的方法来列出自本地分支开始以来或自上次 rebase 以来所做的更改。

通过 easy 我的意思是无需查找和粘贴提交 SHA 或不必计算我想回顾的提交数量。

git diff origin/master 很接近,但它指的是远程,自从我从中签出新分支以来可能已经发生分歧。

我希望可以使用 git diff BASE_HEAD 之类的东西。

...除非已经有办法做到这一点。有人知道答案吗?

使用 git diff @{u}...HEAD,三个点。

如果有两个点,或者省略HEAD,它会显示两边变化的差异。

三个点,它只会显示与您这边的变化的差异。

编辑:对于需求略有不同的人,您可能会对 git merge-base 感兴趣(请注意,它比其他答案使用的选项更多)。

您可以使用 git merge-base 找到 分支点 。考虑 master 主线和 dev 您感兴趣的历史分支。要找到 devmaster、运行 分支的点:

git merge-base --fork-point master dev

我们现在可以 diff dev 在此基础上:

git diff $(git merge-base --fork-point master dev)..dev

如果 dev 当前分支 这简化为:

git diff $(git merge-base --fork-point master)

有关详细信息,请参阅 git-merge-base documentation

您可以使用以下方法从分支起点区分当前分支:

git diff (start point)...

其中(起点)是分支名称、commit-id 或标记。

例如,如果您正在处理从 develop 分支出来的功能分支,您可以使用:

git diff develop...

对于当前分支自分支点以来的所有更改。

这已在评论中提到,但我认为它值得回答状态。我不知道自从上次变基后它会做什么。

对于差异,您需要三点表示法。如果您的分支名为 dev 并且它从 master:

分支
% git diff master...dev

对于日志,您需要两点符号:

% git log master..dev

修订语法 r1..r2(带两个点)表示 "everything reachable from r2 (inclusive) but not reachable from r1 (inclusive)"。使用它的正常方法是将 r1r2 视为指定提交序列中的范围(r1 独占,r2 包含),所以如果你有10 次修订,3..7 将显示更改 4、5、6 和 7。它是 {1, 2, 3, 4, 5, 6, 7} 减去 {1, 2, 3}。但是 r1 不一定是 r2 的祖先。把它想象成一个集合操作,其中 r1 代表从 r1 向后的整个祖先,而 r2 代表从 r2 向后的整个祖先,你正在减去第一组来自第二组。

那么:

git log master..dev

是分支的整个历史减去master的整个历史。换句话说,只是分支。

在 Visual Studio 2017 年,有一种方便的方式来显示差异:

  1. Team Explorer -> Branches 中右键单击分支并 select View History

  1. History - branch 控制 select 你想要的提交 diff 和 select Compare Commits

您会得到一个很好的差异概览,并且您可以在比较模式下打开文件。

与远程 master 分支比较:

git diff $(git merge-base HEAD origin/master)..

提到

Use git diff @{u}...HEAD, with three dots.

但是...最好使用 Git 2.28(2020 年第 3 季度)完成。
以前,“git diff”用于以随机和无意义的范围表示法接受参数,例如“git diff A..B C ", "git diff A..B C...D”等,已清理

参见 commit b7e10b2, commit 8bfcb3a (12 Jun 2020), and commit bafa2d7 (09 Jun 2020) by Chris Torek (chris3torek)
(由 Junio C Hamano -- gitster -- in commit 1457886 合并,2020 年 6 月 25 日)

git diff: improve range handling

Signed-off-by: Chris Torek

When git diff is given a symmetric difference A...B, it chooses some merge base from the two specified commits (as documented).

This fails, however, if there is no merge base: instead, you see the differences between A and B, which is certainly not what is expected.

Moreover, if additional revisions are specified on the command line ("git diff A...B C"), the results get a bit weird:

  • If there is a symmetric difference merge base, this is used as the left side of the diff.
    The last final ref is used as the right side.

  • If there is no merge base, the symmetric status is completely lost.
    We will produce a combined diff instead.

Similar weirdness occurs if you use, e.g., "git diff C A...B D". Likewise, using multiple two-dot ranges, or tossing extra revision specifiers into the command line with two-dot ranges, or mixing two and three dot ranges, all produce nonsense.

To avoid all this, add a routine to catch the range cases and verify that that the arguments make sense.

As a side effect, produce a warning showing which merge base is being used when there are multiple choices; die if there is no merge base.

The documentation 现在包括:

'git diff' [<options>] <commit> [<commit>...] <commit> [--] [<path>...]:

This form is to view the results of a merge commit.

The first listed must be the merge itself; the remaining two or more commits should be its parents.
A convenient way to produce the desired set of revisions is to use the {caret}@ suffix.
For instance, if master names a merge commit, git diff master master^@ gives the same combined diff as git show master.

我在 .gitconfig 中写了一个别名来解决这个任务:

[alias]
    # See changes since branching off of main branch
    changes = "!f() { \
        current=$(git rev-parse --abbrev-ref HEAD); \
        main=$(git symbolic-ref refs/remotes/origin/HEAD | sed 's@^refs/remotes/origin/@@'); \
        commit=$(git merge-base --fork-point \"$main\" \"$current\"); \
        git diff \"$commit\"...; \
    }; f"

逐行,此别名:

  1. 定义了一个shell函数,f,其中
  2. 计算当前分支名称,
  3. 计算主分支名称(可以是 main、master、develop 等),
  4. 计算这两个分支分叉的提交,并且
  5. 运行 git diff 以查看自此提交以来的更改

如果您使用较新的 git 版本,您只需使用

git diff --merge-base <target_branch>

它(对我而言)提供与当前投票最高的答案相同的结果:

git diff $(git merge-base --fork-point origin/main)

该命令在 Git Version 2.30 中引入为:

"git diff A...B" learned "git diff --merge-base A B", which is a longer short-hand to say the same thing.

所以基本上它是另一种获得与 相同结果的方法。