Cofanie błędnego merge’a w git-svn

Kolejny wpis oparty na ostatnich doświadczeniach z pracy. Tym razem dość klasycznie: stworzyłem w swoim repozytorium git feature brancha na podstawie brancha testing zamiast mastera. Do testing – jak łatwo się domyślić – domerdżowuję feature branche przed przekazaniem ich do testów, w związku z tym jest tam zawsze co najmniej kilka modyfikacji czekających na przetestowanie.

Niestety, zorientowałem się o tym dopiero po merge’u ww. feature brancha do mastera oraz wykonaniu git svn dcommit  (korzystam z git-svn), więc całość została nie tylko u mnie, ale też poszła do SVN-a. Sam git reset do commita sprzed merge’owania niewiele pomógł, ponieważ każdy git svn rebase i tak wracał do pierwotnego ustawienia HEAD.

Na początek, żeby pozbyć się nieprzetestowanych zmian z repozytorium SVN-a, wygenerowałem odwrotnego diffa:

git diff --no-prefix HEAD HEAD~1 > ~/revert.diff

I spatchowałem kod w masterze:

patch -p0 < ~/revert.diff

Po czym dodałem i scommitowałem zmiany w masterze oraz wypchnąłem je do SVN-a przez:

git svn dcommit

(można to było zrobić poprzez git reset lub git revert, jednak to był sposób, z którego mogłem skorzystać bez przeglądania dokumentacji, a ciągle istniało ryzyko, że ktoś ten kod w międzyczasie pobierze)

Mając stan SVN-a sprzed błędnego merge’a, przeszedłem do wertowania internetu.

Rozwiązaniem okazało się cofnięcie HEAD w gicie do ostatniego commita sprzed merge’a:

git reset --hard commit_hash

A następnie wykonanie tego samego dla SVN-owego remote’a. W tym celu należy użyć

git svn reset -r svn_revision_id

gdzie svn_revision_id  to ID ostatniej rewizji SVN sprzed błędnego merge’a.

Dzięki temu zarówno repozytorium git, jak i lokalny remote wskazują na stan sprzed merge’a. Wykonanie:

git svn rebase

pobierze więc kolejne commity z SVN na nowo i nie będzie przestawiało HEAD-a w niepożądane miejsce.

Z racji tego, że mój feature branch posiadał błędnego rodzica, do przeniesienia zmian na mastera skorzystałem z cherry-pick:

git cherry-pick commit_hash