什么是“基础” git差异?
我想问的是XY问题,但怀疑并没有完全在主题上,“我如何记住/记住git diff的各种语法?” git diff语法(个人)令人困惑,我还不清楚您如何记住他们在直觉上所做的(即没有死记硬背的记忆),因为基本逻辑似乎不清楚。
但是要进一步分解这个问题,我的清晰度是:git diff的默认基础是什么?
这是我对git diff语法到目前为止的理解:
git diff
:将工作目录与分期区域进行比较git diff head
:将工作目录与head(当前提交)git diff branch/commit
:如上所述,将WD与分支/提交git diff -stasting
:将登台区与头(?!)进行比较(?!)git diff foo bar
:比较foo和bar
最“直观”且易于理解的语法是git diff diff foo bar
,或者散布提示。如果“ foo”是差异的“基础”,则“ bar”是“比较”。其余的对我不直觉。例如,我以为git diff -stataged
显示了工作目录和登台区域之间的区别,但事实并非如此。
如果我使用file1 file2
语法重新编写这些语法,则i think think ,它看起来像这样:
git git diff
- >git diff wd..index
git diff head
- >git diff wd..head
git diff commit/branch
- >git diff wd..commit/branch
git diff -starged
- >git diff index..head
,
所以我的假设是:git diff
的基础是工作目录。除非您指定- 分期
或- cached
,则基本对登台区域的更改。
问题是:
- 这是对git diff语法背后的逻辑的正确解释,以及git diff的“基础”?
- 是否还有另一种直观可以理解
git diff
语法背后的逻辑的方法,而不仅仅是记住命令?
The XY question that I want to ask but suspect is not fully on topic is "How can I remember/memorise the various syntaxes of git diff?" The git diff syntaxes are (personally) confusing, and it's not clear to me how you can remember what they do intuitively (i.e. without rote memorisation), because the underlying logic doesn't seem clear.
But to break down the question further, my issue in clarity is this: what is the default base of a git diff?
Here is my understanding of the git diff syntaxes so far:
git diff
: compares working directory with staging areagit diff HEAD
: compares working directory with HEAD (current commit)git diff branch/commit
: as above, compares WD with branch/commitgit diff --staged
: compares staging area with HEAD (?!)git diff foo bar
: compare foo and bar
The most "intuitive" and easy to understand syntax is git diff foo bar
, or diffing a commit-ish. If "foo" is the "base" of the diff, then "bar" is the "comparison". The rest are not intuitive to me. For example I would have thought git diff --staged
shows the difference between the working directory and the staging area, but that's not the case.
If I were to re-write these syntaxes using a file1 file2
syntax, I think it would look something like this:
git diff
->git diff WD..index
git diff HEAD
->git diff WD..HEAD
git diff commit/branch
->git diff WD..commit/branch
git diff --staged
->git diff index..HEAD
So my hypothesis is this: the base of a git diff
is the working directory, always. Unless you specify --staged
or --cached
, the base changes to the staging area.
The question is:
- Is this a correct interpretation of the logic behind the git diff syntax, and the "base" of the git diff?
- Is there another more intuitive way to understand the logic behind the
git diff
syntax, rather than just memorising the commands?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您所写的基本上是正确的,但是您的
..
语法是翻转的,*基本是模棱两可的,因此我将使用术语“ old”和“ new”。这是一个正确的表:git diff< commit1> < commit2>
:常规语法(< commit1> is“ old”,< commit2> is“ new”)git diff diff
-git diff Index worktree
git diff< commit>
- >git diff< commit> Worktree
  (< commit>可以是头部,分支等)git diff -cached
- >git diff head索引
  ( - 阶段是 - 接口的同义词)git diff - cached< commit>
- >git diff< commit>索引
摘要:
指定少于两个提交时,默认行为是将worktree用作“新”版本。您可以指定
- 缓存
将索引用作“新”版本。如果您不指定“旧版本”,git将选择一个明智的默认版(在比较工作室时,“ old”将是索引;当比较索引时,“ old”将是头部)。
特殊情况的原因之一是GIT的修订语法只能提及提交 - 它不能用来表示工作室或索引。因此,一般语法(
git diff< commit1>< commit2>
)不能用于比较工作室或索引。最短表单(
git diff
和git diff -cached
)在使用以下工作流程时非常方便:中,您可以使用
git diff
在将其添加到索引之前查看最新编辑。这种情况经常发生,因此命令很短,很高兴。当您即将达到步骤5(提交)时,您可以使用
git diff -cached
查看索引中的更改,这些更改即将进行。方向可能会令人困惑(例如
git diff - cached< commit>
表示git git diff> commit> index
,请注意订单是如何翻转的)案例将是您想要的:当您将工作室与某物进行比较时,您几乎总是想将工作室视为“新”版本(即我从那以后进行的编辑所做的< ...>?” ),同样,当您将索引与几乎总是希望将索引视为“新”版本(即“将要进行的更改将要进行的事情)时进入下一个提交?” )。在您想要反向方向的极少数情况下,您可以使用git diff -r ...
。*语法
git diff< commit1> ..< commit2>
是git git diff< commit1> gt; < commit2>
,即订单为 old..new 。 (请注意,..
在git diff
之外具有微妙的含义。)What you've written is basically correct, but your
..
syntax is flipped,* and "base" is ambiguous so I'll use the terms "old" and "new". Here is a correct table:git diff <commit1> <commit2>
: general syntax (<commit1> is "old", <commit2> is "new")git diff
->git diff INDEX WORKTREE
git diff <commit>
->git diff <commit> WORKTREE
(<commit> can be HEAD, a branch, etc.)git diff --cached
->git diff HEAD INDEX
(--staged is a synonym for --cached)git diff --cached <commit>
->git diff <commit> INDEX
Summary:
When you specify less than two commits, the default behaviour is to use the worktree as the "new" version. You can specify
--cached
to use the index as the "new" version.If you don't specify the "old" version, Git will choose a sensible default (when comparing the worktree, "old" will be the index; when comparing the index, "old" will be HEAD).
One of the reasons for the special cases is that Git's revision syntax can only refer to commits – it can't be used to denote the worktree or the index. So the general syntax (
git diff <commit1> <commit2>
) can't be used to compare the worktree or the index.The shortest forms (
git diff
andgit diff --cached
) are very convenient when using the following workflow:After steps 1 and 3 (edits), you can use
git diff
to review the most recent edits before you add them to the index. This happens frequently, so it's nice that the command is short to type.When you are about to reach step 5 (commit), you can use
git diff --cached
to view the changes in the index, which are about to be committed.The direction can be confusing (e.g.
git diff --cached <commit>
meansgit diff <commit> INDEX
, note how the order flipped), but in almost all cases it will be what you want: when you compare the worktree to something, you almost always want to treat the worktree as the "new" version (i.e. "What edits have I made since <...>?"), and likewise when you compare the index to something you almost always want to treat the index as the "new" version (i.e. "What changes are about to go into the next commit?"). In the rare cases where you want the reverse direction, you can usegit diff -R ...
.*The syntax
git diff <commit1>..<commit2>
is a synonym forgit diff <commit1> <commit2>
, i.e. the order is old..new. (Note that..
has a subtly different meaning outsidegit diff
.)AS 汤姆回答,术语 base 并不是那么好。我本人也不喜欢旧,因为您可以给出
git diff
任何任意的两个承诺将它们进行比较,并且它们都可以“非常旧”。好吧,我们可以使用古老的和老式的,也许是As tom answered, the term base isn't that great. I myself dislike old-and-new as well, because you can give
git diff
any arbitrary two commits to compare those, and they can both be "very old". Well, we could use old and older, perhaps ????, but what if they're both equally old? For instance, given the "benzene ring" commit graph fragment:we can, if we like, diff the snapshots stored in commits
I
andK
, and they're both equally "old" when compared to the current commitN
. Or, we can givegit diff
the newer commit first, then the older one:git diff N G
, and here the "new" commit isG
, even though it's clearly a lot older.What I like to go for here is simply "left and right". We pick one tree-of-files—one commit's snapshot, or whatever—that goes on the left side of the diff, and another tree to go on the right, and Git provides to use a reasonably minimal edit sequence that will transform the left-side tree into the right-side tree.
It's worth mentioning, at this point, that we don't have to use two trees since we can diff individual files:
Here
file1
is on the left andfile2
is on the right. But they're still left and right. The really problematic case is when we havegit diff
produce a combined diff, because then we have a single left-side tree and multiple right-side trees.With that out of the way, let me get to what I think is the core of your question, which I'll put in bold here:
My answer is: You can't. Well, I don't think you can. I have to refer back to the manual pages now and then myself, and I deal with this close to daily! There is a system, but there are lots of exceptions. Tom's bullet list is excellent, and you can try to memorize the reasoning behind the "flipped when using
--cached
" part, but ultimately, the way to handle this is to keep the documentation close by.The main thing to remember is that we're always diffing pairs. This is true regardless of whether we're doing trees (then we diff the trees, and pair up files and diff the files) or files (then we just diff the pair of files), and it's even still true when doing combined diffs (where we diff left and right side, repeating the left-side over and over again with a different right-side each time). Everything in the syntax is about picking the right pairs, and the two cases that are special—by special, I mean different from other Git usage—in
git diff
here are:which is just a semi-deprecated way to spell
git diff A B
, and:which is a request to invoke
git merge-base A B
to find the (singular) merge base ofA
andB
and use that as the left side; the right side here is then alwaysB
.In other Git usage,
A..B
andA...B
mean what is documented in the gitrevisions page, which is another manual page to keep close at hand at all times.