2016-01-31 5 views
0

В git, как удалить удаленные файлы и переименовать, начиная с определенной фиксации в ветке, сохраняя при этом историю изменений для каждого файла (удаленных и переименованных)?Как удалить удаления и переименовать из истории?

Мой вариант использования: я взял ветку и начал оттуда новую ветку, где я удалил некоторые файлы и переименовал некоторые другие. Затем я изменил оставшиеся (и часто переименованные) файлы (а также добавил некоторые файлы). Теперь я хочу вернуться к исходным именам и восстановить удаленные файлы (которые все еще существуют на общей базе), сохраняя при этом историю всего. Моя конечная цель - объединить обратно в исходную ветку (так without the renames and file deletions that I introduced).

Можно ли это сделать? Мне интересно, как это легко, тем более что измененные файлы были изменены (поэтому наивное удаление переименований разделило бы ссылку на историю между исходными файлами и изменениями, которые я хочу сохранить)

PS: Изменения так как разветвленная ветвь обширна (по крайней мере, на «очищенной» ветке).

+0

Git не отслеживает историю имен файлов. Это трекер контента; он вычисляет изменения имени файла из дельт во время выполнения. –

+0

"*, так как переименованные файлы были изменены, поэтому наивное удаление переименований разделило бы ссылку на историю между исходными файлами и изменениями *« Это не обязательно так. Git может вычислять переименования даже при модификации файлов. Также, если вы переименуете файлы обратно к их оригинальным именам с помощью обычного фиксации, ваша ветка должна слить. – Schwern

ответ

2

Вам не нужно переписывать историю, чтобы сделать работу слиянием. Вы можете вернуть переименования и повторно ввести удаленные файлы, а затем совершить и слить. Используйте git mv, чтобы переименовать файлы. Удаленные файлы можно восстановить с помощью git checkout <rev-which-deleted-the-file>^ -- <filename>. See this answer for details.

Удаленные и переименованные файлы можно найти, используя git-log's --diff-filter.

Git не сохраняет переименования, он вычисляет их на лету с некоторыми эвристиками, чтобы иметь дело с небольшими изменениями. git-log, git-diff и git-blame у всех есть опции, такие как -C и -M, чтобы контролировать, как сильно Git пытается найти скопированные и переименованные (перемещенные) файлы. Таким образом, непрерывность истории не обязательно теряется переименованиями в отрасли.


Если вы действительно хотите, чтобы переписать историю, сначала найти все изменения, которые Удаление файлов с помощью git log --diff-filter=D master..branch. Затем вы можете использовать git rebase -i для изменения этих коммитов и восстановления удаленного файла.

Rewrites немного сложнее, потому что вам придется отменить переименование, а затем переименовать файл в каждом последующем коммите. Это задание для git-filter-branch, которое может применить одно и то же изменение к серии коммитов.

git filter-branch --tree-filter 'if [ -f new ]; mv new old; fi' master..branch 

--tree-filter запускает команду оболочки на каждой фиксации, а затем изменяет фиксации путем добавления и удаления файлов по мере необходимости.

Как и прежде, для поиска переименований используйте git log --diff-filter=R master..branch.

+0

Спасибо. Я использовал первый метод (без перезаписи истории): 'git mv' и' git checkout ... 'для удаленных файлов. Затем я объединил каждую ветку в другую (и проверил обновления). Тем не менее история файла, получившего много изменений, исчезла из 'git log'. Однако он появляется в запросе на растяжение. Есть ли способ заполучить такую ​​историю? – EOL

+0

@EOL Я не уверен, что вы имеете в виду. Это было бы лучше, как новый вопрос. – Schwern

+0

Для полноты: я переименовал файл из 'master':' git mv old_name.txt new_name.txt', чтобы он совпадал с именем из другого филиала ('production'). После слияния 'production' я не увидел полную историю изменений' new_name.txt', когда я сделал git log new_name.txt'. Теперь я понимаю, что нужно выполнить 'git log --follow new_name.txt', чтобы следить за изменениями переименований и списков. Спасибо за ваш отзыв. :) – EOL

0

Вы можете попробовать сделать git rebase -i для повреждающей ветви, в точке разветвления. Для безопасности я сначала создал новую ветку на кончике ветки, которую вы хотите калечить, на случай (ха-ха! Закон Мерфи неумолимо) что-то пошло не так.

Если изменения очень обширны, есть способы автоматизировать это, но это более важно. Подробности см. На странице Pro git book.

+0

Я считаю, что проблема с 'git rebase -i' заключается в том, что вы отмените переименование в одном коммите, любые коммиты, которые изменили переименованный файл, либо вызовут конфликт, либо вызовут копию файла. – Schwern

+0

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

+0

Спасибо. Изменения _are_, к сожалению, обширные ... – EOL

Смежные вопросы