16

以前 有人 过有关在 Git 中重命名文件的问题,但我无法解决我的具体问题。

我已经移动和编辑了多个文件(我没有使用git mv- 不幸的是现在为时已晚)。现在我想要它,所以当我的同事从我的存储库中提取,对这些相同的文件进行了自己的编辑(不移动它们)时,它成功地将我的更改与他在文件的新位置中的更改合并。要成功合并,Git 显然需要知道这些是相同的文件。

Git 是否足够聪明,可以自己解决这个问题?似乎很难相信。如果是这样,我如何确定 Git 会拾取特定的文件移动 - 即使内容已更改?

4

3 回答 3

21

Git 实际上并不跟踪存储库中的重命名,它使用差异启发式来确定您是否将文件重命名为另一个文件。也就是说,如果你git mv一个文件然后完全替换了内容,它被认为是重命名,你不需要使用git mv它来检测重命名。

例如:

% mv d.txt e.txt
% git rm d.txt
rm 'd.txt'
% git add e.txt
% git commit -m"rename without git mv"
[master f70ae76] rename without git mv
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename d.txt => e.txt (100%)
% git diff --summary --find-renames HEAD~1 HEAD
 rename d.txt => e.txt (100%)

同样,git mv并不意味着文件会被重命名,它仍然会使用 diff 算法:

% git mv e.txt f.txt
% echo "Completely replacing f.txt" > f.txt
% git add f.txt
% git commit -m"git mv doesn't help here"
[master 068d19c] git mv doesn't help here
 2 files changed, 1 insertion(+), 14 deletions(-)
 delete mode 100644 e.txt
 create mode 100644 f.txt
% git diff --summary --find-renames HEAD~1 HEAD
 delete mode 100644 e.txt
 create mode 100644 f.txt
于 2012-10-08T16:16:22.177 回答
8

默认情况下,只要文件在两次提交之间被删除,git 就会检查重命名——不需要手动告诉它。如果您确实移动了一个文件(使用 git mv,而不是手动删除它并再次添加它)它会忽略提示。出于性能原因,启发式算法不会一直运行——如果您将一个文件移开,然后添加一个具有原始名称的新文件,则可能无法检测到该移动。

请注意,从逻辑上讲,git 仅存储每个修订版中存在的树:它不存储有关修订版之间所做更改的任何跟踪信息。

如果您想查看检测到的内容,可以使用-M( --find-renames) 开关git diff来显示重命名。此开关还打开启发式,如果您有一个不会触发它们的提交,这很有用。

这种基于启发式的方法是保持提交小且独立的一个很好的理由(如果您需要另一个),因为这使 git 的工作更容易。

于 2012-10-08T16:15:50.360 回答
2

git diff没有发现我重命名了文件更改了它们的内容。我的场景是我有文件 A、B、C,并插入了一个新的 B,所以旧的 B 现在是 C,旧的 C 现在是 D。git diff告诉我 B 和 C 现在完全不同了!

我使用的解决方案既繁琐又手动,但确实完成了工作。

  1. 尽我所能重命名文件。即B到Bnew,C到B,D到C。
  2. 做了差异,检查没有错误。
  3. 承诺。
  4. 用于git mv将文件重新命名为新名称。B 到 C,C 到 D。
  5. 承诺。
  6. 其他是否重命名,并将它们作为新文件提交。即Bnew to B。
于 2013-11-13T13:00:22.560 回答