Подтвердить что ты не робот

Переместить файл и каталог в подкаталог вместе с историей фиксации

Как переместить каталог и файлы в подкаталог вместе с историей фиксации?

Например:

  • Структура исходного каталога: [project]/x/[files & sub-dirs]

  • Структура целевой директории: [project]/x/p/q/[files & sub-dirs]

4b9b3361

Ответ 1

Чтобы добавить к bmargulies comment, полная последовательность:

mkdir -p x/p/q      # make sure the parent directories exist first
git mv x/* x/p/q    # move folder, with history preserved
git commit -m "changed the foldername x into x/p/q"

Попробуйте сначала просмотреть предварительный просмотр перемещения:

git mv -n x/* x/p/q

Wolfgang комментарии:

Если вы используете bash, вы можете избежать проблемы с попыткой переместить папку в себя, используя расширенный глобус, подобный этому (используя shopt встроенный):

shopt -s extglob; git mv !(folder) folder

Капитан Man сообщает в комментариях:

mkdir temp 
git mv x/* temp
mkdir -p x/p/q
git mv temp x/p/q
rmdir temp;

Контекст:

Я нахожусь в Windows с Cygwin.
Я просто понял, что сделал неправильный пример shopt -s extglob, поэтому мой путь может быть не нужен, но я обычно использую zsh вместо bash, и у него не было команды shopt -s extglob (хотя я уверен, что там является альтернативой), поэтому этот подход должен работать через оболочки (подталкивание в вашей оболочке mkdir и rmdir, если оно особенно чуждо)


В качестве альтернативы spanky упоминает в комментариях -k опции git mv:

Продвиньте или переименуйте действия, которые приведут к возникновению ошибки.

git mv -k * target/

Это позволит избежать ошибки "can not move directory into itself".

Ответ 2

Git отлично справляется с отслеживанием контента, даже если он перемещается, поэтому git mv, безусловно, лучший способ, если вы перемещаете файлы, потому что раньше они принадлежали x, но теперь они принадлежат x/p/q, потому что проект развивался таким образом.

Однако иногда есть причина для перемещения файлов в подкаталог на протяжении всей истории проекта. Например, если файлы были помещены где-то по ошибке, и с тех пор было сделано еще несколько коммитов, но прерывистые коммиты даже не имеют смысла с файлами в неправильном месте. Если все это произошло в локальной ветке, мы хотим навести порядок, прежде чем нажимать.

Вопрос гласит "вместе с историей коммитов", что я бы интерпретировал как переписывание истории именно таким образом. Это можно сделать с помощью

git filter-branch --tree-filter "cd x; mkdir -p p/q; mv [files & sub-dirs] p/q" HEAD

Затем файлы появляются в подкаталоге p/q на протяжении всей истории.

Древовидный фильтр хорошо подходит для небольших проектов, его преимущество в том, что команда проста и понятна. Для больших проектов это решение не очень хорошо масштабируется, если производительность имеет значение, подумайте об использовании фильтра индекса, как описано в этом ответе.

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

Ответ 3

Я вижу, что это старый вопрос, но я все еще чувствую себя обязанным ответить С моим текущим решением проблемы, которое я извлек из одного из примеров в git book. Вместо использования неэффективного --tree-filter я перемещаю файлы прямо в индекс с помощью --index-filter.

git filter-branch -f --index-filter 'PATHS='git ls-files -s | sed "s/^<old_location>/<new_location>/"';GIT_INDEX_FILE=$GIT_INDEX_FILE.new; echo -n "$PATHS" | git update-index --index-info && if [ -e "$GIT_INDEX_FILE.new" ]; then mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"; fi' -- --all

это специализация одного из примеров из книги. Я также использовал этот же пример для массового переименования файлов в истории фиксации в одном особом случае. при перемещении файлов в подкаталогах: не забудьте экранировать символ/в путях с помощью символа \, чтобы команда sed работала как положено.

Пример:

Project Directory
                 |-a
                 |  |-a1.txt
                 |  |-b
                 |  |  |-b1.txt

чтобы переместить каталог b в корневой каталог проекта:

git filter-branch -f --index-filter 'PATHS='git ls-files -s | sed "s/a\/b\//b\//"';GIT_INDEX_FILE=$GIT_INDEX_FILE.new; echo -n "$PATHS" | git update-index --index-info && if [ -e "$GIT_INDEX_FILE.new" ]; then mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"; fi' -- --all

Результат:

Project Directory
                 |-a
                 |  |-a1.txt
                 |
                 |-b
                 |  |-b1.txt

Ответ 4

Команда git mv - самый простой способ. Однако, по крайней мере, на моем Linux-ящике мне нужно было указать флаг -k, чтобы избежать получения ошибки, что папка не может быть перемещена в себя. Я смог выполнить действие, используя...

mkdir subdirectory
git mv -k ./* ./subdirectory
# check to make sure everything moved (see below)
git commit

В качестве предупреждения это пропустит все ходы, которые приведут к возникновению ошибки, поэтому вы, вероятно, захотите проверить, что все работает правильно после перемещения и до фиксации.