【问题标题】:Git how to detect whole folder deleted/movedGit如何检测整个文件夹已删除/移动
【发布时间】:2023-04-11 01:40:01
【问题描述】:

Git 基于内容而不是文件,因此我目前了解以下行为,但我想知道是否有特殊选项或黑客来检测此类事情:

git init
mkdir -p foo/bar
echo "test" foo/a.txt
echo "test2" foo/bar/b.txt
git add -A
git commit -m "test"

rm -fr foo
git add -A
git commit -m "delete whole dir"
git log --name-status

当我查看日志时,Git 不会明确告诉我 foo 已删除,但所有文件 foo/a.txt 和 foo/bar/b.txt 已删除

commit d1513a9b36cd546371a194e798566c49e779e3a9
Date:   Tue Sep 8 16:58:21 2015 +0200

    delete whole dir

D       foo/a.txt
D       foo/bar/b.txt

commit 135f7ae52dfddcee5eeb7bdfa9f0d5c924fed3af
Date:   Tue Sep 8 16:58:10 2015 +0200

    test

A       foo/a.txt
A       foo/bar/b.txt

因此,如果我创建以下提交:

mkdir -p foo/bar
echo "test" > foo/a.txt
echo "test2" > foo/bar/b.txt
echo "test3" > foo/bar/c.txt
git add -A
git commit -m "test2"

rm -f foo/a.txt foo/bar/b.txt
git add -A
git commit -m "delete just 2 files"
git log --name-status

commit delete whole dir 和 delete just 2 files 之间的name-status 相似

commit 92564fb59464fd6bba2766a6d488c2ff8ca967ea
Date:   Tue Sep 8 17:03:09 2015 +0200

    delete just 2 files

D       foo/a.txt
D       foo/bar/b.txt

commit 3b13f27e960c4ec66464e8a1e0d23f038a872564
Date:   Tue Sep 8 17:02:50 2015 +0200

    test2

A       foo/a.txt
A       foo/bar/b.txt
A       foo/bar/c.txt

有没有办法检测整个目录被删除时的差异?

【问题讨论】:

  • 我不认为它们是一种检测差异的方法
  • 不,你不能这样做

标签: git


【解决方案1】:

据我所知,没有专门的 git 命令来检测目录是否已被删除/移动。

但是,如果整个目录已移动到跟踪的 git 存储库中的新位置,它应该显示在 git status 命令的 Untracked files: 部分下。此外,它的所有文件都将显示为已删除。

对于已删除的目录,如果您希望该目录不再存在,您可以运行ls 命令仔细检查该目录是否实际上已被删除。如果目录不存在,则不会对其进行跟踪。

如果目录存在但不包含任何内容,那么 git 也不会跟踪它。不过,你可以试试

git ls-files dirName/ --error-unmatch; echo$?

这个解决方案最初是在this StackOverflow question 上提到的。该命令应该检查 git 是否正在跟踪特定文件,但在这种情况下,git 将检查是否有任何文件 dirName 是文件路径的一部分。如果文件夹未被跟踪,则会显示错误。

【讨论】:

  • git ls-files 是一把钥匙!感谢您的贡献 (:upvote:)
  • git ls-files 是一把钥匙!感谢您的贡献 (:upvote:)
【解决方案2】:

假设您的存储库中的示例树结构为:

Initial commit

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

    new file:   a/b/c/d/e/q.txt
    new file:   a/b/c/m.txt
    new file:   a/b/c/n.txt
    new file:   a/b/f/o.txt
    new file:   a/b/f/p.txt
    new file:   a/b/k.txt
    new file:   a/b/z.txt
    new file:   a/x.txt
    new file:   a/y.txt

让我们进行以下提交:

commit 0bb4d4d50072c1eac1c3cb2b14b670deba8ee31b
Author: Site User <user@site.com>
Date:   Tue Sep 8 19:27:58 2015 +0100

    removed a/b/c/d/e/q.txt

D       a/b/c/d/e/q.txt

-

commit 3b53f16eb2fd7d3d605180ccabcfa71eb9e9225a
Author: Site User <user@site.com>
Date:   Tue Sep 8 19:28:55 2015 +0100

    removed a/b/c/m.txt and a/b/c/n.txt (full a/b/c)

D       a/b/c/m.txt
D       a/b/c/n.txt

-

commit 3af8ace473944996fb8b21135106360305e8b89a
Author: Site User <user@site.com>
Date:   Tue Sep 8 19:30:30 2015 +0100

    added a/b/g/w.txt

A       a/b/g/w.txt

-

提交 3b53f16eb2fd7d3d605180ccabcfa71eb9e9225a 是看到文件夹“a/b/c”消失的那个,因为其中的最后一个文件被删除。

要在文件夹 a/b/c 被删除时查找提交的 SHA#,您可以使用以下组合查找涉及“a/b/c”文件夹的最后一次提交:

#> git log --name-status -- a/b/c 

和

#> git ls-tree -r [commit] -- a/b/c

类似:

for cmt in $(git log --pretty=%H -- a/b/c); \
    do X=$(git ls-tree -r "${cmt}" -- a/b/c); \
    [[ -z "${X}" ]] && echo "The folder a/b/c has been deleted in commit: ${cmt}"; \
done

输出:

The folder a/b/c has been deleted in commit: 3b53f16eb2fd7d3d605180ccabcfa71eb9e9225a

以简单的 BASH 脚本形式(我将其命名为 deleted.sh,应该具有可执行权限):

#!/bin/bash

P="$1"
GIT=$(which git)

for cmt in $($GIT log --pretty=%H -- "${P}"); do
    X=$($GIT ls-tree -r "${cmt}" -- "${P}");
    [[ -z "${X}" ]] && echo "The folder a/b/c has been deleted in commit: ${cmt}";
done

用法:

./deleted.sh a/b/c

输出:

The folder a/b/c has been deleted in commit: 3b53f16eb2fd7d3d605180ccabcfa71eb9e9225a

它是如何工作的

第一次提交,追溯历史,在树中没有与文件夹路径匹配的文件,应该这样做。

这就是 shell 脚本正在做的事情。

它在历史记录中向后迭代,检索与文件夹中的任何文件相关的所有 SHA#,然后在这些提交中找到第一个没有与提供的路径匹配的文件,在吉特树。

该提交出现在要检查的列表中的事实确保其中存在涉及该文件夹的更改。

在其树中没有与该文件夹匹配的文件这一事实(过滤后的“ls-tree”返回一个空字符串),确保它是该文件夹中的最后一个文件已被删除的提交。

【讨论】:

  • 但最后一次从文件夹提交并不意味着该文件夹已被删除?
  • 第一次提交,追溯历史,在树中没有与文件夹路径匹配的文件,应该这样做。这就是 shell 脚本正在做的事情。它在历史中向后迭代,检索与文件夹中任何文件相关的所有 SHA#,然后在这些提交中找到第一个没有与 Git 树中提供的路径匹配的文件的提交。跨度>
  • @Kakawait,请参阅“它是如何工作的”注释作为解释。
  • 你拯救了这一天!谢谢! :-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多