Jak najlepiej cofnąć scalanie Git, które usuwa pliki z repozytorium?

13

Wyobraź sobie, że dzieje się tak (i ​​że wszyscy używamy SourceTree):

  1. Wszyscy pracujemy nad pochodzeniem / rozwojem.
  2. Wyjeżdżam na tydzień na wakacje.
  3. Mój współpracownik od kilku dni pracuje lokalnie, nie łącząc źródła / rozwoju z powrotem z lokalnym oddziałem deweloperskim.
  4. Próbuje wykonać push, zostaje poinformowany, że najpierw musi się połączyć, a następnie wykonuje pull.
  5. Dostaje konflikt, uniemożliwiając kontynuowanie automatycznego zatwierdzania po scaleniu.
  6. Zakładając, że Git jest jak SVN, mój współpracownik odrzuca „nowe” pliki w swojej kopii roboczej, a następnie dokonuje scalenia - usuwając te „nowe” pliki z głowy źródła / develop.
  7. Po tej rewizji trwa tygodniowa praca deweloperów.
  8. Wracam z wakacji i dowiaduję się, że brakuje kilku dni mojej pracy.

Wszyscy jesteśmy bardzo nowi w Git (jest to nasz pierwszy projekt, w którym go używamy), ale zrobiłem to, aby to naprawić:

  1. Zmień nazwę „develop” na „develop_old”.
  2. Scal develop_old w nowy oddział „develop_new”.
  3. Zresetuj gałąź develop_new do ostatniego zatwierdzenia przed złym scaleniem.
  4. Cherry wybiera odtąd każde zatwierdzenie, jeden po drugim, ręcznie rozwiązując konflikty.
  5. Wciśnij develop_old i develop_new do źródła.

W tym momencie develop_new jest, mam nadzieję, „dobrą” kopią wszystkich naszych zmian, które zostały ponownie zastosowane w kolejnych tygodniach. Zakładam również, że „odwrotne zatwierdzanie” będzie działało dziwnie podczas scalania, zwłaszcza że na nim opiera się praca na kilka następnych tygodni - a ponieważ scalanie zawiera wiele rzeczy, których chcemy, wraz z rzeczami, których nie robimy ” t.

Mam nadzieję, że to się nigdy więcej nie powtórzy, ale jeśli to się powtórzy, chciałbym wiedzieć o łatwiejszym / lepszym sposobie naprawiania rzeczy. Czy istnieje lepszy sposób na cofnięcie „złego” scalenia, gdy w repozytorium opartym na tym scaleniu wykonano wiele pracy?

Jerzy
źródło
1
Czy możesz zamieścić zrzut ekranu drzewa git (odpowiednio zredagowany) lub wynik swojego ulubionego git logformatu z odpowiednimi adnotacjami o tym, co wydarzyło się przy różnych zatwierdzeniach? (Zredagowałem / dodałem adnotację git log --graph --pretty=oneline --abbrev-commiti stamtąd stamtąd)
1
Jest już dla ciebie za późno, ale złapałyby to testy jednostkowe.
dokładnie
1
@nalply: Nie, jeśli złe scalanie usunęło również testy jednostkowe.
Aaronaught
Wow, to naprawdę podstępny pech.
dokładnie

Odpowiedzi:

6

Jeśli dobrze zrozumiałem, to twoja sytuacja:

    ,-c--c--c--c--M--a--a--X ← develop
o--o--y--y--y--y-´

Po wspólnej historii (o) popełniłeś i popchnąłeś swoją pracę (y). Twój współpracownik (c) pracował nad swoim lokalnym repozytorium i wykonał złe połączenie (M). Następnie mogą pojawić się dodatkowe zatwierdzenia (a) na M.

git reset --hard develop M^2
git branch coworker M^1

Teraz twój wykres wygląda dokładnie tak, jak przed złym scaleniem:

    ,-c--c--c--c ← coworker
o--o--y--y--y--y ← develop

Wykonaj dobre scalenie (G):

git checkout develop
git merge coworker

Wynikające z:

    ,-c--c--c--c-、
o--o--y--y--y--y--G ← develop

Teraz przeszczep dodatkowe zatwierdzenia:

git reset --hard X
git rebase --onto G M develop

To daje końcowy wynik:

    ,-c--c--c--c-、
o--o--y--y--y--y--G--a--a--X ← develop

Należy pamiętać, że może to spowodować więcej konfliktów scalania. Właśnie zmieniłeś historię, tzn. Wszyscy twoi współpracownicy powinni sklonować / zresetować / zmienić bazę na nową historię.

PS: Oczywiście należy wymienić G, Ma Xw twoich poleceń przez odpowiedni popełnić id.

michas
źródło
Wydaje się dość oczywiste w pytaniu, że wszystkie te zatwierdzenia zostały już wypchnięte do wspólnego repozytorium, więc nie sądzę, aby zmiana bazy była dobrym wyborem. Cofanie wszystkich ostatnich zatwierdzeń, a następnie wybieranie cofniętych, nie powodujących konfliktów, na dobre scalenie jest bezpieczniejsze.
Aaronaught
To była część z klonowaniem / resetowaniem / rebase. - Jeśli jest tylko kilku programistów, zalecenie im aktualizacji ich repozytoriów może być prawidłową opcją.
michas,
1

Dobrze, że zastanawiasz się, jak naprawić repozytorium, ale jeśli współpracownik usunął tylko nowe pliki i nie zastąpił wielu aktualizacji, znacznie prostszym podejściem byłoby po prostu przywrócenie usuniętych plików.

Prawdopodobnie zacznę od próby wybrania (do bieżącej głowy) oryginalnych zatwierdzeń, w których dodałeś kod, który teraz zaginął. Jeśli z jakiegoś powodu to nie zadziała, po prostu sprawdź starą wersję z dodanymi plikami i dodaj je ponownie w nowym zatwierdzeniu.

To, co opisujesz, jest właściwie podzbiorem znanego anty-wzorca Git, którego przez całe życie nie pamiętam nazwy - ale jego sedno polega na dokonywaniu jakichkolwiek „ręcznych zmian” podczas scalania Git (tj. Edycji) które w rzeczywistości nie rozwiązują żadnych konfliktów scalania, ale wprowadzają jakieś całkowicie niezwiązane ze sobą zmiany) jest uważane za wyjątkowo złą praktykę, ponieważ są one zasadniczo maskowane przez samo scalanie i łatwo można je przeoczyć w przeglądach kodu lub sesjach debugowania.

Zdecydowanie więc wytłumacz swojemu współpracownikowi, że to była epicka porażka, ale zastanów się nad uderzeniem opaski przed przygotowaniem się do poważnej operacji.

Aaronaught
źródło
Zgadzam się, że jeśli znikną całe pliki, jedną rzeczą, którą możesz zrobić, jest to, że nie martwisz się historią w starych plikach: 1. stwórz nową gałąź z obecnie pomieszanej gałęzi. 2. przełącz się z powrotem do złej gałęzi i utwórz kolejną nową gałąź, która jest gałęzią ratunkową. 3. Z gałęzi ratunkowej wróć do zatwierdzenia przed zatwierdzeniem niepowodzenia. 4. Skopiuj usunięte pliki gdzieś poza git 5. Przejdź do innej nowej gałęzi. 6. Skopiuj nowe wersje usuniętych plików do nowego oddziału i zatwierdź. Jest bardziej skomplikowany sposób na zapisanie historii, którym jest słynny post Linusa T.
Elin
1
W rzeczywistości pokazuje to, jak możesz korzystać z kasy jasonrudolph.com/blog/2009/02/25/... To o wiele ładniejsze.
Elin