Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams That's actually not true. That answer does not address removing the submodule entry from .git/config . The accepted answer shows the up-to-date way to fully remove a a submodule. It's also explained more succinctly in this answer: stackoverflow.com/a/36593218/1562138 fvgs Apr 13, 2016 at 9:02 I found this article very helpful in removing submodules. It includes information on removing entries in the .gitsubmodules and .git/config files link Ri_ May 15, 2016 at 17:46 Please save yourself some time and directly go the answer that works (in 2017): stackoverflow.com/a/36593218/528313 Vincenzo Pii Jan 16, 2017 at 12:57 I've wrestled submodule problems for two days. The breakthrough came when I found this: forums.developer.apple.com/thread/13102 . Basically, Xcode, and perhaps other apps, struggle to expand url's containing '~'. Once I changed ssh://username@server.remoteHost.com/~/git/MyRepo.git to ssh://username@server.remoteHost.com/home/username/git/MyRepo.git (look up the actual path on your server), all the weirdness disappeared with ten minutes. See also stackoverflow.com/questions/32833100/… Elise van Looij Feb 9, 2018 at 12:48

In modern git (I'm writing this in 2022, with an updated git installation), this has become quite a bit simpler:

  • Run git rm <path-to-submodule> , and commit .
  • This removes the filetree at <path-to-submodule> , and the submodule's entry in the .gitmodules file. I.e. all traces of the submodule in your repository proper are removed.

    As the docs note however, the .git dir of the submodule is kept around (in the modules/ directory of the main project's .git dir), " to make it possible to checkout past commits without requiring fetching from another repository ".
    If you nonetheless want to remove this info, manually delete the submodule's directory in .git/modules/ , and remove the submodule's entry in the file .git/config . These steps can be automated using the commands

  • rm -rf .git/modules/<path-to-submodule> , and
  • git config --remove-section submodule.<path-to-submodule> .
  • Older community wiki instructions:

    Via the page Git Submodule Tutorial :

    To remove a submodule you need to:

  • Delete the relevant section from the .gitmodules file.
  • Stage the .gitmodules changes:
    git add .gitmodules
  • Delete the relevant section from .git/config .
  • Remove the submodule files from the working tree and index:
    git rm --cached path_to_submodule (no trailing slash).
  • Remove the submodule's .git directory:
    rm -rf .git/modules/path_to_submodule
  • Commit the changes:
    git commit -m "Removed submodule <name>"
  • Delete the now untracked submodule files:
    rm -rf path_to_submodule
  • See also : alternative steps below .

    @abernier A curt answer could be "because no such command exists." My guess is that they're trying to make the removal of submodule files vs submodule configuration explicit to avoid accidental data loss. Perhaps one person would think that git submodule rm simply removes submodule registration, and would be surprised if the command also deleted the local repository. Any local changes would be irretrievably lost. And perhaps another person would think that only the files would be removed. John Douthat Jan 21, 2011 at 1:50 Frankly, I don't know why. I hope they add a command, though. These 4 steps are too complicated. John Douthat Jan 21, 2011 at 1:56 Here's a bash script that removes a submodule, just create a git alias for submodule-rm ;) gist.github.com/2491147 Capi Etheriel Apr 25, 2012 at 17:27

    Since git1.8.3 (April 22d, 2013) :

    There was no Porcelain way to say "I no longer am interested in this submodule", once you express your interest in a submodule with " git submodule init ".
    " git submodule deinit " is the way to do so.

    The deletion process also uses git rm (since git1.8.5 October 2013).

    Summary

    The 3-steps removal process would then be:

    0. mv a/submodule a/submodule_tmp
    1. git submodule deinit -f -- a/submodule    
    2. rm -rf .git/modules/a/submodule
    3. git rm -f a/submodule
    # Note: a/submodule (no trailing slash)
    # or, if you want to leave it in your working tree and have done step 0
    3.   git rm --cached a/submodule
    3bis mv a/submodule_tmp a/submodule
    

    Explanation

    rm -rf: This is mentioned in Daniel Schroeder's answer, and summarized by Eonil in the comments:

    This leaves .git/modules/<path-to-submodule>/ unchanged.
    So if you once delete a submodule with this method and re-add them again, it will not be possible because repository already been corrupted.

    git rm: See commit 95c16418:

    Currently using "git rm" on a submodule removes the submodule's work tree from that of the superproject and the gitlink from the index.
    But the submodule's section in .gitmodules is left untouched, which is a leftover of the now removed submodule and might irritate users (as opposed to the setting in .git/config, this must stay as a reminder that the user showed interest in this submodule so it will be repopulated later when an older commit is checked out).

    Let "git rm" help the user by not only removing the submodule from the work tree but by also removing the "submodule.<submodule name>" section from the .gitmodules file and stage both.

    git submodule deinit: It stems from this patch:

    With "git submodule init" the user is able to tell git they care about one or more submodules and wants to have it populated on the next call to "git submodule update".
    But currently there is no easy way they can tell git they do not care about a submodule anymore and wants to get rid of the local work tree (unless the user knows a lot about submodule internals and removes the "submodule.$name.url" setting from .git/config together with the work tree himself).

    Help those users by providing a 'deinit' command.
    This removes the whole submodule.<name> section from .git/config either for the given submodule(s) (or for all those which have been initialized if '.' is given).
    Fail if the current work tree contains modifications unless forced.
    Complain when for a submodule given on the command line the url setting can't be found in .git/config, but nonetheless don't fail.

    This takes care if the (de)initialization steps (.git/config and .git/modules/xxx)

    Since git1.8.5, the git rm takes also care of the:

  • 'add' step which records the url of a submodule in the .gitmodules file: it is need to removed for you.
  • the submodule special entry (as illustrated by this question): the git rm removes it from the index:
    git rm --cached path_to_submodule (no trailing slash)
    That will remove that directory stored in the index with a special mode "160000", marking it as a submodule root directory.
  • If you forget that last step, and try to add what was a submodule as a regular directory, you would get error message like:

    git add mysubmodule/file.txt 
    Path 'mysubmodule/file.txt' is in submodule 'mysubmodule'
    

    Note: since Git 2.17 (Q2 2018), git submodule deinit is no longer a shell script.
    It is a call to a C function.

    See commit 2e61273, commit 1342476 (14 Jan 2018) by Prathamesh Chavan (pratham-pc).
    (Merged by Junio C Hamano -- gitster -- in commit ead8dbe, 13 Feb 2018)

    git ${wt_prefix:+-C "$wt_prefix"} submodule--helper deinit \
      ${GIT_QUIET:+--quiet} \
      ${prefix:+--prefix "$prefix"} \
      ${force:+--force} \
      ${deinit_all:+--all} "$@"
                    @yourfriendzak here is one example of someone successfully using it: stackoverflow.com/a/16161950/6309. But keep in mind that, contrary to what I originally believed, 1.8.3 is not yet released! On Unix, you can compile it from the sources.
    – VonC
                    Apr 28, 2013 at 18:45
                    @HamishDowner the special entry should be gone (the directory is no longer a submodule), and the .gitmodules should be ok, but I would still double-check anything with the .git directory (ie the local config, within your local repo: that isn't modified by a git pull)
    – VonC
                    Jun 4, 2013 at 15:40
                    @Jayen yes, if you commit the removal of the .gitmodules entry and the removal of the special entry in the index, and push that repo, others can pull it and that submodule will be gone.
    – VonC
                    Aug 2, 2013 at 6:04
                    In current git (v1.9+), plain old git rm submodule does exactly what you want as other people have already said.
    – Pete Peterson
                    Jun 12, 2014 at 17:36
    

    The majority of answers to this question are outdated, incomplete, or unnecessarily complex.

    A submodule cloned using git 1.7.8 or newer will leave at most four traces of itself in your local repo. The process for removing those four traces is given by the three commands below:

    # Remove the submodule entry from .git/config
    git submodule deinit -f path/to/submodule
    # Remove the submodule directory from the superproject's .git/modules directory
    rm -rf .git/modules/path/to/submodule
    # Remove the entry in .gitmodules and remove the submodule directory located at path/to/submodule
    git rm -f path/to/submodule
                    Why this answer has so few upvotes? All those popular answers miss something, this is the only one that really removes all traces of a submodule, in the simplest possible way. And note: the order of commands matters.
    – mbdevpl
                    Sep 7, 2016 at 6:08
                    @mbdevpl came 3 years after the accepted answer, and I guess no one's managed to convince the OP to accept this one
    – Andy
                    Feb 20, 2017 at 1:58
                    In 2019 this doesn't work. The last line actually tries to remove from the .git/modules folder, which you've already removed in the above line. Adding -- to the first line like the accepted answer seems to make this work.
    – Fmstrat
                    Jun 28, 2019 at 20:01
    

    Just a note. Since git 1.8.5.2, two commands will do:

    git rm -r the_submodule
    rm -rf .git/modules/the_submodule
    

    As @Mark Cheverton's answer correctly pointed out, if the second line isn't used, even if you removed the submodule for now, the remnant .git/modules/the_submodule folder will prevent the same submodule from being added back or replaced in the future. Also, as @VonC mentioned, git rm will do most of the job on a submodule.

    --Update (07/05/2017)--

    Just to clarify, the_submodule is the relative path of the submodule inside the project. For example, it's subdir/my_submodule if the submodule is inside a subdirectory subdir.

    As pointed out correctly in the comments and other answers, the two commands (although functionally sufficient to remove a submodule), do leave a trace in the [submodule "the_submodule"] section of .git/config (as of July 2017), which can be removed using a third command:

    git config -f .git/config --remove-section submodule.the_submodule 2> /dev/null
                    I'm on git version 2.4.9 (Apple Git-60) and all I had to do was rm the_submodule. I pushed that then re-added a folder named the same as the submodule and it worked without issue.
    – David Silva Smith
                    Dec 3, 2015 at 21:23
                    This does not remove the submodule entry from .git/config. See stackoverflow.com/a/36593218/1562138 for the complete way to remove a submodule.
    – fvgs
                    Apr 13, 2016 at 8:53
                    @drevicko I just tested this with Git 2.11.1 and I observe the same behavior as before. git init && git submodule add <repository> && git rm <name> leaves behind the .git/config entry and the .git/modules/<name> directory and its contents. Perhaps you didn't initialize the submodule prior to removing it?
    – fvgs
                    Feb 22, 2017 at 16:58
                    @danday74 your command is actually needed if the submodule is checked out. otherwise you will get an error Unlink of file '...' failed
    – Adam Burley
                    Feb 28, 2018 at 21:38
    
  • Remove config entries:
    git config -f .git/config --remove-section submodule.$submodulename
    git config -f .gitmodules --remove-section submodule.$submodulename
  • Remove directory from index:
    git rm --cached $submodulepath
  • Commit
  • Delete unused files:
    rm -rf $submodulepath
    rm -rf .git/modules/$submodulename
  • Please note: $submodulepath doesn't contain leading or trailing slashes.

    Background

    When you do git submodule add, it only adds it to .gitmodules, but once you did git submodule init, it added to .git/config.

    So if you wish to remove the modules, but be able to restore it quickly, then do just this:

    git rm --cached $submodulepath
    git config -f .git/config --remove-section submodule.$submodulepath
    

    It is a good idea to do git rebase HEAD first and git commit at the end, if you put this in a script.

    Also have a look at an answer to Can I unpopulate a Git submodule?.

    I had a lot of submodules (and a bigger mess) so I had to pass them through a for loop. Since most of them where under a specific directory and ls output contained trailing slashes. I did something like for dir in directory/*; do git rm --cached $dir; done. – Pablo Olmos de Aguilera C. Oct 9, 2011 at 20:50 To get this the list which can be used in script for recursive deletion - git config -f .git/config -l | cut -d'=' -f1 | grep "submodule.$MODPATH" | sed 's/^submodule\.//' | sed 's/\.url$//' - - looks like you have to really do this in case if there is something messed up, otherwise just git submodule | grep -v '^+' | cut -d' ' -f3 – errordeveloper Oct 12, 2011 at 0:43 to get the list of modules where no local changes had been made - git submodule | grep '^+' | cut -d' ' -f2 – errordeveloper Oct 12, 2011 at 1:01 note, I had to include submodulename in double quotes "submodulename" .. referring the .git/config file – muon Jul 20, 2017 at 15:22 Simple. Efficient. In 2.25.0, after the step 1, you need to stage .gitmodules changes before step 2. – Michel Donais Feb 5, 2020 at 14:56

    To remove a submodule added using:

    REPOSITORY=blah@blah.com:repos/blah.git
    MOD_DIR=lib/blah
    git submodule add $REPOSITORY $MOD_DIR
    
    git rm $MOD_DIR
    

    That's it.

    For old versions of git (circa ~1.8.5, actually even in 2.26.2) use:

    git submodule deinit $MOD_DIR
    git rm $MOD_DIR
    git config -f .gitmodules --remove-section submodule.$MOD_DIR
                    +1 indeed. This is the only correct answer from git 1.8.3 onwards. Should be accepted as the correct one.
    – Xananax
                    Jul 2, 2014 at 18:26
                    @RudolfAdamkovic it works for me? Notice it only removes the submodule entry if the exact path matches; if you've moved a submodule and then use git rm it doesn't; A quick test with 2.5.4 on my mac updates the .gitmodules file, as described in the documentation here: git-scm.com/docs/git-rm#_submodules ... but if you have found some kind of combination of platform / version where this doesn't happen, you should probably lodge a bug about it.
    – Doug
                    Jan 2, 2016 at 15:48
                    This answer is not entirely correct. git rm leaves stuff in .git/modules/ dir and  .git/config file (ubuntu, git 2.7.4). Other answer works 100%: stackoverflow.com/a/36593218/4973698
    – mbdevpl
                    Sep 7, 2016 at 6:03
                    Will deinit remove the submodule but leave the files? I want it to remove all of the remnants in git but leave the actual folder in place.
    – justin.m.chase
                    Nov 3, 2021 at 19:08
                    I was having troubles with this as well. If you try to reinstall a submodule to the same path, it keeps the branch info cached in the location you mentioned which messes things up.
    – jangosteve
                    Mar 5, 2012 at 22:27
                    Thanks, I needed this too. @Anton, I agree, and I've edited the topvoted answer to add this info.
    – William Denniss
                    Sep 23, 2012 at 15:17
                    I used the --name option to make the replace work... see stackoverflow.com/questions/14404704/…
    – joseph.hainline
                    Jan 18, 2013 at 18:06
    

    You must remove the entry in .gitmodules and .git/config, and remove the directory of the module from the history:

    git rm --cached path/to/submodule
    

    If you'll write on git's mailing list probably someone will do a shell script for you.

    There is no need for any shell script, other answer has commands for removing all traces of a submodule: stackoverflow.com/a/36593218/4973698 – mbdevpl Sep 7, 2016 at 6:06
    [alias]
      rms = "!f(){ git rm --cached \"$1\";rm -r \"$1\";git config -f .gitmodules --remove-section \"submodule.$1\";git config -f .git/config --remove-section \"submodule.$1\";git add .gitmodules; }; f"
    

    Put that in your git config, and then you can do: git rms path/to/submodule

    -1 as this is plain too wrong. FIRST: This assumes that the submodule's name and path are identical which is most often not the case. I.E. git clone https://github.com/hilbix/empty.git; cd empty; git submodule add https://github.com/hilbix/empty.git one; git mv one two; git rms two. SECOND: You must execute this from the correct path. git aliases should work anywhere in the worktree (or fail gracefully). THIRD: git config -f .git/config fails within submodules, as .git usually is a file there. – Tino Nov 25, 2019 at 9:31

    I found deinit works good for me:

    git submodule deinit <submodule-name>    
    git rm <submodule-name>
    

    From git docs:

    deinit

    Unregister the given submodules, i.e. remove the whole submodule.$name section from .git/config together with their work tree.

    AFAICS this seems to be the most safest answer for newer gits which know of deinit, as the other answer removes the .git/modules/submodule directory too early, which seems to make newer gits to fail now or then. Also (see my comment there) removing .git/modules/submodule might be the wrong path, so this is a dangerous step, best taken later only when git complains (or if you are 299% sure this what you want, is the correct path and really needed). – Tino Nov 25, 2019 at 9:42 I also needed git commit to commit staged changes in working dir: modified .gitmodules and deleted <submodule-path>. – Yuri Pozniak Feb 19, 2020 at 1:01
  • Delete the relevant line from the .gitmodules file:

    git config -f .gitmodules --remove-section submodule.$path_to_submodule

  • Delete the relevant section from .git/config

    git config -f .git/config --remove-section submodule.$path_to_submodule

  • Unstage and remove $path_to_submodule only from the index (to prevent losing information)

    git rm --cached $path_to_submodule

  • Track changes made to .gitmodules

    git add .gitmodules

  • Commit the superproject

    git commit -m "Remove submodule submodule_name"

  • Delete the now untracked submodule files

    rm -rf $path_to_submodule

    rm -rf .git/modules/$path_to_submodule

  • so everyone else who pulls down my change will have to run rm -rf $path_to_submodule rm -rf .git/modules/$path_to_submodule to remove the submodule cache ? – j2emanue Apr 24, 2015 at 15:09 I recommend to update, git submodule update. And if the submodules paths weren't updated correctly (git throws an error), remove them: rm -rf .git/modules/<submodule> && rm -rf <submodule> && git submodule update – luissquall Apr 29, 2015 at 0:22

    If the submodule was accidentally added because you added, committed and pushed a folder that was already a Git repository (contained .git), you won’t have a .gitmodules file to edit, or anything in .git/config. In this case all you need is :

    git rm --cached subfolder
    git add subfolder
    git commit -m "Enter message here"
    git push
    

    FWIW, I also removed the .git folder before doing the git add.

  • git submodule deinit <path to submodule>
  • Remove the section from .gitmodules
  • git rm <path to submodule>
  • Delete the module files which you need to remove from your project.
  • Add the deleted files to git and call git add .gitmodules
  • Commit and Push
  • For me it was enough to call git submodule deinit <submodule_name> and git rm <path_to_submodule>. Last command automatically deletes the entry inside the .gitmodules. Git 2.17 – Dmytro Ovdiienko May 5, 2020 at 20:42

    After experimenting with all the different answers on this site, I ended up with this solution:

    #!/bin/sh
    path="$1"
    if [ ! -f "$path/.git" ]; then
      echo "$path is no valid git submodule"
      exit 1
    git submodule deinit -f $path &&
    git rm --cached $path &&
    rm -rf .git/modules/$path &&
    rm -rf $path &&
    git reset HEAD .gitmodules &&
    git config -f .gitmodules --remove-section submodule.$path
    

    This restores the exact same state as before you added the submodule. You can right away add the submodule again, which was not possible with most of the answers here.

    git submodule add $giturl test
    aboveScript test
    

    This leaves you with a clean checkout with no changes to commit.

    This was tested with:

    $ git --version
    git version 1.9.3 (Apple Git-50)
                    -1 Does not work if you try to remove a submodule within a submodule (submodule can form trees!).  Also this is dangerously buggy due to missing quoting!  Example git submodule add https://github.com/hilbix/empty.git 'dangerous .. submodule' -> when you try to remove 'dangerous .. submodule' with your script, this will rm -rf .. which is most likely not what you want ..
    – Tino
                    Nov 25, 2019 at 9:49
    

    What I'm currently doing Dec 2012 (combines most of these answers):

    oldPath="vendor/example"
    git config -f .git/config --remove-section "submodule.${oldPath}"
    git config -f .gitmodules --remove-section "submodule.${oldPath}"
    git rm --cached "${oldPath}"
    rm -rf "${oldPath}"              ## remove src (optional)
    rm -rf ".git/modules/${oldPath}" ## cleanup gitdir (optional housekeeping)
    git add .gitmodules
    git commit -m "Removed ${oldPath}"
    

    I recently find out a git project which include many useful git related command: https://github.com/visionmedia/git-extras

    Install it and type :

    git-delete-submodule submodule
    

    Then things are done. The submodule directory will be removed from your repo and still exist in your filesystem. You can then commit the change like: git commit -am "Remove the submodule".

    You can call this as git delete-submodule, as git-extras needs to be in the path to work. Also note that I recommend to not use git-extras, as many parts of it are extremely buggy and dangerous. I.E. git-delete-submodule possibly removes the wrong path below .git/modules/*, as it assumes that the module and the path are identical (which is quite often not the case), and it does not work correctly if you try to remove a submodule within a submodule. git-extras might be 99% helpful, but please do not complain if things utterly go wrong using it. YOU HAVE BEEN WARNED! – Tino Nov 25, 2019 at 10:03 For saving time use this commands apt install git-extras && git delete-submodule submodule. @Chien-Wei Huang has extra - in post – Machinexa Sep 2, 2021 at 17:20

    Here is what I did :

    1.) Delete the relevant section from the .gitmodules file. You can use below command:

    git config -f .gitmodules --remove-section "submodule.submodule_name"
    

    2.) Stage the .gitmodules changes

    git add .gitmodules
    

    3.) Delete the relevant section from .git/config. You can use below command:

    git submodule deinit -f "submodule_name"
    

    4.) Remove the gitlink (no trailing slash):

    git rm --cached path_to_submodule
    

    5.) Cleanup the .git/modules:

    rm -rf .git/modules/path_to_submodule
    

    6.) Commit:

    git commit -m "Removed submodule <name>"
    

    7.) Delete the now untracked submodule files

    rm -rf path_to_submodule
                    Thanks for this.  For me, I had to rearrange the first three steps' order to 3), 1), 2). Doing 1) first gave fatal: no submodule mapping found in .gitmodules for path 'submodule_name' at step 3.  Both steps were necessary though.  (git v2.8.2)
    – U007D
                    Aug 25, 2016 at 0:16
    

    For the benefit of the reader, this here tries to sum it up and give a step-by-step guide on how to do it if things do not work as expected. Following is the tested and safe way for git version 2.17 and above to get rid of a submodule:

    submodule="path/to/sub"              # no trailing slash!
    git submodule deinit -- "$submodule"
    git rm -- "$submodule"
    
  • If this does not work for you, see below.
  • No options. Nothing dangerous. And do not even consider doing more!
  • Tested with Debian Buster 2.20.1 and Ubuntu 18.04 2.17.1.
  • "$submodule" is just to emphasize where to put the name, and that you have to be careful with spaces and the like
  • If on Windows ignore the first line and replace "$submodule" with the Windows way of a properly specified path to the submodule. (I am not Windows)
  • Warning!

    Never touch the insides of the .git directory yourself! Editing inside .git enters the dark side. Stay away at all cost!

    And yes, you can blame git for this, as many handy things were missing in git in the past. Like a proper way to remove submodules again.

    I think there is a very dangerous part in the documentation of git submodule. It recommends to remove $GIT_DIR/modules/<name>/ yourself. In my understanding this is not only plain wrong, it is extremely dangerous and provokes major headaches in future! See below.

    Note that

    git module deinit
    

    is the direct inverse to

    git module init
    
    git submodule deinit -- module
    git rm -- module
    

    also is quite the inverse to

    git submodule add -- URL module
    git submodule update --init --recursive -- module
    

    because some commands basically need to do more than just a single thing:

  • git submodule deinit -- module
  • (1) updates .git/config
  • git rm
  • (2) removes the files of the module
  • (3) thereby recursively removes the submodules of the submodule
  • (4) updates .gitmodules
  • git submodule add
  • pulls in the data to .git/modules/NAME/
  • (1) does git submodule init, so updates .git/config
  • (2) does git submodule update, so, nonrecursively checks out the module
  • (4) updates .gitmodules
  • git submodule update --init --recursive -- module
  • pulls in further data if needed
  • (3) checks out the submodules of the submodule recursively
  • This cannot be fully symmetric, as keeping it strictly symmetric does not make much sense. There simply is no need for more than two commands. Also "pulling in the data" is implicit, because you need it, but removing the cached information is not done, because this is not needed at all and might wipe precious data.

    This truly is puzzling to newcomers, but basically is a good thing: git just does the obviously thing and does that right, and does not even try to do more. git is a tool, which must do a reliable job, instead of being just another "Eierlegende Wollmilchsau" ("Eierlegende Wollmilchsau" translates for me to "some evil version of a Swiss army knife").

    So I understand complaints of people, saying "Why doesn't do git the obvious thing for me". This is because "obvious" here depends from the point of view. Reliability in each and every situation is far more important. Hence what's obvious for you often is not the right thing in all possible technical situations. Please remember that: AFAICS git follows the technical path, not the social one. (Hence the clever name: git)

    If this fails

    The commands above may fail due to following:

  • Your git is too old. Then use a newer git. (See below how to.)
  • You have uncommitted data and might lose data. Then better commit them first.
  • Your submodule is not clean in a git clean sense. Then first clean your submodule using that command. (See below.)
  • You have done something in the past which is unsupported by git. Then you are on the dark side and things get ugly and complicated. (Perhaps using another machine fixes it.)
  • Perhaps there are more ways to fail I am not aware of (I am just some git power-user.)
  • Possible fixes follow.

    Use a newer git

    If your machine is too old there is no submodule deinit in your git. If you do not want (or can) update your git, then just use another machine with a newer git! git is meant to be fully distributed, so you can use another git to get the job done:

  • workhorse:~/path/to/worktree$ git status --porcelain must not output anything! If it does, cleanup things first!
  • workhorse:~/path/to/worktree$ ssh account@othermachine
  • othermachine:~$ git clone --recursive me@workhorse path/to/worktree/.git TMPWORK && cd TMPWORK
  • Now do the submodule stuff
  • othermachine:~/TMPWORK$ git commit . -m . && exit
  • workhorse:~/path/to/worktree$ git fetch account@othermachine:TMPWORK/.git
  • workhorse:~/path/to/worktree$ git merge --ff-only FETCH_HEAD. If this does not work, use git reset --soft FETCH_HEAD
  • Now cleanup things, until git status is clean again. You are able to do so, because you have had it clean before, thanks to the first step.
  • This othermachine can be some VM, or some Ubuntu WSL under Windows, whatever. Even a chroot (but I assume that you are non-root, because if you are root it should be more easy to update to the newer git).

    Note that if you cannot ssh in, there are trainloads of ways to transport git repositories. You can copy your worktree on some USB stick (including the .git directory), and clone from the stick. Clone the copy, just to get things in a clean fashion again. This might be a PITA, in case your submodules are not accessible from othermachine directly. But there is a solution for this, too:

    git config --add url.NEWURLPREFIX.insteadOf ORIGINALURLPREFIX
    

    You can use this multiply, and this is saved into $HOME/.gitconfig. Something like

    git config --add 'url./mnt/usb/repo/.insteadof' https://github.com/
    

    rewrites URLs like

    https://github.com/XXX/YYY.git
    
    /mnt/usb/repo/XXX/YYY.git
    

    It's easy if you start to become accustomed to powerful git features like this.

    Cleanup things first

    Cleaning manually up is good, because this way you perhaps detect some things you forgot about.

  • If git complains about unsaved stuff, commit and push it somewhere safe.
  • If git complains about some leftovers, git status and git clean -ixfd is your friend
  • Try to abstain from options to rm and deinit as long as you can. Options (like -f) for git are good if you are a Pro. But as you came here, you probably are not so experienced in the submodule area. So better be safe than sorry.
  • Example:

    $ git status --porcelain
     M two
    $ git submodule deinit two
    error: the following file has local modifications:
    (use --cached to keep the file, or -f to force removal)
    fatal: Submodule work tree 'two' contains local modifications; use '-f' to discard them
    $ cd two
    $ git submodule deinit --all
    error: the following file has local modifications:
        md5chk
    (use --cached to keep the file, or -f to force removal)
    fatal: Submodule work tree 'md5chk' contains local modifications; use '-f' to discard them
    $ cd md5chk
    $ git submodule deinit --all
    error: the following file has local modifications:
    (use --cached to keep the file, or -f to force removal)
    fatal: Submodule work tree 'tino' contains local modifications; use '-f' to discard them
    $ cd tino
    $ git status --porcelain
    ?? NEW
    $ git clean -i -f -d
    Would remove the following item:
    *** Commands ***
        1: clean                2: filter by pattern    3: select by numbers    4: ask each
        5: quit                 6: help
    What now> 1
    Removing NEW
    $ cd ../../..
    $ git status --porcelain
    $ git submodule deinit two
    Cleared directory 'two'
    Submodule 'someunusedname' (https://github.com/hilbix/src.git) unregistered for path 'two'
    

    You see, there is no -f needed on submodule deinit. If things are clean, in a git clean sense. Also note that git clean -x is not needed. This means git submodule deinit unconditionally removes untracked files which are ignored. This is usually what you want, but do not forget about it. Sometimes ignored files might be precious, like cached data which takes hours to days to be calculated again.

    Why never remove $GIT_DIR/modules/<name>/?

    Probably people want to remove the cached repository, because they are afraid to run into a problem later. This is true, but running into that "problem" is the correct way to solve it! Because the fix is easy, and done right you will be able to live happily ever after. This avoids more cumbersome trouble than when you remove the data yourself.

    Example:

    mkdir tmptest &&
    cd tmptest &&
    git init &&
    git submodule add https://github.com/hilbix/empty.git two &&
    git commit -m . &&
    git submodule deinit two &&
    git rm two &&
    git commit -m . &&
    git submodule add https://github.com/hilbix/src.git two
    

    The last line outputs following error:

    A git directory for 'two' is found locally with remote(s):
      origin    https://github.com/hilbix/empty.git
    If you want to reuse this local git directory instead of cloning again from
      https://github.com/hilbix/src.git
    use the '--force' option. If the local git directory is not the correct repo
    or you are unsure what this means choose another name with the '--name' option.
    

    Why this error? Because .git/modules/two/ previously was populated from https://github.com/hilbix/empty.git and now shall be re-populated from something else, namely https://github.com/hilbix/src.git. You won't see this if you re-populate it from https://github.com/hilbix/empty.git

    What to do now? Well, just do exactly as told! Use --name someunusedname

    git submodule add --name someunusedname https://github.com/hilbix/src.git two
    

    .gitmodules then looks like

    [submodule "someunusedname"]
        path = two
        url = https://github.com/hilbix/src.git
    

    ls -1p .git/modules/ gives

    someunusedname/
    

    This way in future you can switch branches/commit forward and backward and will never get into any trouble again, due to two/ having two different (and possibly incompatible) upstream repositories. And the best is: You keep both cached locally, too.

  • This is not only true for you. It also is true for all others using your repository.
  • And you do not lose history. In case you forgot to push the very latest version of the old submodule, you can enter the local copy and do so later on. Note that it is quite common that somebody forgets to push some submodules (because this is a PITA for newcomers, until they became accustomed to git).
  • However if you removed the cached directory, both different checkouts will stumble upon each other, because you will not use the --name options, right? So each time you do the checkout you perhaps have to remove the .git/modules/<module>/ directory again and again. This is extremely cumbersome and makes it hard to use something like git bisect.

    So there is a very technical reason to keep this module directory as a placeholder. People who recommend to remove something below .git/modules/ either do not know better or forget to tell you that this makes powerful features like git bisect nearly impossible to use if this crosses such a submodule incompatibility.

    A further reason is shown above. Look at the ls. What do you see there?

    Well, the 2nd variant of module two/ is not under .git/modules/two/, it is under .git/modules/someunusedname/! So things like git rm $module; rm -f .git/module/$module are totally wrong! You must either consult module/.git or .gitmodules to find the right thing to remove!

    So not only most other answers fall into this dangerous trap, even very popular git extensions had this bug (it's now fixed there)! So better keep your hands of the .git/ directory if you do not exactly, what you are doing!

    And from the philosophical view, wiping history is always wrong! Except for quantum mechanics, as usual, but this is something completely different.

    FYI you probably guessed it: hilbix is my GitHub account.

    This encyclopedia of a post should be broken up into clearer sections with bigger/clearer sub headings to indicate the actual answer, and the different "troubleshooting"/etc sections. – Andrew Jan 19, 2020 at 19:17 Great answer with gotchas I am certain to have learned about the hard way. Highly recommend everyone at least speed reads it. – goldfishalpha Feb 7 at 11:01

    All the answers look outdated. I am using git version 2.28.0. One line answer is,

    git rm path-to-submodule
    

    However, even though the submodule is removed from source control, .git/modules/path-to-submodule still contains the submodule repository and .git/config contains its URL, so you still have to remove those manually:

    git config --remove-section submodule.path-to-submodule
    rm -rf .git/modules/path-to-submodule
    

    Sometimes, you have to use the -f flag:

    $ git rm -f img2vec
    

    For example, because you might get an error like this:

    $ git rm img2vec/
    error: the following file has changes staged in the index:
        img2vec
    (use --cached to keep the file, or -f to force removal)
                    Since this the top & most recent answer, you should update it with the following steps as well:  1. Remove the .gitmodules file. 2. Remove relevant data from the index as well by invoking the git rm --cached -r <path-to-submodule-dir>
    – Jarmos
                    Nov 10, 2021 at 10:19
    

    I had to take John Douthat's steps one step further and cd into the submodule's directory, and then remove the Git repository:

    cd submodule
    rm -fr .git
    

    Then I could commit the files as a part of the parent Git repository without the old reference to a submodule.

    I had to do this too in order to get past a "fatal: Not a git repository:" error when trying to do the git rm --cache step. – RickDT Apr 1, 2013 at 15:48

    With git v2.7.4 simple 3 steps worked just fine.

    git submodule deinit -f -- a/submodule    
    git rm -f a/submodule
    git commit
    

    Here are the 4 steps that I found necessary or useful (important ones first):

    git rm -f the_submodule
    rm -rf .git/modules/the_submodule
    git config -f .git/config --remove-section submodule.the_submodule
    git commit -m "..."
    

    In theory, git rm in step 1 should take care of it. Hopefully, the second part of OP question can be answered positively one day (that this can be done in one command).

    But as of July 2017, step 2 is necessary to remove data in .git/modules/ for otherwise, you can't e.g. add the submodule back in the future.

    You can probably get away with the above two steps for git 1.8.5+ as tinlyx's answer noted, as all git submodule commands seem to work.

    Step 3 removes the section for the_submodule in the file .git/config. This should be done for completeness. (The entry may cause problems for older git versions, but I don't have one to test).

    For this, most answers suggest using git submodule deinit. I find it more explicit and less confusing to use git config -f .git/config --remove-section. According to the git-submodule documentation, git deinit:

    Unregister the given submodules ... If you really want to remove a submodule from the repository and commit that use git-rm[1] instead.

    Last but not least, if you don't git commit, you will/may get an error when doing git submodule summary (as of git 2.7):

    fatal: Not a git repository: 'the_submodule/.git'
    * the_submodule 73f0d1d...0000000:
    

    This is regardless of whether you do steps 2 or 3.

    The best way to remove a submodule from git:

    $ git submodule deinit -f <submodule-name>
    $ rm -rf .git/modules/<submodule-name>
    $ git config -f .gitmodules --remove-section submodule.<submodule-name>
    $ git config -f .git/config --remove-section submodule.<submodule-name>
    $ git rm --cached <submodule-name>
    $ git commit -m 'rm submodule: <submodule-name>'
    

    I just found the .submodule (forgot exact name) hidden file, it has a list... you can erase them individually that way. I just had one, so I deleted it. Simple, but it might mess up Git, since I don't know if anything's attached to the submodule. Seems ok so far, aside from libetpan's usual upgrade issue, but that's (hopefully) unrelated.

    Noticed nobody posted manual erasing, so added

    Did not work, neither for git 2.17.1 nor git 2.20.1. However using git rm instead of git add worked for both. Notes: -f is not needed if things are clean. Be sure to never use options with git if you want to protect against unintended data loss. Also note that this leaves .git/modules/{module_name} in place. It is best practice to keep it there because git prints the correct(!) help how to proceed if something is blocked due to this. – Tino Nov 25, 2019 at 10:37
    project dir:     ~/foo_project/
    submodule:       ~/foo_project/lib/asubmodule
    - - - - - - - - - - - - - - - - - - - - - - - - -
      1.   cd ~/foo_project
      2.   git rm lib/asubmodule && 
              rm .git/modules/lib/asubmodule && 
                git submodule lib/asubmodule deinit --recursive --force
    

    Delete the relevant line from the .gitmodules file:

    git config -f .gitmodules --remove-section submodule.$path_to_submodule
    

    Delete the relevant section from .git/config

    git config -f .git/config --remove-section submodule.$path_to_submodule
    

    Unstage and remove $path_to_submodule only from the index (to prevent losing information)

    git rm --cached $path_to_submodule
    

    Track changes made to .gitmodules

    git add .gitmodules
    

    Commit the superproject

    git commit -m "Remove submodule submodule_name"
    

    Delete the now untracked submodule files

    rm -rf $path_to_submodule
    rm -rf .git/modules/$path_to_submodule
    

    See also : Alternative guide lines

    Can you please extend this with how to remove a submodule following a 'git submodule add' but without having ever committed it? I assume that in that case no commit is needed to remove the submodule, right? – Carlo Wood Jan 3, 2020 at 11:43 I think you need to swap the git rm --cached $path_to_submodule and git add .gitmodules no? I did get an error on the first command: fatal: Please stage your changes to .gitmodules or stash them to proceed because I had unstaged changes to .gitmodules. Doing the git add .gitmodules first solves that. – Carlo Wood Jan 3, 2020 at 11:49

    This worked for me. The above answers were showing this in the terminal and nothing else was happening

    'fatal: not removing 'demolibapp' recursively without -r'
    
  • demolibapp is my submodule name that I want to remove
  • git submodule deinit demolibapp
  • git rm --cached demolibapp -r
  • rm -rf .git/modules/demolibapp
  • git add --all
  • git commit -m "removing extra submodules"
  • git push
  • rm -rf demolibapp
  • If you want to remove the submodule without deleting the folder from your local file system here is what worked for me:

    MOD=example
    git rm --cached -f apps/$MOD
    git config -f .gitmodules --remove-section submodule.$MOD