list-tracked         List all files tracked by vcsh
    list-tracked-by \\
         <repo>          List files tracked by a repository
+   list-untracked       List all files not tracked by vcsh
    pull                 Pull from all vcsh remotes
    push                 Push to vcsh remotes
    rename <repo> \\
 }
 
 list_untracked() {
+       command -v 'comm' >/dev/null 2>&1 || fatal "Could not find 'comm'"
+
+       temp_file_others=$(mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX") || fatal 'Could not create temp file'
+       temp_file_untracked=$(mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX") || fatal 'Could not create temp file'
+       temp_file_untracked_copy=$(mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX") || fatal 'Could not create temp file'
+
+       # Hack in support for `vcsh list-untracked -r`
+       directory_opt="--directory"
+       shift 1
+       while getopts "r" flag; do
+               if [ x"$1" = x'-r' ]; then
+                       unset directory_opt
+               fi
+               shift 1
+       done
+
        for VCSH_REPO_NAME in $(list); do
-               [ -n $ran_once ] && files_untracked=$(printf '%s\n' "$files_untracked" | grep -x "$files_other")
                export GIT_DIR="$VCSH_REPO_D/$VCSH_REPO_NAME.git"
-               files_other="$(git ls-files --others)"
-               [ -z $ran_once ] && { ran_once=1; files_untracked=$files_other; }
+               git ls-files --others "$directory_opt" | (
+                       while read line; do
+                               echo "$line"
+                               directory_component=${line%%/*}
+                               [ -d "$directory_component" ] && printf '%s/\n' "$directory_component"
+                       done
+                       ) | sort -u > $temp_file_others
+               if [ -z "$ran_once" ]; then
+                       ran_once=1
+                       cp $temp_file_others $temp_file_untracked || fatal 'Could not copy temp file'
+               fi
+               cp $temp_file_untracked $temp_file_untracked_copy || fatal 'Could not copy temp file'
+               comm -12 --nocheck-order $temp_file_others $temp_file_untracked_copy > $temp_file_untracked
        done
-       echo "$files_untracked" | sort -u
+       cat $temp_file_untracked
+
+       unset directory_opt directory_component
+       rm -f $temp_file_others $temp_file_untracked $temp_file_untracked_copy || fatal 'Could not delete temp files'
 }
 
 rename() {