2013-09-06 9 views
51

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

Например:

  • Источник структуры каталогов: [project]/x/[files & sub-dirs]

  • Целевая структура каталога: [project]/x/p/q/[files & sub-dirs]

+1

git mv сделаю это. – bmargulies

+0

Я не понимаю большинства ответов на этот вопрос, я пробовал все пути, у меня всегда либо была ошибка, либо просто ничего не происходило, поэтому я просто вырезал папку .git и вставил ее в подпапку ... угадайте, что ? Это сработало! – Ayyash

ответ

37

Чтобы добавить в bmargulies «s 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 

Wolfgangcomments:

If you're using bash, you can avoid the issue of trying to move a folder into itself by using an extended glob like so (using the shopt built-in):

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

Captain Man отчеты in the comments приходится делать:

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

Контекст:

I am on Windows with Cygwin.
I just realized I did the shopt -s extglob example wrong so my way may not have be necessary, but I typically do use zsh instead of bash, and it didn't have the command shopt -s extglob (though I'm sure there is an alternative), so this approach should work across shells (subbing in your shell's mkdir and rmdir if it's especially foreign)


В качестве альтернативы spanky упоминает in the comments-k option of git mv:

Skip move or rename actions which would lead to an error condition.

git mv -k * target/ 

Что бы избежать Ошибка "can not move directory into itself".

+2

Вы не можете переместить 'x' в его подкаталог. 'git mv ...' выполняет эту работу, не нужно «git add ...», если нет дальнейших изменений. – vonbrand

+0

@vonbrand хорошие баллы. Я отредактировал ответ соответственно. – VonC

+0

Как использовать git mv здесь? Он жалуется, что я не могу переместить каталог в его подкаталог. –

34

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 подкаталоге на протяжении всей истории.

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

+7

спасибо, сделан мой день! Я хотел «сменить» все файлы дерева в новый подкаталог и использовал ваш подход с помощью 'mv *./The-subdir', но получил ошибку:« не может переместить-subdir в подкаталог сам по себе. Мое решение используйте 'mv the-subdir/tmp; mv */tmp/the-subdir mv/tmp/the-subdir. /' внутри команды tree-filter. Работает как шарм. – Alexander

+0

Я не мог заставить это работать, если только я 'git mv [files & sub-dirs] p/q' вместо вызова raw' mv'; Запуск на Mac.Но он действительно хорошо работает для меня, так что спасибо! – d4vidi

8

Я вижу, что это старый вопрос, но я все еще чувствую себя обязанным ответить. С моим текущим решением проблемы, которое я получил из одного из примеров в 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 

переместить каталог б корня проекта:

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 
3

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

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

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

+0

Примечание: флаг -k не работает на Mac OS X (Sierra), а также, по-видимому, на Ubuntu. –

+0

@ Dr.JohnnyMohawk В последней версии XCode его доступный .. – Stephen