55

How do I get rid of submodules when switching branches. I do not understand why git clean says it removed the submodule but does not. Is this a bug? Below are cut&paste steps to reproduce.

git --version
git version 1.7.8.4

git init submod
cd submod
echo "This is a submodule" > README.txt
git add .
git commit -m "Initial commit"
cd ..
git init prog
cd prog
echo "This is a program" > README.txt
git add .
git commit -a -m "Initial commit"
git checkout -b topic1
git submodule add ../submod
git commit -m "Added submodule"

git checkout master
#warning: unable to rmdir submod: Directory not empty
#Switched to branch 'master'

git status
# On branch master
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       submod/
#nothing added to commit but untracked files present (use "git add" to track)

git clean -fd
#Removing submod/

git status
# On branch master
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       submod/
#nothing added to commit but untracked files present (use "git add" to track)
Adrian Cornish
  • 23,227
  • 13
  • 61
  • 77
  • 1
    Sounds like a bug in the output of `git clean`. I imagine it's ignoring submodules explicitly, since deleting them may delete unrecoverable information (e.g. local changes), but it shouldn't be claiming to remove it – Lily Ballard Feb 16 '12 at 21:23
  • Also seems as the checkout should remove it as well - especially since its clean with no changes – Adrian Cornish Feb 17 '12 at 04:13

3 Answers3

78

This isn't a bug, it's documented behaviour. From man git-clean:

If an untracked directory is managed by a different git repository, it is not removed by default.

The submod directory is a different git repository; if you want to remove it, Use -f option twice if you really want to remove such a directory.

git clean -f -f -d submod does remove submod. See my steps below (almost identical; different git version and hard-coded submodule path because otherwise git spits the dummy).


Steps


$ git --version
git version 1.7.5.4 # Note, different git-version. 

Make the two repositories


git init submod
cd submod
echo "This is a submodule" > README.txt
git add .
git commit -m "Initial commit"
cd ..
git init prog
cd prog
echo "This is a program" > README.txt
git add .
git commit -a -m "Initial commit"

Add submod as a git submodule in topic1 branch.


git checkout -b topic1
git submodule add /Users/simont/sandbox/SOTESTING/Subdir-testing/submod
git commit -m "Added submodule"

Now for the interesting section.


$ git checkout master
warning: unable to rmdir submod: Directory not empty
Switched to branch 'master'

git status
# On branch master
# Untracked files:
#   (use "git add ..." to include in what will be committed)
#
#       submod/
#nothing added to commit but untracked files present (use "git add" to track)

Attempt to git-clean, then actually git-clean.


git clean -fd
#Removing submod/

git status
# On branch master
# Untracked files:
#   (use "git add ..." to include in what will be committed)
#
#       submod/
#nothing added to commit but untracked files present (use "git add" to track)

$ # As we can see, we haven't actually removed anything yet. 
$ ls
README.txt  submod

$ git clean -f -f -d submod
Removing submod/

$ ls
README.txt

$ git status
# On branch master
nothing to commit (working directory clean)
Community
  • 1
  • 1
simont
  • 68,704
  • 18
  • 117
  • 136
  • 5
    I like the fact that the -ff option is mentioned in the -d section of the man page, but not in the -f section... – marc.guenther Jul 24 '12 at 10:42
  • 2
    This is awesome! I'm using it as `git clean -ffxd` (to remove ignored files as well). At some point I may post to the mailing list about adding a submodule section (and maybe adding a hint in the error message). – eacousineau Sep 08 '13 at 21:19
  • 2
    This solution worked for me at first. But when switching back to the branch with the submodule, the files for it were gone. So I had to update the submodule again, and at that point I was back at the beginning with the same problem. – Anas Feb 04 '14 at 17:45
  • The solution provided is temporary as @anas said we are back to square one on checking back and restoring the repository. Anyone else found a better solution to this problem lately ? – Vihaan Verma Apr 07 '15 at 08:13
  • git -f -f -d doesn't work in version 2.5.0. – rickfoosusa Jan 29 '16 at 18:17
  • Great answer but `-ffd` may be better flags than `-f -f -d` for some depending on environment... @rickfoosusa just do `git -ffd` or `git -f -f -d` without mentioning any modules... I am guessing like me you have a branch with modules not in other branches and your switching between... – CrandellWS Apr 05 '16 at 02:54
18

To remove the "leftover" submodules after checking out a different branch, you can run the following. This command will recursively clean the main repository and all submodules. Warning: this will remove all untracked files as well.

git clean -xffd && git submodule foreach --recursive git clean -xffd

To see which files will be deleted without actually deleting yet, add the -n flag.

git clean -nxffd && git submodule foreach --recursive git clean -nxffd

Key to the command is the double-f passed to Git clean. Without that, Git will not remove folders that are a submodule (i.e. folders containing a .git subfolder).

jorisv92
  • 420
  • 4
  • 7
  • 2
    BE WARY, the `x` in above suggestion removes all `.gitignore` ignored files, which might not be the desired result. Other than that it seems rather effective. – Spangaer Apr 04 '22 at 14:35
0

Fundamentally, I used the accepted answer successfully (with git clean -ffd)... but for whatever complicated reason that wasn't quite enough in my use case. I still had a few untracked files/directories left behind in a submodule or two (out of a fairly large collection).

I could NOT employ the shotgun git clean -xffd approach, as I have untracked, ignored files and directories which need to be left in place.

What worked for me was to:

I think these steps were needed because the .gitignores in the repo / submodules must have been interfering (despite the fact I couldn't quite determine exactly why!). The second round of the cleaning might (?) resolve the issue of having nested .gitignores which are removed by the first clean, after still causing some undesired effect, but with those gone running the clean again finishes the job?

BuvinJ
  • 10,221
  • 5
  • 83
  • 96