Восстановить ранее удаленный код (не обязательно один или весь файл) в git

Некоторое время назад я удалил функцию класса a из своего кода и зафиксировал удаление. Эта функция была реализована как отдельный класс со спецификацией в стиле BDD, а несколько других классов были изменены в фиксации удаления, поскольку они использовали эту функцию. Коммит чистый, в том смысле, что единственное изменение в коммите — это удаление этой единственной функции.

Теперь я передумал и решил, что хочу вернуть эту функцию, только поскольку я удалил ее, я внес целую кучу изменений. (Я знал, что это возможно, но не сохранил копию, потому что знал, что могу вытащить ее из-под контроля версий). Я нашел фиксацию: cb2a6b1 и вижу удаленные строки, когда я: git show cb2a6b1. Вопрос в том, как я могу теперь применить эти строки обратно в свой код?

git diff cb2a6b1 cb2a6b1~1 создает diff, который переформулирует удаление как добавление, но это не будет git apply, главным образом потому, что изменились номера строк. Я могу просто вручную поместить материал обратно с некоторым ручным редактированием текста, но есть ли более автоматическая альтернатива?


person Ollie Saunders    schedule 21.11.2009    source источник


Ответы (2)


Попробуйте git revert cb2a6b1.

Если он не может автоматически понять, что нужно делать, он должен предоставить вам конфликты слияния, которые вы можете исправить вручную.

person Phil    schedule 21.11.2009

Другой вариант — git rebase -i. Это сложнее, чем git revert, но у вас также больше возможностей.

Допустим, у вас есть репозиторий git, который содержит только файл README:

$ cat README
This is line alpha.
Line Beta.
Line Gamma.

Затем вы удаляете бета-версию строки и фиксируете свое изменение:

(make changes)
$ git commit -am 'removed beta'

Теперь вы добавляете еще несколько строк, коммитя по пути:

(make changes)
$git commit -am 'added delta'
(make changes)
$git commit -am 'added epsilon'

Теперь наш файл README и журнал git выглядят так:

$ cat README
This is line alpha.
Line Gamma.
Line Delta.
Line Epsilon.
$ git log --pretty=oneline
56ae2db58905607270434045b2a7218237d3716e added epsilon
058ec4b92fb279370f6e5b81c4aebb6250f93c6b added delta
19801b380956b60f36b4922796ea86935a75e569 removed beta
bc9057cebf05352eb5596eaf753708a14de589d2 initial commit

Теперь мы решаем, что нам не стоило удалять бета-строку. git rebase на помощь! Всякий раз, когда я делаю какое-либо перемещение, мне нравится использовать временную ветку, так как я меняю историю.

$ git checkout -b fixingthings

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

$ git rebase -i bc9057c

Теперь вы увидите это в своем редакторе:

pick 19801b3 removed beta
pick 058ec4b added delta
pick 56ae2db added epsilon

# Rebase bc9057c..56ae2db onto bc9057c
#
# Commands:
#  p, pick = use commit
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

Комментарии внизу полезны. Просто удалите строку с фиксацией, от которой хотите избавиться, сохраните и закройте, а git позаботится обо всем остальном. Теперь ваш README выглядит так:

$ cat README
This is line alpha.
Line Beta.
Line Gamma.
Line Delta.
Line Epsilon.

Это как волшебство!

Если хотите, вы можете сейчас слиться со своей главной веткой и удалить временную ветку.

$ git checkout master
Switched to branch "master"
$ git merge fixingthings
Auto-merging README
Merge made by recursive.
$ git branch -d fixed
Deleted branch fixingthings (was 1247141).

Что делает git rebase, так это рассматривает каждую фиксацию как патч и воспроизводит их по порядку (или нет, как вы скажете). Это означает, что у вас могут быть конфликты слияния. Если это произойдет с вами, rebase приостановится, и вы разрешите конфликты. Существует множество руководств о том, что делать в такой ситуации. Этот мне понравился.

person Neall    schedule 22.11.2009