Home > git > git – how to easily remove ‘deleted’ files

git – how to easily remove ‘deleted’ files

git is a distributed version control system. There are lots of tutorials online to teach you the basics of this great system; that’s not the intent of this post. Rather, I want to share a neat trick I found on another site.

When you move files that have been checked into git without using the git mv command, as often happens when using an IDE and renaming a file, you are left with untracked files, and deleted files.

Nick@Macintosh-3 ~/Desktop/git_example$ mkdir src
Nick@Macintosh-3 ~/Desktop/git_example$ touch src/Hello.java
Nick@Macintosh-3 ~/Desktop/git_example$ git add src/
Nick@Macintosh-3 ~/Desktop/git_example$ git ci -m "Initial commit"
[master (root-commit) 97eb204] Initial commit
 0 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 src/Hello.java
Nick@Macintosh-3 ~/Desktop/git_example master$ git status
# On branch master
nothing to commit (working directory clean)
Nick@Macintosh-3 ~/Desktop/git_example master$ ls
Nick@Macintosh-3 ~/Desktop/git_example master$ mv src/Hello.java src/Goodbye.java
Nick@Macintosh-3 ~/Desktop/git_example master$ git status
# On branch master
# Changed but not updated:
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#   deleted:    src/Hello.java
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#   src/Goodbye.java
no changes added to commit (use "git add" and/or "git commit -a")

As soon as you delete the src/Hello.java and add the src/Goodbye.java file, git is smart enough to realize that you really have just renamed or moved the file:

Nick@Macintosh-3 ~/Desktop/git_example master$ git rm src/Hello.java
rm 'src/Hello.java'
Nick@Macintosh-3 ~/Desktop/git_example master$ git add src/Goodbye.java
Nick@Macintosh-3 ~/Desktop/git_example master$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#   renamed:    src/Hello.java -> src/Goodbye.java

While this pattern is not too onerous when you move just a few files around, when you are in the midst of refactoring you could have multiple files moved into different directories, leading to a raft of these deleted files that need to be manually removed from git. Because they are no longer at the old location in the file system, we cannot use tab completion to help remove the old files; you must type out the full path to the file to be deleted. This can be a big pain.

For instance, imagine I have the following tree structure:

Nick@Macintosh-3 ~/Desktop/git_example master$ tree src/
`-- org
    `-- example
        `-- nick
            |-- 1.java
            |-- 10.java
            |-- 2.java
            |-- 3.java
            |-- 4.java
            |-- 5.java
            |-- 6.java
            |-- 7.java
            |-- 8.java
            `-- 9.java

And we change the package name from an external, non-git process/program:

Nick@Macintosh-3 ~/Desktop/git_example master$ mv src/org/example/nick src/org/example/blog
Nick@Macintosh-3 ~/Desktop/git_example master$ git add src/org/example/blog/
Nick@Macintosh-3 ~/Desktop/git_example master$ git st
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#   new file:   src/org/example/blog/1.java
#   new file:   src/org/example/blog/10.java
#   new file:   src/org/example/blog/2.java
#   new file:   src/org/example/blog/3.java
#   new file:   src/org/example/blog/4.java
#   new file:   src/org/example/blog/5.java
#   new file:   src/org/example/blog/6.java
#   new file:   src/org/example/blog/7.java
#   new file:   src/org/example/blog/8.java
#   new file:   src/org/example/blog/9.java
# Changed but not updated:
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#   deleted:    src/org/example/nick/1.java
#   deleted:    src/org/example/nick/10.java
#   deleted:    src/org/example/nick/2.java
#   deleted:    src/org/example/nick/3.java
#   deleted:    src/org/example/nick/4.java
#   deleted:    src/org/example/nick/5.java
#   deleted:    src/org/example/nick/6.java
#   deleted:    src/org/example/nick/7.java
#   deleted:    src/org/example/nick/8.java
#   deleted:    src/org/example/nick/9.java

It is a bit of a pain to remove all of the deleted files individually.

Fortunately, there is a shortcut.

Nick@Macintosh-3 ~/Desktop/git_example master$ git ls-files --deleted
Nick@Macintosh-3 ~/Desktop/git_example master$ git rm `git ls-files --deleted`
rm 'src/org/example/nick/1.java'
rm 'src/org/example/nick/10.java'
rm 'src/org/example/nick/2.java'
rm 'src/org/example/nick/3.java'
rm 'src/org/example/nick/4.java'
rm 'src/org/example/nick/5.java'
rm 'src/org/example/nick/6.java'
rm 'src/org/example/nick/7.java'
rm 'src/org/example/nick/8.java'
rm 'src/org/example/nick/9.java'

If this is a common enough use case, we can add aliases in the global ~/.gitconfig file to support this.

    br = branch
    ci = commit
    co = checkout
    st = status
    # list files
    ls = ls-files
    # list deleted files
    lsd = ls-files --deleted
    # remove deleted files
    rmd = !git rm `git ls-files --deleted`

See the great wiki page on Aliases for information. The exclamation mark is used to indicate that the command invoked is a non-git one; you can execute arbitrary shell commands this way. For instance:

    # A stupid thing to do, but illustrates that arbitrary unix commands can be executed in this manner
    cal = !cal
Nick@Macintosh-3 ~/Desktop/git_example master$ git cal
   September 2010
Su Mo Tu We Th Fr Sa
          1  2  3  4
 5  6  7  8  9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30

All credit to the git cheat sheet site that initially brought the ls-files –deleted trick to my attention. Hopefully the alias I have provided will be useful to some people.

Categories: git Tags: , ,
  1. February 11, 2012 at 4:39 pm

    Thanks – I found this tip useful.

  2. Mikhail T.
    February 13, 2012 at 5:40 pm

    Unfortunately didn’t work for me… I have git version 1.7.8 installed on Windows machine… I am pretty sure it has something to do with Windows version of Git (or bash)…
    So, I got same problem solved by using this tip from stackoverflow.com:

    You can use

    git add -u

    To add the deleted files to the staging area, then commit them

    git commit -m “Deleted files manually”



  1. July 17, 2012 at 9:56 pm

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: