Как мне манипулировать (выгружать и загружать) индексом Git как текстом? - PullRequest
0 голосов
/ 11 декабря 2018

Я обнаружил, что мне нужно выполнить сложное переписывание истории git.В частности, мне нужно удалить большинство файлов и перебрать несколько оставшихся.Е. g.:

$ pr -m -t <(/bin/tree a) <(/bin/tree b)
a                                   b
├── 5                               ├── renamed-3
├── 6                               └── renamed-4
└── foo                             
    └── bar                         0 directories, 2 files
        ├── 3                       
        ├── 4                       
        └── baz                     
            ├── 1                           
            └── 2                           

3 directories, 6 files

Это легко сделать с помощью git filter-branch --tree-filter.Тем не менее, --tree-filter медленный, с гораздо более быстрой альтернативой в виде --index-filter.

Я попытался выразить желаемые операции через git rm --cached и git mv --cached, но оказалось, чтодовольно некрасивоБыло бы намного проще, если бы я мог манипулировать содержимым индекса в виде текста, используя стандартные инструменты Unix (sed / grep / awk).

Есть ли пара команд Git, которые позволили бы

  • сбросить текущее содержимое индекса Git в стандартный вывод в виде текста в формате некоторый (одна запись в строке, включая полный путь к файлу);
  • прочитать текст в приведенном вышеотформатировать из stdin в индекс Git, полностью заменив его текущее содержимое?

Пример желаемого использования:

git filter-branch --index-filter 'git magic-index-dump | awk "..." | git magic-index-replace'

Ответы [ 2 ]

0 голосов
/ 11 декабря 2018

[Это улучшение ответа Торека , который был отклонен как правка.]

Возможно использовать git ls-files --stage и git update-index --index-info для выгрузки и добавления в индекс, соответственно, в одном и том же текстовом формате.

Формат описан в git-update-index (1) :

mode SP sha1 SP stage TAB path

Этот формат <...> соответствует выводу git ls-files --stage.

Используется поле "stage"представлять конфликтующее слияние в индексе.Если не происходит слияние, оно всегда будет равно 0.

Обратите внимание, что git update-index добавляется только к индексу.Чтобы заменить содержимое индекса, его можно очистить перед обновлением или, скорее, записать в другой файл индекса, чтобы избежать любых видов скачков данных, вызванных чтением и обновлением / удалением одного и того же файла в одном и том же конвейере.

Помещение этого в однострочник будет выглядеть довольно грязно, поэтому мы напишем пользовательскую команду Git git-replace-index:

#!/bin/sh -e

: ${GIT_DIR:="$(git rev-parse --git-dir)"}
: ${GIT_INDEX_FILE:="$GIT_DIR/index"}
GIT_INDEX_NEW="$GIT_INDEX_FILE.new"

GIT_INDEX_FILE="$GIT_INDEX_NEW" git update-index "$@"
rm -f "$GIT_INDEX_FILE"
if [ -e "$GIT_INDEX_NEW" ]; then
    mv "$GIT_INDEX_NEW" "$GIT_INDEX_FILE"   
fi

С этим помощником результирующий конвейер будет иметь вид:

git ls-files --stage | ... | git replace-index --index-info
0 голосов
/ 11 декабря 2018

Использование git ls-files --stage и git update-index --index-info может помочь вам в этом, хотя это немного неловко: удаление файла означает установку его режима на ноль, а переименование файла равно , продублируйте строку (до конца инструкции) при смене названия;затем установите нулевой режим в исходной строке .Смысл помещения новой записи в end заключается в том, что возможно, что ваше новое имя совпадает с именем некоторого существующего файла, который вы планируете удалить - если этого не произойдет, вам не нужнобудьте довольно хитрыми.

Внутри операции ветвления фильтра никогда не должно быть никакого продолжающегося слияния, поэтому все номера ступеней должны быть (и оставаться) равными нулю на протяжении всей операции.

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