Как переписать историю коммитов?

Создав ветку Y из рабочей ветки X, я удалил некоторые файлы, чтобы уменьшить визуальный шум, не видя эти файлы в FS, пока работал с веткой Y. Эти файлы изменяются в ветке X.

вот сценарий:

A - B [origin/master]
     \
      C - D - G - H [origin/X]
           \
            E - F [Y]

Изменения из ветки Y также переносятся в origin/Y

Уже выставлен PR-запрос ветки Y на рассмотрение.


Как переписать историю коммитов в origin/Y, чтобы вернуть файл?


person overexchange    schedule 21.07.2019    source источник
comment
Возможный дубликат Как восстановить файл, ранее удаленный в git история?   -  person eftshift0    schedule 21.07.2019
comment
@ eftshift0 Филиал Y уже находится в запросе PR при последней фиксации. Этот запрос не отличается от прилагаемого?   -  person overexchange    schedule 21.07.2019
comment
эта часть там не объясняется ... но рецепт возврата файлов остается прежним ... теперь, когда вы получаете исправленную ветку, вы делаете: git push -f origin Y. После того, как вы принудительно нажали ветку, PR должен обновиться на github или bitbucket.   -  person eftshift0    schedule 21.07.2019
comment
@ eftshift0 Я parent of the commit that deleted the file скажу id1. Что такое id of the previous commit на шаге 2 ниже? После id1 у меня удалено несколько файлов   -  person overexchange    schedule 21.07.2019
comment
Родительский идентификатор - это идентификатор, который вы используете для запуска команды git checkout <rev-id> -- <deleted-filepath>.   -  person eftshift0    schedule 21.07.2019


Ответы (2)


На всякий случай дам вам простой рецепт. Предположим, ваша ветка называется A, и вы удалили файлы на A ~ 3 (то есть на 3 версии после A):

git checkout A~3 # we set ourselves on the revision where the files where deleted
git checkout HEAD~1 -- file1 file2 file3 # get back the files from the previous revision
git commit --amend --no-edit # commit new revision with the deleted files back in place
git cherry-pick A~3..A # replay revisions after this new revision
# if you like the results:
git branch -f A # set the branch on this new position
git checkout A
git push -f origin A

Это должно работать

person eftshift0    schedule 21.07.2019
comment
Я вижу, что этот подход более прост ... Поскольку в моем случае один файл удаляется, один файл переименовывается и изменяется. Но это меняет мою историю коммитов. - person overexchange; 21.07.2019
comment
История коммитов изменится ... по крайней мере, содержимое ревизий ... даже если вы сохраните ту же строку ревизий с комментарием / автором, вы переписываете историю. - person eftshift0; 21.07.2019
comment
Итак, я хочу применить этот подход к текущей фиксации. Но разве для этого не потребуется новая фиксация после применения этого подхода, а затем подтолкнуть эти изменения? Потому что у меня есть PR-запрос, который находится в текущей фиксации? - person overexchange; 21.07.2019
comment
Итак, что вы хотите, это создать новую дополнительную ревизию, в которую вы вернете файлы? Конечно, это возможно ... не самый элегантный способ справиться с этим, но возможно ... и, конечно, вам понадобится новый коммит после проверки удаленных файлов. - person eftshift0; 21.07.2019
comment
Создает ли git push -u origin Y какие-либо проблемы после изменений в истории коммитов? потому что история коммитов изменена в локальной ветке Y? - person overexchange; 21.07.2019
comment
Если вы не переписывали историю, а только добавили ревизию, чтобы вернуть файлы? Не должно быть проблем. - person eftshift0; 21.07.2019
comment
Я просто добавлю новую фиксацию (ревизию), чтобы вернуть файлы. Но перед этим, как мне поступить с PR-запросом, который находится в текущем коммите? Этот PR-запрос мешает мне создавать новую фиксацию (ревизию) и подталкивать? - person overexchange; 21.07.2019
comment
github и bitbucket (если вы их используете) будут отражать обновление PR, когда вы нажимаете на ветку, которая использовалась для создания PR. - person eftshift0; 21.07.2019
comment
Находясь в текущей фиксации, после выполнения этого подход, история коммитов меняется. git push может не работать ... Как заставить origin/Y синхронизироваться с локальным Y? - person overexchange; 21.07.2019
comment
что ты имеешь в виду? Если вы не переписывали историю Y, а только добавили ревизию, push не завершится ошибкой. Не получится, если переписать историю. - person eftshift0; 21.07.2019
comment
Моя плохая ... история коммитов не изменилась. git push все прошло нормально - person overexchange; 21.07.2019
comment
Теперь ... могу ли я переустановить родительскую ветку? Поскольку у меня есть файлы после создания новой версии с помощью этого подхода? - person overexchange; 21.07.2019

Как упоминал @ eftshift0 в комментариях, этот ответ может оказаться полезным. Он показывает, что вы можете восстановить потерянный файл и переписать историю git следующим образом:

git rebase -i <id of the commit with the files before they were deleted>
git checkout <id of the commit previous to the one you're currently on> <filename>
git commit --amend
git rebase --continue
git tag -d originalHead

Тем не менее, есть смысл сохранить историю git неизменной, поэтому другой вариант восстановления потерянного файла без изменения истории git можно найти в этом ответе, в котором говорится:

git checkout <id of the commit with the files before they were deleted> <filename>

Кроме того, если вы хотите восстановить несколько файлов, этот ответ показывает несколько способов сделать это, например, запуск git checkout несколько раз.

person AbsoluteSpace    schedule 21.07.2019
comment
previous commit будет фиксацией, предшествующей фиксации, в которой исчезли файлы. Кроме того, если вы хотите восстановить несколько файлов, этот ответ показывает несколько способов сделать это. Я обновлю свой ответ. - person AbsoluteSpace; 21.07.2019
comment
Из каталога, в котором выполняются эти команды, есть два файла, удаленных в подкаталоге dir1. - person overexchange; 21.07.2019
comment
Это также поддерживает новые файлы, созданные в последней фиксации? - person overexchange; 21.07.2019
comment
Должно. Взгляните на git status. - person eftshift0; 21.07.2019
comment
git checkout будет поддерживать новые файлы в последней фиксации, если вы не извлечете файл, который вы изменили в своей текущей ветке. - person AbsoluteSpace; 21.07.2019
comment
В вашем ответе: id of the commit with the files before they were deleted на шаге 1 то же самое, что id of the commit previous to the one without the files на шаге 2? - person overexchange; 21.07.2019
comment
Не обязательно, моя неудачная формулировка. id of the commit with the files before they were deleted - это идентификатор родительского коммита, который удалил файлы, но id of the commit previous to the one without the files - это просто коммит перед тем, над которым вы сейчас работаете. Я обновил сообщение, чтобы сделать шаг 2 более понятным. - person AbsoluteSpace; 21.07.2019
comment
В чем заключается идея оформления заказа на id of commit previous to the one am currently on на шаге 2? почему не коммит, который я сейчас выполняю? - person overexchange; 21.07.2019
comment
вероятно, HEAD будет работать так же хорошо при оформлении заказа ... но я не хотел добавлять немного перца в рецепт, который уже был опробован и протестирован (из того, что вы можете видеть во всех голосах за). - person eftshift0; 21.07.2019
comment
@ eftshift0 Я следую второму подходу, но вижу, что история коммитов меняется - person overexchange; 21.07.2019