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 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
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
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?
Listing all the deleted files in all of git history can be done by combining git log with --diff-filter . The log gives you lots of options to show different bits of information about the commit that happened at that point.
GitHub's version control features allow us to see the complete history of a doc, access a doc at any point in time, and find deleted docs without manual backups.
On GitHub, you can see the commit history of a repository by: Navigating directly to the commits page of a repository. Clicking on a file, then clicking History, to get to the commit history for a specific file.
git can't push empty directories. It can only track files. If you try to push a folder with nothing in it, although it will exist on your local machine, nothing will go into your branch. So if someone tries to clone your code, they won't have the same folder structure as you do on your local machine.
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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.
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:
#> 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):
#!/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.
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.
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.
As far as I know, there is no special git command to detect if a directory has been deleted/moved.
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. 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. 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. Still, you could try
git ls-files dirName/ --error-unmatch; echo$?
This solution was originally mentioned on this 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. If the folder isn't being tracked then an error will show up.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With