Как упростить команду git-status с помощью diff-фильтра, например, ГИТ-Diff-индекс - PullRequest
0 голосов
/ 25 апреля 2019

Есть ли способ написать следующую команду без grep и без sed?

Я думаю, что это может быть достигнуто, например, с помощью git-diff-index, но я поражен деталями.

Исходная команда:

git status -s --porcelain /some/path | grep -E '^(.M|[MA].|\?\?)' | sed -e 's/^.. //g';

Это эквивалентно этому?

git diff-index --name-only --diff-filter=AM HEAD -- /some/path

1 Ответ

1 голос
/ 25 апреля 2019

Хорошо, давайте начнем с команды 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]

Итак, при некоторой работе можно получить «тот же» вывод. Мы хотим:

  1. Имена файлов M -статусов в рабочем дереве: git diff-files --name-only --diff-filter=M.

  2. Имена A или M статусных файлов в индексе: git diff-index --name-only --diff-filter=AM.

  3. неотслеживаемые файлы. Этого нельзя сделать ни с одной из двух команд 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 не всегда будет совпадать, поскольку вместо этого вы увидите файл только один раз . (Опять же, это, вероятно, в любом случае лучше.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...