@@ -557,6 +557,10 @@ public function getNamespaces()
557557 {
558558$ namespaces = [];
559559foreach ($ this ->all ()as $ command ) {
560+ if ($ command ->isHidden ()) {
561+ continue ;
562+ }
563+
560564$ namespaces =array_merge ($ namespaces ,$ this ->extractAllNamespaces ($ command ->getName ()));
561565
562566foreach ($ command ->getAliases ()as $ alias ) {
@@ -644,6 +648,12 @@ public function find($name)
644648$ commands =preg_grep ('{^ ' .$ expr .'}i ' ,$ allCommands );
645649 }
646650
651+ // hidden commands can only be matched exactly and shall not appear otherwise
652+ $ hiddenCommands =$ this ->removeHiddenCommands ($ commands );
653+ if (isset ($ hiddenCommands [$ name ])) {
654+ return $ hiddenCommands [$ name ];
655+ }
656+
647657// if no commands matched or we just matched namespaces
648658if (empty ($ commands ) ||\count (preg_grep ('{^ ' .$ expr .'$}i ' ,$ commands )) <1 ) {
649659if (false !==$ pos =strrpos ($ name ,': ' )) {
@@ -654,6 +664,8 @@ public function find($name)
654664$ message =sprintf ('Command "%s" is not defined. ' ,$ name );
655665
656666if ($ alternatives =$ this ->findAlternatives ($ name ,$ allCommands )) {
667+ $ this ->removeHiddenCommands ($ alternatives );
668+
657669if (1 ==\count ($ alternatives )) {
658670$ message .="\n\nDid you mean this? \n " ;
659671 }else {
@@ -1101,6 +1113,38 @@ private function findAlternatives(string $name, iterable $collection): array
11011113return array_keys ($ alternatives );
11021114 }
11031115
1116+ /**
1117+ * Removes hidden commands commands from a given array of command names and
1118+ * returns them as Command instances.
1119+ *
1120+ * @param string[] $commandNames The command names to filter
1121+ *
1122+ * @return Command[] An associative array of removed commands with
1123+ * command names and command aliases being the keys
1124+ *
1125+ * @internal
1126+ */
1127+ private function removeHiddenCommands (array &$ commandNames ):array
1128+ {
1129+ $ hiddenCommands = [];
1130+ foreach ($ commandNamesas $ key =>$ commandName ) {
1131+ $ command =$ this ->has ($ commandName ) ?$ this ->commands [$ commandName ] :$ this ->commandLoader ->get ($ commandName );
1132+
1133+ if (!$ command ->isHidden ()) {
1134+ continue ;
1135+ }
1136+
1137+ $ hiddenCommands [$ commandName ] =$ command ;
1138+ foreach ($ command ->getAliases ()as $ alias ) {
1139+ $ hiddenCommands [$ alias ] =$ command ;
1140+ }
1141+
1142+ unset($ commandNames [$ key ]);
1143+ }
1144+
1145+ return $ hiddenCommands ;
1146+ }
1147+
11041148/**
11051149 * Sets the default Command name.
11061150 *