让git status显示未修改/未更改的跟踪文件?

时间:2013-04-30 19:00:45

标签: git version-control

这是一个简短的代码段示例(您可以将其粘贴到Linux终端中),创建一个新的git存储库并向其中添加一些文件(使用git版本1.7.9.5):

cd /tmp/
mkdir myrepo_git
cd myrepo_git/
git init
git config user.name "Your Name"
git config user.email you@example.com
echo "test" > file_tracked_unchanged.txt
echo "test" > file_tracked_changed.txt
echo "test" > file_untracked.txt
git add file_tracked_unchanged.txt 
git add file_tracked_changed.txt
git commit -m "initial commit"

现在,在初始提交之后,我想要更改file_tracked_changed.txt文件,并保持其他文件(此处仅file_tracked_unchanged.txt)保持不变以进行下一次提交。以下是一个片段,演示了git statusgit ls-filesgit shell输出的前缀为#的各种输出:

echo "test more" >> file_tracked_changed.txt

git status -uno
# # On branch master
# # Changes not staged for commit:
# #   (use "git add <file>..." to update what will be committed)
# #   (use "git checkout -- <file>..." to discard changes in working directory)
# #
# # modified:   file_tracked_changed.txt
# #
# no changes added to commit (use "git add" and/or "git commit -a")
git status
# # On branch master
# # Changes not staged for commit:
# #   (use "git add <file>..." to update what will be committed)
# #   (use "git checkout -- <file>..." to discard changes in working directory)
# #
# # modified:   file_tracked_changed.txt
# #
# # Untracked files:
# #   (use "git add <file>..." to include in what will be committed)
# #
# # file_untracked.txt
# no changes added to commit (use "git add" and/or "git commit -a")
git status -uno --short
#  M file_tracked_changed.txt
git status --short
#  M file_tracked_changed.txt
# ?? file_untracked.txt
git ls-files -v
# H file_tracked_changed.txt
# H file_tracked_unchanged.txt

git add file_tracked_changed.txt

git status -uno
# # On branch master
# # Changes to be committed:
# #   (use "git reset HEAD <file>..." to unstage)
# #
# # modified:   file_tracked_changed.txt
# #
# # Untracked files not listed (use -u option to show untracked files)
git status
# # On branch master
# # Changes to be committed:
# #   (use "git reset HEAD <file>..." to unstage)
# #
# # modified:   file_tracked_changed.txt
# #
# # Untracked files:
# #   (use "git add <file>..." to include in what will be committed)
# #
# # file_untracked.txt
git status -uno --short
# M  file_tracked_changed.txt
git status --short
# M  file_tracked_changed.txt
# ?? file_untracked.txt
git ls-files -v
# H file_tracked_changed.txt
# H file_tracked_unchanged.txt

我正在寻找的是一个命令,它将显示目录中的所有跟踪文件(git ls-files -v所做的),以及它们准确的存储库状态(git ls-files未显示,如它显示H作为所有跟踪文件的状态)。例如,我想获得类似伪代码的东西:

git status-tracked
# M file_tracked_changed.txt
# . file_tracked_unchanged.txt

...其中点.是指示跟踪但未更改的文件的符号(如果我没记错,SVN可能会使用U字符)。

最终,我还要显示目录中所有文件的状态,如伪代码:

git status-tracked-and-untracked
# M file_tracked_changed.txt
# . file_tracked_unchanged.txt
# ?? file_untracked.txt

...但是让我了解所有跟踪文件的状态更为重要,就像上面的伪git status-tracked一样。

git中的任何命令,已经做过类似的事情了吗?

7 个答案:

答案 0 :(得分:7)

谢谢@sdaau。我做了一些更改,以便它运行得更快,并以与git status相同的格式提供结果:

git ls-files | while read -r line;
do
    st=$(git status -s "$line");
    if [ -n "$st" ]; then
        echo "$st";
    else
        echo "   $line";
    fi;
done

答案 1 :(得分:3)

感谢@Andomargit ls-tree提示;这就是它所显示的:

git ls-tree --name-status HEAD
# file_tracked_changed.txt
# file_tracked_unchanged.txt

...但我想要状态:)

好的,这是一个解决方案,同时调用ls-filesstatus,并将它们与bash解析进行交错:

git ls-files -cdmoskt --abbrev=8 | while read -r line; do \
  fn=$(echo "$line" | sed 's/.*\s\(\w\+\)/\1/'); \
  st=$(git status -s "$fn" | printf "%-02s " $(sed 's/\([[:print:]]\+\)\s.*/\1/')); \
  echo "$st- $line"; \
done

如果你在OP示例中运行它,那么你得到:

git ls-files -cdmoskt --abbrev=8 | while read -r line; do fn=$(echo "$line" | sed 's/.*\s\(\w\+\)/\1/'); st=$(git status -s "$fn" | printf "%-02s " $(sed 's/\([[:print:]]\+\)\s.*/\1/')); echo "$st- $line"; done
# ?? - ? file_untracked.txt
# M  - H 100644 52e7a08e 0  file_tracked_changed.txt
#    - H 100644 9daeafb9 0  file_tracked_unchanged.txt

......这基本上就是我想要的。 (如果我有幸将其转换为git别名,我会在此发回。


编辑:此处为git别名(适用于~/.gitconfig):

  ls-fstatus = "! cd $PWD/$GIT_PREFIX; git ls-files -cdmoskt --abbrev=8 | while read -r line; do \
    fn=$(echo \"$line\" | sed \"s/.*\\s\\([[:print:]]\\+\\)/\\1/\"); \
    st=$(git status -s "$fn" | printf \"%-02s \" $(sed \"s/\\([[:print:]]\\+\\)\\s.*/\\1/\")); \
    echo \"$st- $line\"; \
  done "

...所以可以在给定的git repo子目录中调用git ls-fstatus

答案 2 :(得分:2)

@RogerDueck's answer的启发,我制作了一个脚本,每个脚本只执行git ls-filesgit status一次。使用约1700个文件,我的回购速度大约快了15倍,不到2秒。

编辑:添加了一些修复程序和一些单元测试,转移到GitHub:https://github.com/frnhr/git-fullstatus

示例输出:

 M some/file
D  another/file
 D more/files/blahblah
A  this/is/an/added/file/i/think
   an/unchanged_file
   another/unchanged_file

答案 3 :(得分:2)

可在Linux上运行的快速一线软件:

sort -uk 2bi <(git status -s) <(git ls-files | sed 's/^/ . /')

答案 4 :(得分:0)

git status -s | egrep -v '^\?\?'

这会过滤掉以??开头的行,即未跟踪的文件。

答案 5 :(得分:0)

frnhr's answer在macOS上不适合我,因为它具有较旧的bash版本。这在perl中也有类似的想法。代替qsort,它只是合并已经排序的两个列表(末尾被忽略的文件除外)。

#!/usr/bin/env perl

use strict;

# --ignored means something different to ls-files than to status
my @ls_args = grep( ! m/^(-i|--ignored)/, @ARGV );

my @files  = split( /\n/, `git ls-files  @ls_args` );
my @status = split( /\n/, `git status -s @ARGV` );

# merge the two sorted lists
while (@files and @status) {
    $status[0] =~ m/^.. (.*)/;
    my $cmp = $1 cmp $files[0];
    if ($cmp <= 0) {
        print shift @status, "\n";
        if ($cmp == 0) {
            shift @files;
        }
    }
    else {
        print "   ", shift @files, "\n";
    }
}
# print remainder
print map {"   $_\n"} @files;
print map {"$_\n"} @status;

答案 6 :(得分:0)

这是一个版本,其中包含要检查的文件列表,并为传入的每个文件输出某事-修改,未修改('')或忽略('??')。 / p>

SubCode == Holiday

和同一件事的一线git别名:

#!/bin/bash
sorted=$(printf '%s\n' $(realpath --relative-to . "$@") | sort)
for f in $sorted; do
    st=$(git status -s "$f");
    lsf=$(git ls-files "$f");
    if [ -n "$st" ]; then
        echo "$st";
    elif [ -n "$lsf" ]; then
        echo "   $lsf";
    else
        echo "?? $f"
    fi;
done