简体   繁体   English

Git如何检测整个文件夹已删除/移动

[英]Git how to detect whole folder deleted/moved

Git is based on content and no file so I currently understand the following behavior but I want to know if there is a special option or hack to detect such thing: Git 基于内容而不是文件,所以我目前了解以下行为,但我想知道是否有特殊选项或 hack 来检测这样的事情:

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

When I check log, Git will not clearly said me that foo was deleted but all file foo/a.txt and foo/bar/b.txt was deleted当我查看日志时, Git不会明确告诉我foo已删除,但所有文件foo/a.txtfoo/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

Thus if I create following commits:因此,如果我创建以下提交:

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

name-status between commit delete whole dir and delete just 2 files are similar提交delete whole dirdelete 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

Is there any way to detect difference when whole directory is deleted?删除整个目录时有什么方法可以检测差异吗?

Assuming a sample tree structure in your repository as:假设您的存储库中的示例树结构为:

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

Let's make the following commits:让我们进行以下提交:

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

- ——

Commit 3b53f16eb2fd7d3d605180ccabcfa71eb9e9225a is the one that sees the folder "a/b/c" disappear, as the last file in it is removed.提交 3b53f16eb2fd7d3d605180ccabcfa71eb9e9225a 是看到文件夹“a/b/c”消失的那个,因为其中的最后一个文件被删除。

To find the SHA# of the commit when the folder a/b/c has been deleted, you can find the last commit involving the "a/b/c" folder by using a combination of:要在删除文件夹 a/b/c 时查找提交的 SHA#,您可以使用以下组合查找涉及“a/b/c”文件夹的最后一次提交:

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

and

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

Something like:就像是:

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

Output:输出:

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

In a form of simple BASH script (which I name deleted.sh, should have executable permissions):以一种简单的 BASH 脚本形式(我将其命名为 delete.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

Usage:用法:

./deleted.sh a/b/c

Output:输出:

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

How does it work它是如何工作的

The first commit, going back in history, that has no files in tree matching the folder path, should do.第一次提交,回到历史记录,树中没有与文件夹路径匹配的文件,应该这样做。

That is what the shell script is doing.这就是shell脚本正在做的事情。

It iterates backwards in history, retrieving all of the SHA#s that are related to any files in the folder, and then finds - among those commits - the first, that does not have any files matching the path provided, in the Git tree.它在历史中向后迭代,检索与文件夹中任何文件相关的所有 SHA#,然后在 Git 树中找到第一个提交,即没有任何与提供的路径匹配的文件。

The fact that that commit is coming up in the list to inspect, insures that there are changes, in it, that involve the folder.该提交出现在要检查的列表中这一事实确保了其中存在涉及该文件夹的更改。

The fact that there are no files matching the folder in its tree (filtered "ls-tree" returns an empty string), insures that it is the commit where le last file in that folder has been deleted.没有文件与其树中的文件夹匹配(过滤后的“ls-tree”返回空字符串)这一事实确保它是该文件夹中最后一个文件已被删除的提交。

As far as I know, there is no special git command to detect if a directory has been deleted/moved.据我所知,没有特殊的 git 命令来检测目录是否已被删除/移动。

However, if the whole directory has moved to a new location within a tracked git repository it should show up under the Untracked files: section of the git status command.但是,如果整个目录已移动到跟踪的 git 存储库中的新位置,它应该显示在git status命令的Untracked files:部分下。 Plus, all of its files will show as deleted.另外,它的所有文件都将显示为已删除。

As for the deleted directory, if you expect the directory to no longer exist you can run the ls command to double check that the directory has, in fact, been removed.至于删除的目录,如果您希望该目录不再存在,您可以运行ls命令来仔细检查该目录是否实际上已被删除。 If the directory isn't there, it isn't being tracked.如果目录不存在,则不会对其进行跟踪。

If the directory exists but contains nothing, then git is also not tracking it.如果目录存在但不包含任何内容,则 git 也不会跟踪它。 Still, you could try不过你可以试试

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

This solution was originally mentioned on this StackOverflow question .这个解决方案最初是在这个 StackOverflow question上提到的。 The command is supposed to check if a particular file is being tracked by git but in this situation git will check if there are any files where dirName is part of the file path.该命令应该检查 git 是否正在跟踪特定文件,但在这种情况下,git 将检查是否有任何文件dirName是文件路径的一部分。 If the folder isn't being tracked then an error will show up.如果未跟踪文件夹,则会显示错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM