什么是“基础” git差异?

发布于 2025-02-13 14:23:57 字数 1391 浏览 0 评论 0原文

我想问的是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 area
  • git diff HEAD: compares working directory with HEAD (current commit)
  • git diff branch/commit: as above, compares WD with branch/commit
  • git 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

帅冕 2025-02-20 14:23:57

您所写的基本上是正确的,但是您的..语法是翻转的,*基本是模棱两可的,因此我将使用术语“ 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 diffgit diff -cached)在使用以下工作流程时非常方便:

  1. 使一些编辑
  2. 将它们添加到索引中,
  3. 使得更多编辑使得更多编辑
  4. 添加它们 在步骤1和第3(编辑)之后的索引
  5. 提交

中,您可以使用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 and git diff --cached) are very convenient when using the following workflow:

  1. Make some edits
  2. Add them to the index
  3. Make some more edits
  4. Add them to the index
  5. Commit

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> means git 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 use git diff -R ....


*The syntax git diff <commit1>..<commit2> is a synonym for git diff <commit1> <commit2>, i.e. the order is old..new. (Note that .. has a subtly different meaning outside git diff.)

夏花。依旧 2025-02-20 14:23:57

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:

          I--J
         /    \
...--G--H      M--N   <-- somebranch (HEAD)
         \    /
          K--L

we can, if we like, diff the snapshots stored in commits I and K, and they're both equally "old" when compared to the current commit N. Or, we can give git diff the newer commit first, then the older one: git diff N G, and here the "new" commit is G, 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:

git diff --no-index -- file1 file2

Here file1 is on the left and file2 is on the right. But they're still left and right. The really problematic case is when we have git 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:

How can I remember/memorise the various syntaxes of git diff?

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:

git diff A..B

which is just a semi-deprecated way to spell git diff A B, and:

git diff A...B

which is a request to invoke git merge-base A B to find the (singular) merge base of A and B and use that as the left side; the right side here is then always B.

In other Git usage, A..B and A...B mean what is documented in the gitrevisions page, which is another manual page to keep close at hand at all times.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文