Removal of unused dependencies using "autoremove"

I thought running apt-get autoremove without any following argument removes all unused dependencies left on the system, while running apt-get autoremove xxx removes xxx and its unused dependencies.

However I discovered otherwise. Running apt-get autoremove xxx not only removes xxx and its unused dependencies, it also removes all other unused dependencies.

I then tried running apt-get remove --auto-remove xxx, thinking that this would remove only xxx and its unused dependencies. To my surprise, this also removed xxx, its unused dependencies, and all other unused dependencies.

This leads me to two related questions.

(1) Is this the intended behaviour of the commands?

(2) Is there an easy way to remove xxx and its unused dependencies without removing other unused dependencies?

(It appears that aptitude remove also behaves in a similar way.)


Solution 1:

Looking in the file cmdline/apt-get.cc from the source tarball at http://packages.ubuntu.com/source/maverick/apt, I can see that --auto-remove is an argument which enables the APT::Get::AutomaticRemove setting.

The commands autoremove and remove both calls the function DoInstall.

The command "autoremove" sets APT::Get::AutomaticRemove too and it does therefore the same thing as --auto-remove.

Looking in the DoAutomaticRemove function, it's clearly visible that enabling the APT::Get::AutomaticRemove setting (--auto-remove and autoremove does this) causes Apt looping through all installed packages and marks unused packages for deletion.

From main():

CommandLine::Args Args[] = {
   // ... stripped to save space
   {0,"auto-remove","APT::Get::AutomaticRemove",0},
   // ...
}
CommandLine::Dispatch Cmds[] = { // ...
                                {"remove",&DoInstall},
                                {"purge",&DoInstall},
                                {"autoremove",&DoInstall},
                                // ...
}
// ...
// Parse the command line and initialize the package library
CommandLine CmdL(Args,_config);

From DoInstall():

 unsigned short fallback = MOD_INSTALL;
   if (strcasecmp(CmdL.FileList[0],"remove") == 0)
      fallback = MOD_REMOVE;
   else if (strcasecmp(CmdL.FileList[0], "purge") == 0)
   {
      _config->Set("APT::Get::Purge", true);
      fallback = MOD_REMOVE;
   }
   else if (strcasecmp(CmdL.FileList[0], "autoremove") == 0)
   {
      _config->Set("APT::Get::AutomaticRemove", "true");
      fallback = MOD_REMOVE;
   }

From function DoAutomaticRemove:

   bool doAutoRemove = _config->FindB("APT::Get::AutomaticRemove", false);
   // ...
   // look over the cache to see what can be removed
   for (pkgCache::PkgIterator Pkg = Cache->PkgBegin(); ! Pkg.end(); ++Pkg) {
       if (doAutoRemove) {
       if(Pkg.CurrentVer() != 0 && 
          Pkg->CurrentState != pkgCache::State::ConfigFiles)
          Cache->MarkDelete(Pkg, purgePkgs);
       else
          Cache->MarkKeep(Pkg, false, false);
   }
   }

I cannot speak whether it's intended or not, you could fill a bug / ask a question at launchpad.net.


At the moment, it is not possible to exclude packages from deletion by apt-get autoremove. If you want to keep packages, run apt-get -s autoremove, copy the packages from the list and remove the packages from that list you want to keep. Finally, remove those packages: sudo apt-get purge [packages-to-be-removed] (purge removes the configuration files too, if any)