使 git status 显示未修改/未更改的跟踪文件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16307091/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Make git status show unmodified/unchanged tracked files?
提问by sdaau
Here is a brief snippet example (which you can paste in your Linux terminal), creating a new git
repository and adding some files to it (using git version 1.7.9.5):
这是一个简短的片段示例(您可以将其粘贴到 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 [email protected]
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"
Now, after the initial commit, I want to change the file_tracked_changed.txt
files, and keep the others (here, only file_tracked_unchanged.txt
) unchanged for the next commit. Below is a snippet which demonstrates that, and the diverse outputs of git status
vs git ls-files
(git
shell output is prefixed with #
):
现在,在初始提交之后,我想更改file_tracked_changed.txt
文件,并file_tracked_unchanged.txt
在下一次提交时保持其他文件(此处,仅)不变。下面是一个片段,它演示了这一点,以及git status
vs的不同输出git ls-files
(git
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
What I'm looking for, is a command which will show all tracked files in a directory (which git ls-files -v
does), with their accurate repository status (which git ls-files
doesn't show, as it shows H
as status for all tracked files). For instance, I'd like to obtain something like the pseudocode:
我正在寻找的是一个命令,它将显示目录中的所有跟踪文件(git ls-files -v
确实如此),以及它们准确的存储库状态(git ls-files
不显示,因为它显示H
为所有跟踪文件的状态)。例如,我想获得类似伪代码的东西:
git status-tracked
# M file_tracked_changed.txt
# . file_tracked_unchanged.txt
... where the dot .
would a symbol indicating a tracked, but unchanged file (if I recall correctly, SVN may use a U
character for these).
...其中点.
是一个符号,表示一个被跟踪但未更改的文件(如果我没记错的话,SVN 可能会使用U
这些字符)。
Ultimately, I'd like to also show the status of all files in a directory, as in the pseudocode:
最后,我还想显示目录中所有文件的状态,如伪代码所示:
git status-tracked-and-untracked
# M file_tracked_changed.txt
# . file_tracked_unchanged.txt
# ?? file_untracked.txt
... but it's more important to me to get to the status of all tracked files, as in the pseudo git status-tracked
above.
...但对我来说更重要的是获取所有跟踪文件的状态,如git status-tracked
上面的伪代码。
Any command in git
, that already does something like this?
中的任何命令git
,已经做了这样的事情?
回答by Roger Dueck
Thanks @sdaau. I've made a few changes so that it runs much faster, and delivers results in the same format as git status
:
谢谢@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
回答by frnhr
Inspired by @RogerDueck's answer, I made a script that executes git ls-files
and git status
only once each. It runs about 15 times faster on my repo with ~ 1700 files, just under 2 sec.
灵感来自@ RogerDueck的答案,我做了一个脚本,执行git ls-files
和git status
只有一次每个。它在我的 repo 上运行大约 15 倍,大约有 1700 个文件,不到 2 秒。
EDIT:Added a number of fixes and some unittests, moved to GitHub: https://github.com/frnhr/git-fullstatus
编辑:添加了一些修复和一些单元测试,移到 GitHub:https: //github.com/frnhr/git-fullstatus
Sample output:
示例输出:
M some/file
D another/file
D more/files/blahblah
A this/is/an/added/file/i/think
an/unchanged_file
another/unchanged_file
回答by sdaau
Thanks to @Andomar, for the git ls-tree
tip; this is what it shows:
感谢@Andomar的git ls-tree
提示;这是它显示的内容:
git ls-tree --name-status HEAD
# file_tracked_changed.txt
# file_tracked_unchanged.txt
... but I want statuses :)
...但我想要状态 :)
OK, here is a solution, calling both ls-files
and status
, and interleaving them with a bit of bash
parsing:
好的,这是一个解决方案,同时调用ls-files
and status
,并通过一些bash
解析将它们交错:
git ls-files -cdmoskt --abbrev=8 | while read -r line; do \
fn=$(echo "$line" | sed 's/.*\s\(\w\+\)//'); \
st=$(git status -s "$fn" | printf "%-02s " $(sed 's/\([[:print:]]\+\)\s.*//')); \
echo "$st- $line"; \
done
If you run this as in the OP example, you get:
如果您像在 OP 示例中那样运行它,您将得到:
git ls-files -cdmoskt --abbrev=8 | while read -r line; do fn=$(echo "$line" | sed 's/.*\s\(\w\+\)//'); st=$(git status -s "$fn" | printf "%-02s " $(sed 's/\([[:print:]]\+\)\s.*//')); echo "$st- $line"; done
# ?? - ? file_untracked.txt
# M - H 100644 52e7a08e 0 file_tracked_changed.txt
# - H 100644 9daeafb9 0 file_tracked_unchanged.txt
... which is basically what I wanted. (I'll post back here if I have luck in converting this into a git
alias).
......这基本上是我想要的。(如果我有幸将其转换为git
别名,我会在这里发帖)。
EDIT: here as git
alias (for ~/.gitconfig
):
编辑:这里作为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 "
... so one can just call git ls-fstatus
in a given git repo subdirectory.
...所以可以只调用git ls-fstatus
给定的 git repo 子目录。
回答by hashstat
Quick one-liner that works on Linux:
适用于 Linux 的快速单线:
sort -uk 2bi <(git status -s) <(git ls-files | sed 's/^/ . /')
sort -uk 2bi <(git status -s) <(git ls-files | sed 's/^/ . /')
回答by GaryO
Here's a version that takes a list of files to check, and outputs somethingfor every file passed in -- modified, unmodified (' '), or ignored ('??').
这是一个需要检查文件列表的版本,并为传入的每个文件输出一些内容——修改、未修改 (' ') 或忽略 ('??')。
#!/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
And a one-liner git alias for the same thing:
还有一个用于同一件事的单行 git 别名:
[alias]
file-status="!f() { 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 }; f"
回答by Mark Gates
frnhr's answerdidn't work for me on macOS, because it has an older version of bash. Here's a similar idea in perl. Instead of qsort, it just merges the two lists, which are already sorted (except ignored files at the end).
frnhr 的回答在 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 = 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;
回答by Andomar
git status -s | egrep -v '^\?\?'
This filters out lines that start with ??
, that is, the untracked files.
这会过滤掉以 开头的行??
,即未跟踪的文件。