Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Git how to detect whole folder deleted/moved

Tags:

git

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?

like image 970
Kakawait Avatar asked Sep 08 '15 15:09

Kakawait


People also ask

How do I see my git deletions?

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.

Can you see deleted files in git history?

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.

How do I see my entire git history?

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.

Can git track folders?

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.


2 Answers

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.

like image 89
Dmitri Sologoubenko Avatar answered Sep 21 '22 08:09

Dmitri Sologoubenko


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.

like image 21
TheSkinnyHipo Avatar answered Sep 21 '22 08:09

TheSkinnyHipo