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