作为LeGEC noted in a comment,如果你只是想比较两个目录树(或两个文件),你不需要Git:普通的diff和其他类似的程序都可以正常工作。
如果你有 Git,你可以在任何两个文件或任何两个目录上使用git diff,它们当前不在任何 Git 存储库中,它会产生一个 Git 风格的差异.
如果你有一个 Git repository,你必须记住这意味着你有 commits。在最高概述级别上,存储库只是一对数据库。一个(通常是迄今为止最大的)保存 Git 的内部对象,包括用户关心的 commits(元数据快照)。另一个数据库(通常要小得多)保存 names: 分支名称、标记名称、远程跟踪名称和其他此类名称。我们(人类)使用这些来查找特定提交,Git 使用它们来查找提交,偶尔也会使用其他一些内部 Git 对象。
这意味着 Git 存储库与文件无关。这是关于提交。 bare Git 存储库(由于各种原因,它不是默认存储库)只有提交和名称。
然而,提交是只读的,提交数据库主要是追加的。也就是说,在很大程度上,您可以使用它添加新的提交。嗯,那个,并且使用任何一个特定的提交来提取文件:每个提交都包含一个每个文件的完整存档,并使其有用,我们必须有一种方法来提取那些(只读)文件(以读取/写入文件)。
因此,如果您确实有一个存储库,那么您确实有一堆提交(可能有数十万个提交,或者可能只有一个提交)。如果你打算做一些工作,然后进行new提交,你会:
-
签出带有
git checkout 或git switch 的提交,它会从提交中提取冻结的快照;
- 在您计算机上的目录(“文件夹”,如果您更喜欢这个术语)中的常规普通文件中执行工作,Git 称之为您的工作树(因为您在这里工作);最终
- 使用
git add 和git commit 为每个文件制作新快照。
这将向存储库添加一个新的提交,而所有现有的提交都保持不变(它必须:它们都是都是只读的,就像新的一样你刚做的一个)。通过这种方式,您永远不会丢失任何由提交组成的历史记录。您只需通过添加新提交来添加 new 历史记录。
您现在可以在以下位置使用git diff:
-
任意两个提交:选择任何两个提交,由任何人在任何时候进行。 (提交被编号,使用唯一的散列 ID,出现随机,但实际上不是。您可以使用其他 Git 程序首先找到散列 ID。)
git diff a123456 b789abc
Git 会将这两个提交提取到内存中的一个临时区域,然后将左侧提交中的每个文件与右侧提交中的相应文件进行比较。如果文件完全相同,Git 什么也不说。如果在某些方面有所不同,Git 会为您提供将左侧文件更改为右侧文件的方法。
-
对根本不在 Git 中的文件或树的任何提交;
-
任何一个提交到您提议的下一次提交中的文件集,也就是Git的索引,也就是暂存区。不过,我们不会在这里详细介绍。
-
任何一个提交到工作树中的文件集;或
-
将 Git 索引(即暂存区)中的文件复制到工作树中的文件。
因为这里有很多可能性,git diff 的参数集有点复杂。一般来说:
如果你给 Git 两个提交哈希 ID,你会得到 commit-vs-commit (commit-pair) 比较。如果没有,您将获得其他操作之一。作为一种特殊情况,如果两个参数都将文件或目录命名为在工作树之外,git diff 将区分这两个文件或目录。
特殊名称HEAD 总是指当前提交(或在某些情况下指当前分支,但对于git diff,当前分支不是'很有趣)。所以
git diff HEAD /path/outside/repo
会将当前提交与根本不在存储库中的给定路径进行比较。同样:
git diff a123456 /path/outside/repo
会将提交 a123456(假设存在具有该哈希 ID 的提交)与存储库外部的给定路径进行比较。
大多数标准 git diff 调用,然而,涉及当前提交、索引/暂存区域或工作树——或者更确切地说,这三者中的两个的组合。完全不带参数运行git diff 意味着将索引中的内容与工作树中的内容进行比较。在没有额外参数的情况下运行 git diff --staged 意味着 比较当前提交中的内容与索引/暂存区域中的内容。
在极少数情况下,您需要 --no-index 作为 git diff 的参数来说服它不要查看索引/暂存区域,但通常 Git 会自行解决。