Zrozumieć Gita...

2

Po wielu latach z CVS (Coyote) i SVN (sporo różnych projektów) przyszedł czas na oswojenie Gita.
O ile te pierwsze z czasem okazały się logiczne, o tyle Git po plus/minus miesiącu użytkowania nadal wydaje mi się całkowicie nielogiczny, a biorąc pod uwagę jego popularność wina musi leżeć między klawiaturą a krzesłem. A ponieważ zaczynam go używać prawie co dzień, to czas dopytać o szczegóły zanim się zniechęcę.

Wkręciłem się w pewien open sourcowy projekt hostowany na Google Code. Wbiłem na ten projekt i zrobiłem sobie prywatnego forka. W przeciwieństwie do SVN, Git trzyma informację o tym, że jest to fork i pozwala na synchronizację.

Do obsługi używam TortoiseGit, bo jestem mocno przyzwyczajony do TortoiseSVN.
Przeczytałem od deski do deski ten tutorial ze wspomnianego wcześniej projektu.

Do rzeczy. Generalnie jakoś udaje mi się wysyłać poprawki do swojego repo, część została już wcielona do głównego repo, ale...
Przedstawię w kolejności kroki, które wykonuję, bo tak zrozumiałem tego tutoriala.

  1. zmieniam kod na localu
  2. komituję lokalnie (inaczej się nie da)
  3. używając okna Git Sync...
    3 a) fetch&rebase z oryginalnego repo - ten krok jak dobrze zrozumiałem jest po to, by swoje lokalne poprawki nanieść niejako na najnowszy kod, a nie ten, z którym zacząłem pracę w punkcie 1
    3 b) tutaj Git jedzie od początku stworzenia mojego forka, za każdym razem (wg mnie powinien od ostatniej pobranej rewizji w poprzednim fetchu)
    3 c) niestety, za każdym razem pokazuje te same konflikty w tych samych plikach - co ciekawe, niektórych nigdy nie ruszałem, więc nie ma mowy o lokalnych zmianach!
    3 d) po każdym rozwiązanym konflikcie muszę nacisnąć "commit"
    3 e) po ręcznym rozwiązaniu konfliktów (niedługo będę znał je na pamięć) pora na pulla...
    3 f) push do mojego repo nie przechodzi, każe mi zrobić najpierw pull (po grzyba? przecież tylko ja tam pushuję, więc powinien widzieć, że ostatnia rewizja na repo się nie zmieniła, nie kumam)
    3 g) Git wymusza na mnie kolejnego commita, tym razem w opisie commita wypełnia mi message jako:
    Merge branch 'master' of https://code.google.com/r/maroonedmb-ardupilot
    Conflicts:
    <lista plików>
    No files affected
    3 h) "No files affected" ?! to dlaczego twierdził, że rozwiązałem jakieś konflitky? jedziemy dalej...
    3 i) dopiero w tym punkcie mam możliwość zrobić push by moje zmiany z commita z punktu 2) poszły na repo na google code

Bardzo długi proces jak na prostą zmianę paru plików i wysłanie do repo. W SVN fakt, że nie ma tego fetch&rebase bo repo nie są połączone, ale to są 2 kroki!

Na koniec wiśniówka na torcie. Zobaczcie na tego screena:
user image
Zaznaczyłem wybraną zmianę. Dlaczego za każdym razem są te same z innymi hashami? Z jednej strony to ta sama zmiana, z drugiej inny hash podpowiada, jakoby to były inne commity/pushe.

Przyznaję wprost, że totalnie nie rozumiem tego systemu i stawiam browca w Pozku temu, kto mnie oświeci i ułatwi pracę (czyli brak tych samych konfliktów przy każdej próbie wysłania swoich zmian do repo).

Ugh... damn you Linus!

0

Nie możesz po prostu po lokalnym commicie zrobić pull potem merge, rozwiązać konflikty, kolejny commit i następnie push? Te fetch and rebase jest jakieś podejrzane. Używałem jednak gita tylko trochę bo wydał mi się dziwny i przeniosłem się na hg...

0

Tylko o ile dobrze zrozumiałem, to ten fetch&rebase to taki svn up z oryginalnego repo, by nie robić potem merge tylko pracować jakby na świeżym kodzie. Tak to zrozumiałem i tak zalecali.

Poza tym, te konflikty są również w plikach, których nie zmieniałem. Albo takie bezsensowne jak poniżej.

A tu kolejny zonk Gita, takie to "konflikty" on widzi :| (na 99% EOL były takie same)
user image

0

Fetach and rebase robi takie coś, że najpierw pobiera sobie gałąź origin (czyli z tymi zmianami jakie tam zaszły, fetch) a potem wsadza Twoje zmiany na jej początek (rebase). To w jakiś niezrozumiały dla mnie sposób ma być lepsze niż fetch i merge (czyli pull).

W obu przypadkach następuje łączenie Twojego kodu z kodem "oryginalnym" i jego najnowszą wersją. (Czyli to samo co svn up)

Co do EOL to może jednak je sprawdź jeszcze raz. Na pewno git ma jakiś mechanizm do synchronizacji EOL.

0

Co do EOL to jestem pewien. Z resztą, jakby coś się z EOL skopało, to w całym pliku. A ten konflikt mam za każdym fetch&rebase. Nawet jak potem zakomituję te rzekome konflikty.
Jakiś absurd.

0

Heniek Garncarz, tego linka przyswoiłem przed pierwszym dotknięciem Gita, zdaję się rozumieć różnicę, ale to nie odpowiada na moje kłopoty z pierwszego posta.

0

Dziwne, że nie używają pull requestów czy coś.

0

Kto oni?
I w jaki sposób ma działać taki pull request i jak to miałoby rozwiązać wspomniane anomalie?

0

...a jak masz ustawione eol?

autocrlf = false
safecrlf = true

tak?

Bo ja mam zawsze problemy gdy autocrlf = true...

0

Mam ustawienia domyślne, czyli:
AutoCrlf = true
SafeCrlf = false

1

Mój pierwszy kontakt z DVCS to był Mercurial, a dopiero potem git. Pierwsze 2 tygodnie z mercurialem to była mordęga ( mercurial jest bardziej przyjazny i łatwiejszy do zrozumienia, porównanie wersji jest też lepsze), jednak obecnie unikam CVS jak tylko to możliwe i zawsze wybieram git-a lub hg.

Co do pierwszego rysunku, to co się tam stało musiało wyglądać mniej więcej tak:

  1. nowy kod na nowym branch (nazwijmy ją twoja bo nie widzę oryginalnej nazwy)
  2. nowy branch twoja został posłany do jakiegoś zdalnego prywatnego repozytorium
  3. potem pewnie było git pull origin master - co powoduje fetch (pobranie nowej wersji branch'a master) i natychmiastowy merge do bieżącego branch'a twoja
  4. następnie wykonano rebase, zapewne gałąź twoja została przeszczepiona na szczyt gałęzi master
  5. ściągnięto kod z prywatnego repozytoriom, w ten sposób odzyskano gałąź twoja w oryginalnej postaci, która została przeszczepiona przez rebase, w efekcie pojaiwły się dwie kopie zmian: ta w master po rebase, oraz ta utworzona na początku (twoja)
  6. ponieważ Marooned zobaczył dwa branch'e, a spodziewał się jednego, to powtórzył cały proces kilka razy i w ten sposób pojawiły się repetycje całej historii.

Ogólnie błąd polegał na tym, że zastosowano dwa podejścia do łącznia branchy (z trzech mozliwych), zawsze trzeba się zdecydować na jedno rozwiązanie:

  1. merge - czyli zwykłe łącznie branchy (pojawia się commit z dwoma parentami). Proste zrozumiałe. Wada jest taka, że tworzy się szerokie drzewo historii, więc jeśli jest dużo developerów to repozytorium robi się mało czytelne
  2. rebase - czyli przeszczepianie gotowej gałęzi do głównej gałęzi - trudniejsze w zrozumieniu, ale daje ładną liniową historię, trzeba pamiętać, że mając kilka repozytoriów (np prywatne) można przez przypadek odtworzyć gałąź, która została już dołączona do master
  3. new commit - czyli przejście do master nastepnie pozostając w master checkout nowego kodu (branch-a) i dokonanie nowego commit'u w master. Dostaje się ładną liniową historię, ale nie nadaje się do publikowania dużych zmian (traci się historię drobnych zmian), natomiast dla małych zadań jest to bardzo dobre rozwiązanie, bo ukrywa się commity śmieci (np poprawka literówki).
1

...no to spróbuj:
autocrlf = false
safecrlf = true

u mnie się sprawdza.
A miałem podobne problemy na domyślnych ustawieniach.
Podobne, nie mówię że to to samo, ani że na pewno zmiana ustawień pomoże :-)
Też wariowało przy diffie...

linki(warto przeczytać):
http://stackoverflow.com/questions/4181870/git-on-windows-what-do-the-crlf-settings-mean
http://stackoverflow.com/questions/170961/whats-the-best-crlf-handling-strategy-with-git

1 użytkowników online, w tym zalogowanych: 0, gości: 1