Хорошо, давайте начнем с команды git status
из этого:
git status -s --porcelain /some/path | grep -E '^(.M|[MA].|\?\?)' | sed -e 's/^.. //g'
Выходной формат --porcelain
(или --porcelain=v1
) представляет собой вариант формата --short
без цветовой кодировки, который печатает два символа для каждого имени файла, затем пробел, а затем имя файла (возможно, в кавычках) в зависимости от core.quotePath
и символов в имени). -s
производит короткий вывод, но у нас уже есть вывод --porcelain=v1
, поэтому он является избыточным (и, вероятно, должен быть удален).
Если вы находитесь в середине конфликтующего слияния, два символа находятся с каждой "стороны" слияния, т. Е. Имеют больше общего с состоянием слияния в процессе выполнения, чем с чем-либо еще. В этом случае вы можете получить U
записей для любого из двух символов. Это не дублируется с git diff-index
, и, по крайней мере, довольно сложно сделать с git diff-files
; для этого необходимо прочитать записи верхнего уровня в индексе, например, git ls-files --stage
или git diff-files -1
и git diff-files -2
. (Я не экспериментировал с git diff-files -<em>digit</em>
.)
Если мы можем игнорировать этот случай без индекса, то два символа:
- Слева:
HEAD
против индекса, один из A, D, M или R; или незаполненный, или вопросительный знак, оба из которых встречаются только по принуждению символа справа.
- Справа: индекс против рабочего дерева, один из A, D, M, R, пробел или знак вопроса.
(На странице руководства перечислены C
, скопированные как возможные состояния. Это состояние может выходить из внутреннего механизма сравнения Git, но только если вы включили поиск копий и git status
Сама команда не не разрешает поиск копий по умолчанию и - по крайней мере, в настоящее время - не имеет флагов для направления, поэтому состояние C
на самом деле никогда не возникает.)
Пробел появляется, когда файл присутствует в обеих сравниваемых сущностях и одинаков в обеих. Если файл F присутствует как в HEAD
(фиксация), так и в индексе и одинаков в обоих, его левое символьное состояние, например, пустое. Однако, если F появляется в индексе и в рабочем дереве, а его состояние одинаково в обоих, git status
вообще не упоминает об этом, поэтому вы никогда не получите два пробела. Вот почему я говорю, что пробел возникает только при принудительном.
Состояние знака вопроса возникает, когда файл существует в рабочем дереве как неотслеживаемый файл. В этом случае файл по определению не в индексе: неотслеживаемый файл - это файл, который появляется в рабочем дереве, но не в индексе. Таким образом, в этом случае вы получите одну строку, которая читает ?? <em>filename</em>
. Обратите внимание, что в в этом случае, возможно, что именованный файл действительно появляется в HEAD
. Если это так, то должно быть удалено в HEAD
-vs-index. Казалось бы, это может выглядеть так:
D? filename
, что имеет смысл, но вместо этого Git показывает это как:
D filename
?? filename
то есть файл появляется дважды, один раз для его состояния HEAD-vs-index = удалено (что не показывает различий с рабочим деревом), а затем снова для его состояния index-vs-work-tree = неотслеживаемое (которое показывает два знака вопроса).
Теперь давайте перейдем к grep
. Аргумент -E
предоставляет регулярное выражение, соответствующее одной из трех альтернатив, каждая из которых привязана к началу строки, поэтому мы всегда смотрим на два символа git status
. Три варианта выражения:
.M
: все, что указано в состоянии index-vs-work-tree: updated . Первая точка принимает любое состояние HEAD-vs-index.
[MA].
: все, что указано в состоянии HEAD-vs-index изменено или добавлено . Вторая точка принимает любое состояние index-vs-work-tree.
??
: неотслеживаемые файлы.
Я думаю, что это может быть достигнуто, например, с помощью git-diff-index
...
Как документация говорит, это
сравните дерево с рабочим деревом или индексом
Итак, учитывая HEAD
в качестве дерева в левой части сравнения и спецификатор, который говорит, что использует рабочее дерево в качестве правой стороны , выполняется то же сравнение, что и в первой половине git status
. Так
git diff-index --cached HEAD [options]
делает то же самое, что и первая половина git status
, и может получить вам эквивалент буквенных кодов, которые вы увидите слева от git status --short
.
Чтобы получить эквивалент буквенных кодов, которые вы видите на справа половине git status --short
, вы должны сравнить сам индекс (не дерево) с рабочим деревом. Вот что делает команда git diff-files
. Так что здесь вам понадобится:
git diff-files [options]
Итак, при некоторой работе можно получить «тот же» вывод. Мы хотим:
Имена файлов M -статусов в рабочем дереве: git diff-files --name-only --diff-filter=M
.
Имена A или M статусных файлов в индексе: git diff-index --name-only --diff-filter=AM
.
неотслеживаемые файлы. Этого нельзя сделать ни с одной из двух команд git diff-*
, но можно сделать с git ls-files --other --exclude-standard
(вам нужен последний вариант, чтобы он соблюдал обычные правила git-ignore).
Таким образом:
(
git diff-files --name-only --diff-filter=M
git diff-index --name-only --diff-filter=AM
git ls-files --other --exclude-standard
)
как группа из трех команд должна давать вам одинаковые имена файлов. Основная проблема заключается в том, что если файл имеет статус и A
-или- M
-in-index и M
-in-work-tree, и вы выполните эти три команды в последовательности, как показано ниже, вы увидите файл дважды . Вы можете решить эту проблему, завершив последовательность команд с помощью канала до sort -u
:
(...) | sort -u
Обратите внимание, что git status --porcelain
делает , печатает имя файла дважды, если оно имеет D
-in-index и не отслеживается, поэтому, если вы хотите разрешить D
-in-index В данном случае результат sort -u
не всегда будет совпадать, поскольку вместо этого вы увидите файл только один раз . (Опять же, это, вероятно, в любом случае лучше.)