Od jakiegoś czasu używam subversion do moich osobistych projektów.
Coraz częściej słyszę wspaniałe rzeczy o Git i Mercurial oraz ogólnie o DVCS.
Chciałbym dać wir całej DVCS, ale nie znam zbyt dobrze żadnej z tych opcji.
Jakie są różnice między Mercurial a Git?
Uwaga: nie próbuję dowiedzieć się, który jest „najlepszy”, a nawet od którego powinienem zacząć. Głównie szukam kluczowych obszarów, w których są one podobne i gdzie są różne, ponieważ jestem zainteresowany, aby wiedzieć, jak różnią się one pod względem wdrażania i filozofii.
Odpowiedzi:
Oświadczenie: Używam Gita, śledzę rozwój Gita na liście mailingowej git, a nawet wnoszę trochę wkładu do Git (głównie gitweb). Znam Mercurial z dokumentacji i niektórych z dyskusji na kanale IRC #revctrl na FreeNode.
Podziękowania dla wszystkich osób na kanale IRC #mercurial, którzy udzielili pomocy na temat Mercurial dla tego zapisu
Podsumowanie
Byłoby miło mieć trochę składni dla tabeli, coś jak w rozszerzeniu Markdown PHPMarkdown / MultiMarkdown / Maruku
.hgtags
pliku ze specjalnymi regułami dla tagów dla poszczególnych repozytoriów, a także obsługuje tagi lokalne w.hg/localtags
; w Git znaczniki znajdują się wrefs/tags/
przestrzeni nazw, a domyślnie są automatycznie pobierane podczas pobierania i wymagają jawnego wypychania.Istnieje kilka rzeczy, które różnią się Mercurial od Git, ale są też inne rzeczy, które czynią je podobnymi. Oba projekty pożyczają od siebie pomysły. Na przykład
hg bisect
polecenie w Mercurial (wcześniej rozszerzenie dwusieczne ) zostało zainspirowanegit bisect
poleceniem w Git, a pomysłgit bundle
zainspirowany przezhg bundle
.Struktura repozytorium, przechowywanie poprawek
W Git istnieją cztery typy obiektów w bazie danych obiektów: obiekty obiektów blob zawierające zawartość pliku, hierarchiczne obiekty drzewa przechowujące strukturę katalogów, w tym nazwy plików i odpowiednie części uprawnień do plików (uprawnienia do plików, będące dowiązaniem symbolicznym) , obiekt zatwierdzenia, który zawiera informacje o autorstwie, wskaźnik do migawki stanu repozytorium przy rewizji reprezentowanej przez zatwierdzenie (poprzez obiekt drzewa z górnego katalogu projektu) i odniesienia do zerowych lub większej liczby zatwierdzeń nadrzędnych, oraz oznaczenie obiektów, które odwołują się do innych obiektów i mogą być podpisane przy użyciu PGP / GPG.
Git wykorzystuje dwa sposoby przechowywania obiektów: format luźny , w którym każdy obiekt jest przechowywany w osobnym pliku (pliki te są zapisywane raz, ale nigdy nie modyfikowane) oraz format spakowany , w którym wiele obiektów jest przechowywanych w kompresji delta w jednym pliku. Atomowość operacji polega na tym, że po zapisaniu obiektu zapisywane jest odwołanie do nowego obiektu (atomowo, przy użyciu sztuczki create + rename).
Repozytoria Git wymagają okresowej konserwacji
git gc
(w celu zmniejszenia miejsca na dysku i poprawy wydajności), choć obecnie Git robi to automatycznie. (Ta metoda zapewnia lepszą kompresję repozytoriów).Mercurial (o ile rozumiem) przechowuje historię pliku w pliku dziennika (razem, jak sądzę, z dodatkowymi metadanymi, takimi jak śledzenie nazw i niektóre informacje pomocnicze); używa płaskiej struktury o nazwie manifest do przechowywania struktury katalogów oraz struktury o nazwie dziennik zmian, który przechowuje informacje o zestawach zmian (wersjach), w tym komunikat zatwierdzenia i zero, jednego lub dwóch rodziców.
Mercurial używa dziennika transakcji, aby zapewnić atomowość operacji, i polega na obcinaniu plików do czyszczenia po nieudanej lub przerwanej operacji. Dzienniki są tylko dołączane.
Patrząc na strukturę repozytorium w Git kontra w Mercurial, widać, że Git bardziej przypomina obiektową bazę danych (lub system plików o treści), a Mercurial bardziej przypomina tradycyjną relacyjną bazę danych o stałym polu.
Różnice: w
Git obiekty drzewa tworzą hierarchiczną strukturę; w pliku manifestu Mercurial jest struktura płaska . W obiekcie obiektów blob Git przechowuj jedną wersję zawartości pliku; w Mercurial filelog przechowuje całą historię pojedynczego pliku (jeśli nie uwzględnimy tutaj żadnych komplikacji przy zmianie nazw). Oznacza to, że istnieją różne obszary operacji, w których Git byłby szybszy niż Mercurial, wszystkie inne rzeczy uważane za równe (jak scalenia lub pokazywanie historii projektu) oraz obszary, w których Mercurial byłby szybszy niż Git (jak nakładanie łatek lub pokazywanie historia pojedynczego pliku).Ten problem może nie być ważny dla użytkownika końcowego.
Ze względu na ustaloną strukturę struktury dziennika zmian Mercurial , zatwierdzenia w Mercurial mogą mieć maksymalnie dwóch rodziców ; zatwierdzenia w Git mogą mieć więcej niż dwoje rodziców (tzw. „scalenie ośmiornicy”). Chociaż (teoretycznie) można zastąpić scalanie ośmiornicy serią scalania dwóch rodziców, może to powodować komplikacje podczas konwersji między repozytoriami Mercurial i Git.
O ile mi wiadomo, Mercurial nie ma odpowiednika tagów (obiektów tagów) z Git. Szczególnym przypadkiem tagów z adnotacjami są tagi podpisane (z podpisem PGP / GPG); ekwiwalent w Mercurial można wykonać za pomocą GpgExtension , którego rozszerzenie jest dystrybuowane wraz z Mercurial. Nie możesz oznaczyć obiektu niezatwierdzonego w Mercurial, tak jak w Git, ale myślę, że nie jest to bardzo ważne (niektóre repozytoria git używają otagowanego obiektu blob do dystrybucji publicznego klucza PGP do weryfikacji podpisanych znaczników).
Referencje: gałęzie i tagi
W Git referencje (gałęzie, gałęzie i tagi zdalnego śledzenia) znajdują się poza DAG zatwierdzeń (tak jak powinny). Odniesienia w
refs/heads/
przestrzeni nazw ( oddziały lokalne ) wskazują na zatwierdzenia i są zwykle aktualizowane przez „git commit”; wskazują na wierzchołek (głowę) gałęzi, dlatego taka nazwa. Odwołania wrefs/remotes/<remotename>/
przestrzeni nazw ( gałęzie zdalnego śledzenia ) wskazują na zatwierdzenie, śledzenie gałęzi w zdalnym repozytorium<remotename>
i są aktualizowane przez „git fetch” lub równoważny. Odniesienia wrefs/tags/
przestrzeni nazw ( znaczniki ) zwykle wskazują na zatwierdzenia (lekkie znaczniki) lub obiekty znaczników (znaczniki z przypisami i podpisami) i nie mają na celu zmiany.Tagi
W Mercurial możesz nadać trwałą nazwę poprawce za pomocą znacznika ; tagi są przechowywane podobnie do wzorców ignorowania. Oznacza to, że globalnie widoczne znaczniki są przechowywane w
.hgtags
pliku kontrolowanym w repozytorium. Ma to dwie konsekwencje: po pierwsze, Mercurial musi zastosować specjalne reguły dla tego pliku, aby uzyskać aktualną listę wszystkich tagów i zaktualizować taki plik (np. Czyta ostatnio zatwierdzoną wersję pliku, aktualnie nie sprawdzoną wersję); po drugie, musisz zatwierdzić zmiany w tym pliku, aby nowy znacznik był widoczny dla innych użytkowników / innych repozytoriów (o ile rozumiem).Mercurial obsługuje również tagi lokalne , przechowywane w
hg/localtags
, które nie są widoczne dla innych (i oczywiście nie można ich przenosić)W Git znaczniki są ustalone (stałe) nazwane odniesienia do innych obiektów (zwykle znaczników obiektów, które z kolei wskazują na zatwierdzenia) przechowywane w
refs/tags/
przestrzeni nazw. Domyślnie, podczas pobierania lub wypychania zestawu wersji, git automatycznie pobiera lub wypycha tagi, które wskazują, że wersje są pobierane lub wypychane. Niemniej jednak możesz w pewnym stopniu kontrolować, które tagi są pobierane lub wypychane.Git traktuje nieznacznie znaczniki lekkie (wskazujące bezpośrednio na zatwierdzenia) i znaczniki z komentarzami (wskazujące na obiekty znaczników, które zawierają komunikat znacznika, który opcjonalnie zawiera podpis PGP, który z kolei wskazuje na zatwierdzenie) nieco inaczej, na przykład domyślnie bierze pod uwagę tylko znaczniki z przypisami zatwierdza przy użyciu „git opisz”.
Git nie ma ścisłego odpowiednika lokalnych tagów w Mercurial. Niemniej jednak najlepsze praktyki git zalecają utworzenie oddzielnego publicznego nagiego repozytorium, w którym wprowadzasz gotowe zmiany i z którego inni klonują i pobierają. Oznacza to, że tagi (i gałęzie), których nie wypychasz, są prywatne w twoim repozytorium. Z drugiej strony można również używać nazw innych niż
heads
,remotes
lubtags
, na przykładlocal-tags
dla lokalnych tagów.Osobista opinia: Moim zdaniem tagi powinny znajdować się poza wykresem zmian, ponieważ są do niego zewnętrzne (są wskaźnikami do wykresu zmian). Tagi nie powinny mieć wersji, ale można je przenosić. Wybór Mercuriala polegający na użyciu mechanizmu podobnego do mechanizmu ignorowania plików oznacza, że albo musi on traktować
.hgtags
specjalnie (plik w drzewie można przenosić, ale zwykły jest wersjonowany), lub mieć tagi tylko lokalne (.hg/localtags
nie jest wersjonowany, ale nieprzenoszalne).Gałęzie
W Git oddział lokalny (wierzchołek gałęzi lub głowa oddziału) to nazwane odniesienie do zatwierdzenia, w którym można rozwijać nowe zatwierdzenia. Rozgałęzienie może również oznaczać aktywną linię rozwoju, tj. Wszystkie zobowiązania dostępne z wierzchołka gałęzi. Lokalne oddziały znajdują się w
refs/heads/
przestrzeni nazw, więc np. Pełna nazwa oddziału „master” to „refs / heads / master”.Bieżąca gałąź w Git (czyli gałąź wyewidencjonowana i gałąź, do której pójdzie nowy zatwierdzenie) to gałąź, do której odwołuje się HEAD ref. HEAD może wskazywać bezpośrednio na zatwierdzenie, a nie symboliczne odniesienie; ta sytuacja bycia w anonimowej gałęzi bez nazwy nazywana jest odłączonym HEAD („gałąź git” pokazuje, że jesteś w „(bez gałęzi)”).
W Mercurial istnieją anonimowe gałęzie (głowy oddziałów) i można korzystać z zakładek (poprzez rozszerzenie zakładek ). Takie oddziały zakładek są czysto lokalne, a nazw tych (do wersji 1.6) nie można przenieść za pomocą Mercurial. Możesz użyć rsync lub scp, aby skopiować
.hg/bookmarks
plik do zdalnego repozytorium. Możesz także użyć,hg id -r <bookmark> <url>
aby uzyskać identyfikator zmiany bieżącej końcówki zakładki.Ponieważ 1.6 zakładek można popychać / wyciągać. Strona BookmarksExtension zawiera sekcję dotyczącą pracy ze zdalnymi repozytoriami . Różnica polega na tym, że w Mercurial nazwy zakładek są globalne , podczas gdy definicja „zdalnego” w Git opisuje także mapowanie nazw oddziałów z nazw w zdalnym repozytorium na nazwy lokalnych oddziałów zdalnego śledzenia; na przykład
refs/heads/*:refs/remotes/origin/*
mapowanie oznacza, że można znaleźć stan gałęzi „master” („refs / heads / master”) w zdalnym repozytorium w gałęzi zdalnego śledzenia „origin / master” („refs / remotes / origin / master”).Mercurial ma również tak zwane gałęzie nazwane , w których nazwa gałęzi jest osadzona w zatwierdzeniu (w zestawie zmian). Taka nazwa jest globalna (przesyłana przy pobieraniu). Te nazwy oddziałów są trwale rejestrowane jako część metadanych zestawu zmian. Dzięki nowoczesnemu Mercurial możesz zamknąć „nazwaną gałąź” i zatrzymać rejestrowanie nazwy gałęzi. W tym mechanizmie wierzchołki gałęzi są obliczane na bieżąco.
„Nazwane gałęzie” Mercuriala powinny być, moim zdaniem, nazwane etykietami zatwierdzeń , ponieważ takie są. Są sytuacje, w których „nazwany oddział” może mieć wiele wskazówek (wiele bezdzietnych zatwierdzeń), a także może składać się z kilku rozłącznych części wykresu poprawek.
W Git nie ma odpowiednika tych „wbudowanych gałęzi” Mercurial; ponadto filozofia Gita mówi, że chociaż można powiedzieć, że gałąź zawiera pewne zatwierdzenie, nie oznacza to, że zatwierdzenie należy do jakiejś gałęzi.
Należy zauważyć, że dokumentacja Mercurial nadal proponuje używanie oddzielnych klonów (oddzielnych repozytoriów) przynajmniej dla gałęzi długowiecznych (przepływ pracy pojedynczej gałęzi na repozytorium), czyli rozgałęziania przez klonowanie .
Oddziały w pchaniu
Mercurial domyślnie popycha wszystkie głowy . Jeśli chcesz wypchnąć pojedynczą gałąź ( pojedynczą głowicę ), musisz określić wersję końcówki gałęzi, którą chcesz wypchnąć. Można określić końcówkę oddziału według numeru wersji (lokalna do repozytorium), identyfikatora rewizji, nazwy zakładki (lokalna do repozytorium, nie można przenieść) lub według wbudowanej nazwy gałęzi (nazwana gałąź).
O ile rozumiem, jeśli prześlesz zakres rewizji, które zawierają zatwierdzenia oznaczone jako znajdujące się w „nazwanej gałęzi” w języku Mercurial, będziesz miał tę „nazwaną gałąź” w repozytorium, do którego wypychasz. Oznacza to, że nazwy takich osadzonych gałęzi („nazwane gałęzie”) są globalne (w odniesieniu do klonów danego repozytorium / projektu).
Domyślnie (zależnie od
push.default
zmiennej konfiguracyjnej) „git push” lub „git push < remote >” Git wypycha pasujące gałęzie , tj. Tylko te lokalne gałęzie, których odpowiednik jest już obecny w zdalnym repozytorium, do którego wpychasz. Możesz użyć--all
opcji git-push („git push --all”) do wypchnięcia wszystkich gałęzi , możesz użyć „git push < remote > < gałąź >” do wypchnięcia danej gałęzi i możesz użyć „git push < remote > HEAD ”, aby przesunąć bieżącą gałąź .Wszystkie powyższe założenia zakładają, że Git nie jest skonfigurowany, które gałęzie mają przesyłać za pośrednictwem
remote.<remotename>.push
zmiennych konfiguracyjnych.Oddziały w pobieraniu
Uwaga: tutaj używam terminologii Git, gdzie „pobieranie” oznacza pobieranie zmian ze zdalnego repozytorium bez integracji tych zmian z pracą lokalną. To właśnie robi „
git fetch
” i „hg pull
”.Jeśli dobrze to rozumiem, domyślnie Mercurial pobiera wszystkie głowy ze zdalnego repozytorium, ale możesz określić gałąź do pobrania za pomocą „
hg pull --rev <rev> <url>
” lub „hg pull <url>#<rev>
”, aby uzyskać pojedynczą gałąź . Możesz określić <rev> za pomocą identyfikatora wersji, nazwy „nazwanej gałęzi” (gałąź osadzona w dzienniku zmian) lub nazwy zakładki. Jednak nazwa zakładki (przynajmniej obecnie) nie jest przenoszona. Wszystkie otrzymane wersje „nazwanych oddziałów” należą do przeniesienia. „Hg pull” przechowuje końcówki gałęzi, które ściągnął jako anonimowe, nienazwane głowy.Domyślnie w Git (dla 'origin' remote utworzony przez „git clone” i dla pilotów utworzonych przy pomocy „git remote add”) „
git fetch
” (lub „git fetch <remote>
”) pobiera wszystkie gałęzie ze zdalnego repozytorium (zrefs/heads/
przestrzeni nazw) i przechowuje je wrefs/remotes/
przestrzeń nazw. Oznacza to na przykład, że gałąź o nazwie „master” (pełna nazwa: „refs / heads / master”) w zdalnym „origin” zostanie zapisana (zapisana) jako gałąź zdalnego śledzenia „origin / master” (pełna nazwa: „refs / piloty / pochodzenie / master ”).Możesz pobrać pojedynczą gałąź w Git za pomocą
git fetch <remote> <branch>
- Git przechowuje żądane gałęzie w FETCH_HEAD, co jest podobne do nienazwanych głów Mercurial.Są to tylko przykłady domyślnych przypadków potężnej składni refitec Git: za pomocą refspecs możesz określić i / lub skonfigurować, które gałęzie chcesz pobrać i gdzie je przechowywać. Na przykład domyślna wielkość liter „pobierz wszystkie gałęzie” jest reprezentowana przez „+ refs / heads / *: refs / remotes / origin / *” wildcard refspec, a „pobierz pojedynczą gałąź” to skrót od „refs / heads / <branch>:” . Specspecs są używane do mapowania nazw gałęzi (refs) w zdalnym repozytorium na lokalne nazwy refs. Ale nie musisz (dużo) wiedzieć o refspecs, aby móc efektywnie współpracować z Gitem (głównie dzięki poleceniu „git remote”).
Osobista opinia: osobiście uważam, że „nazwane gałęzie” (z nazwami gałęzi osadzonymi w metadanych zestawu zmian) w Mercurial są błędnym projektem z jego globalną przestrzenią nazw, szczególnie dla rozproszonego systemu kontroli wersji. Weźmy na przykład przypadek, w którym zarówno Alice, jak i Bob „nazwali gałąź” w swoich repozytoriach nazwaną „for-joe”, gałęzie, które nie mają nic wspólnego. Jednak w repozytorium Joe te dwie gałęzie byłyby traktowane jak jedna gałąź. Więc wymyśliłeś jakąś konwencję chroniącą przed konfliktami nazw oddziałów. Nie jest to problem z Gitem, gdzie w repozytorium Joe gałąź „for-joe” od Alice to „alice / for-joe”, a od Boba to „bob / for-joe”.
„Oddziałom zakładek” Mercurial obecnie brakuje wewnętrznego mechanizmu dystrybucji.
Różnice:
Obszar ten jest jedną z głównych różnic między Mercurialem a Gitem, jak powiedzieli James Woodyatt i Steve Losh w swoich odpowiedziach. Mercurial domyślnie stosuje anonimowe lekkie linie kodowe, które w swojej terminologii nazywane są „główkami”. Git używa lekkich nazwanych gałęzi z iniekcyjnym mapowaniem do mapowania nazw gałęzi w zdalnym repozytorium na nazwy gałęzi zdalnego śledzenia. Git „zmusza” cię do nazywania gałęzi (no, z wyjątkiem pojedynczej gałęzi bez nazwy, sytuacja nazywana odłączoną HEAD), ale myślę, że działa to lepiej w przypadku przepływów pracy obciążających gałęzie, takich jak przepływ pracy gałęzi tematu, co oznacza wiele gałęzi w paradygmacie pojedynczego repozytorium.
Zmiany w nazewnictwie
W Git istnieje wiele sposobów nazywania rewizji (opisanych np. W git rev-parse man page):
^
parametru rewizji oznacza pierwszego rodzica obiektu zatwierdzenia,^n
oznacza n-tego rodzica zatwierdzenia scalania. Przyrostek~n
parametru rewizji oznacza n-tego przodka zatwierdzenia w prostej linii pierwszego-rodzica. Sufiksy te można łączyć, aby utworzyć specyfikator wersji po ścieżce z symbolicznego odwołania, np. „Pu ~ 3 ^ 2 ~ 3”Istnieją również specyfikatory wersji obejmujące reflog, nie wymienione tutaj. W Git każdy obiekt, czy to zatwierdzenie, znacznik, drzewo czy obiekt blob, ma swój identyfikator SHA-1; istnieje specjalna składnia, np. „next: Documentation” lub „next: README”, która odnosi się do drzewa (katalogu) lub obiektu blob (zawartości pliku) przy określonej wersji.
Mercurial ma także wiele sposobów nazywania zestawów zmian (opisanych np. Na stronie hg ):
Różnice
Jak widać, porównując powyższe listy, Mercurial oferuje numery wersji lokalnych do repozytorium, podczas gdy Git nie. Z drugiej strony Mercurial oferuje przesunięcia względne tylko z „tip” (bieżąca gałąź), które są lokalne dla repozytorium (przynajmniej bez ParentrevspecExtension ), podczas gdy Git pozwala określić dowolne zatwierdzenie wynikające z dowolnej końcówki.
Najnowsza wersja nosi nazwę HEAD w Git, a „tip” w Mercurial; w Git nie ma wersji zerowej. Zarówno Mercurial, jak i Git mogą mieć wiele katalogów głównych (może mieć więcej niż jedno zatwierdzenie bez rodzica; zwykle jest to wynikiem dołączenia wcześniej oddzielnych projektów).
Zobacz także: Wiele różnych rodzajów specyfikatorów wersji na blogu Elijaha (newren's).
Osobista opinia: Myślę, że numery wersji są przereklamowane (przynajmniej dla rozproszonego rozwoju i / lub nieliniowej / rozgałęzionej historii). Po pierwsze, w przypadku rozproszonego systemu kontroli wersji muszą być albo lokalne dla repozytorium, albo wymagać specjalnego traktowania niektórych repozytoriów jako centralnego urzędu numeracji. Po drugie, większe projekty, z dłuższą historią, mogą mieć liczbę poprawek w zakresie 5 cyfr, więc oferują tylko niewielką przewagę nad skróconymi do 6-7 znaków identyfikatorami poprawek i implikują ścisłe porządkowanie, podczas gdy poprawki są tylko częściowo zamawiane (mam na myśli, że wersje n i n + 1 nie muszą być rodzicem ani dzieckiem).
Zakresy zmian
W wersji Git zakresy są topologiczne . Powszechnie postrzegana
A..B
składnia, która dla historii liniowej oznacza zakres rewizji rozpoczynający się od A (ale z wyłączeniem A) i kończący się na B (tj. Zakres jest otwarty od dołu ), jest skrótem („cukier syntaktyczny”), dla^A B
którego dla poleceń przejścia historii oznacza wszystko zatwierdzenia osiągalne z B, wyłączając te osiągalne z A. Oznacza to, że zachowanieA..B
zakresu jest całkowicie przewidywalne (i całkiem przydatne), nawet jeśli A nie jest przodkiem B:A..B
oznacza wtedy zakres poprawek od wspólnego przodka A i B (podstawa scalenia ) do wersji B.W wersji Mercurial zakresy zmian oparte są na zakresie numerów wersji . Zakres jest określany za pomocą
A:B
składni i w przeciwieństwie do zakresu Git działa jako przedział zamknięty . Również zakres B: A jest zakresem A: B w odwrotnej kolejności, co nie ma miejsca w Git (ale patrz poniższa uwaga na tematA...B
składni). Ale taka prostota wiąże się z ceną: zakres zmian A: B ma sens tylko wtedy, gdy A jest przodkiem B lub odwrotnie, tj. Z historią liniową; w przeciwnym razie (tak sądzę) zakres jest nieprzewidywalny, a wynik jest lokalny dla repozytorium (ponieważ numery wersji są lokalne dla repozytorium).Zostało to naprawione w Mercurial 1.6, który ma nowy zakres rewizji topologicznej , gdzie „A..B” (lub „A :: B”) jest rozumiany jako zbiór zestawów zmian, które są zarówno potomkami X, jak i przodkami Y. To jest Chyba odpowiednik „--ancestry-path A..B” w Git.
Git ma również zapis
A...B
symetrycznej różnicy poprawek; oznaczaA B --not $(git merge-base A B)
, co oznacza , że wszystkie zatwierdzenia osiągalne z A lub B, ale z wyłączeniem wszystkich zatwierdzeń osiągalnych z obu z nich (osiągalne od wspólnych przodków).Zmienia nazwy
Mercurial wykorzystuje śledzenie nazw w celu zmiany nazw plików. Oznacza to, że informacje o zmianie nazwy pliku są zapisywane w czasie zatwierdzania; w Mercurial informacja ta jest zapisywana w postaci „rozszerzonego pliku różnicowego ” w metadanych pliku filelog (plik rejestru). Konsekwencją tego jest to, że musisz użyć
hg rename
/hg mv
... lub musisz pamiętać, aby uruchomić,hg addremove
aby wykryć zmiany nazw na podstawie podobieństwa.Git jest wyjątkowy wśród systemów kontroli wersji, ponieważ wykorzystuje wykrywanie zmian nazw do radzenia sobie ze zmianami nazw plików. Oznacza to, że fakt zmiany nazwy pliku jest wykrywany w momencie, gdy jest potrzebny: podczas scalania lub podczas wyświetlania różnic (jeśli zażądano / skonfigurowano). Ma to tę zaletę, że algorytm wykrywania zmiany nazwy można ulepszyć i nie jest zawieszany w momencie zatwierdzenia.
Zarówno Git, jak i Mercurial wymagają użycia
--follow
opcji śledzenia nazw podczas wyświetlania historii pojedynczego pliku. Obie mogą zmieniać nazwy podczas wyświetlania historii pliku wgit blame
/hg annotate
.W Git
git blame
polecenie może śledzić ruch kodu, również przenosić (lub kopiować) kod z jednego pliku do drugiego, nawet jeśli ruch kodu nie jest częścią zdrowej zmiany nazwy pliku. O ile mi wiadomo, ta funkcja jest unikalna dla Git (w momencie pisania, październik 2009).Protokoły sieciowe
Zarówno Mercurial, jak i Git mają obsługę pobierania i przekazywania do repozytoriów w tym samym systemie plików, gdzie adres URL repozytorium to tylko ścieżka systemu plików do repozytorium. Oba mają również obsługę pobierania z plików pakietów .
Obsługa pobierania i wypychania obsługi Mercurial za pośrednictwem protokołu SSH i protokołów HTTP. Do SSH potrzebne jest dostępne konto powłoki na maszynie docelowej i kopia zainstalowanego / dostępnego hg. Do uzyskania dostępu HTTP
hg-serve
wymagany jest uruchomiony skrypt Mercurial CGI, a Mercurial musi zostać zainstalowany na serwerze.Git obsługuje dwa rodzaje protokołów używanych do uzyskiwania dostępu do zdalnego repozytorium:
git-daemon
), wymagają zainstalowania git na serwerze. Wymiana w tych protokołach polega na negocjowaniu przez klienta i serwer, jakie obiekty mają ze sobą wspólnego, a następnie generowaniu i wysyłaniu pliku pakietu. Modern Git zawiera obsługę „inteligentnego” protokołu HTTP.git update-server-info
(zwykle uruchamiane z haka ). Wymiana polega na przejściu przez klienta łańcucha zatwierdzeń i pobraniu luźnych obiektów i plików pakietów w razie potrzeby. Minusem jest to, że pobiera więcej niż jest to absolutnie wymagane (np. W przypadku narożnika, gdy jest tylko jeden plik pakietu, zostanie pobrany w całości, nawet jeśli pobierze tylko kilka wersji) i że może wymagać wielu połączeń do zakończenia.Rozszerzanie: skryptowalność a rozszerzenia (wtyczki)
Mercurial jest zaimplementowany w Pythonie , a niektóre kluczowe kody napisane są w C dla wydajności. Zapewnia interfejs API do pisania rozszerzeń (wtyczek) jako sposób dodawania dodatkowych funkcji. Niektóre funkcje, takie jak „oddziały zakładek” lub podpisywanie poprawek, są dostarczane w rozszerzeniach dystrybuowanych z Mercurial i wymagają włączenia.
Git jest zaimplementowany w skryptach C , Perl i shell . Git zapewnia wiele poleceń niskiego poziomu ( hydraulicznych ) odpowiednich do użycia w skryptach. Zwykłym sposobem wprowadzenia nowej funkcji jest napisanie jej jako Perla lub skryptu powłoki, a gdy interfejs użytkownika ustabilizuje się, przepisz go w C w celu zwiększenia wydajności, przenośności, aw przypadku skryptu powłoki unikania przypadków narożnych (ta procedura nazywa się wbudowaniem ).
Git polega na formatach [repozytorium] i protokołach [sieci] i jest zbudowany na nich. Zamiast powiązań językowych (częściowe lub całkowite) reimplementacje Git w innych językach (niektóre z nich są częściowo reimplementacje i częściowo owijają się wokół poleceń git): JGit (Java, używany przez EGit, Eclipse Git Plugin), Grit (Ruby) , Dulwich (Python), git # (C #).
TL; DR
źródło
Myślę, że możesz poczuć, w jaki sposób te systemy są podobne lub różne, oglądając te dwa filmy:
Linus Torvalds w serwisie Git ( http://www.youtube.com/watch?v=4XpnKHJAok8 )
Bryan O'Sullivan w Mercurial ( http://www.youtube.com/watch?v=JExtkqzEoHY )
Oba są bardzo podobne w projekcie, ale bardzo różne we wdrożeniach.
Używam Mercurial. O ile rozumiem Git, jedną z głównych rzeczy git jest to, że śledzi zawartość plików zamiast samych plików. Linus mówi, że jeśli przeniesiesz funkcję z jednego pliku do drugiego, Git opowie Ci historię tej pojedynczej funkcji w trakcie przenoszenia.
Mówią też, że git działa wolniej niż HTTP, ale ma swój własny protokół sieciowy i serwer.
Git działa lepiej jako gruby klient SVN niż Mercurial. Możesz ciągnąć i naciskać na serwer SVN. Ta funkcja jest wciąż rozwijana w Mercurial
Zarówno Mercurial, jak i Git mają bardzo ładne dostępne rozwiązania hostingowe (BitBucket i GitHub), ale Google Code obsługuje tylko Mercurial. Nawiasem mówiąc, mają bardzo szczegółowe porównanie Mercurial i Git, które zrobili, aby zdecydować, który z nich wspierać ( http://code.google.com/p/support/wiki/DVCSAnalysis ). Ma wiele dobrych informacji.
źródło
Jakiś czas temu napisałem wpis na blogu o modelach rozgałęziających Mercurial i zawierałem porównania z modelem rozgałęziającym gita. Może uznasz to za interesujące: http://stevelosh.com/blog/entry/2009/8/30/a-guide-to-branching-in-mercurial/
źródło
Używam obu dość regularnie. Główną różnicą funkcjonalną jest sposób, w jaki nazwy Git i Mercurial rozgałęziają się w repozytoriach. W Mercurial nazwy gałęzi są klonowane i wyciągane wraz z ich zestawami zmian. Kiedy dodajesz zmiany do nowej gałęzi w Mercurial i wypychasz do innego repozytorium, nazwa gałęzi jest wypychana w tym samym czasie. Tak więc nazwy oddziałów są mniej lub bardziej globalne w Mercurial i musisz użyć rozszerzenia Bookmark, aby mieć tylko lekkie nazwy lokalne (jeśli chcesz, Mercurial domyślnie używa anonimowych lekkich kodelin, które w swojej terminologii są zwane „głowami”). W Git nazwy gałęzi i ich iniekcyjne mapowanie do zdalnych gałęzi są przechowywane lokalnie i musisz nimi zarządzać jawnie, co oznacza, że wiesz, jak to zrobić.
Jak zauważą tutaj inni, istnieje wiele drobnych różnic. Z gałęziami jest duży wyróżnik.
źródło
Spójrz na post Git vs. Mercurial: Please Relax na blogu Patrick Thomson, w którym pisze:
Git to MacGyver , Mercurial to James Bond
Pamiętaj, że ten post na blogu pochodzi z 7 sierpnia 2008 r. I od tego czasu oba SCM znacznie się poprawiły.
źródło
Mercurial jest prawie w całości napisany w języku python. Rdzeń Gita jest napisany w C (i powinien być szybszy niż Mercurial), a narzędzia napisane w sh, perl, tcl i używają standardowych narzędzi GNU. Dlatego musi zabrać ze sobą wszystkie narzędzia i interpretatory do systemu, który ich nie zawiera (np. Windows).
Oba wsparcie działa z SVN, chociaż obsługa svn AFAIK jest zepsuta dla git w Windows (być może jestem po prostu pechowa / lame, kto wie). Istnieją również rozszerzenia, które pozwalają na współpracę między git i Mercurial.
Mercurial ma niezłą integrację Visual Studio . Ostatnim razem, gdy sprawdzałem, wtyczka do Git działała, ale była bardzo wolna.
Podstawowe zestawy poleceń są bardzo podobne (init, klonowanie, dodawanie, status, zatwierdzanie, wypychanie, wyciąganie itp.). Tak więc podstawowy przepływ pracy będzie taki sam. Istnieje również klient podobny do TortoiseSVN.
Rozszerzenia dla Mercurial mogą być napisane w pythonie (nic dziwnego!), A dla git mogą być napisane w dowolnej formie wykonywalnej (plik binarny, skrypt powłoki itp.). Niektóre rozszerzenia są niesamowicie potężne
git bisect
.źródło
Jeśli potrzebujesz dobrego wsparcia dla systemu Windows, możesz preferować Mercurial. TortoiseHg (wtyczka eksploratora Windows) oferuje prosty w obsłudze interfejs graficzny do dość złożonego narzędzia. Jak podam tutaj, będziesz mieć także wtyczkę Visual Studio . Jednak ostatnim razem, gdy próbowałem, interfejs SVN nie działał tak dobrze w systemie Windows.
Jeśli nie przeszkadza ci interfejs wiersza poleceń, polecam Git. Nie z powodów technicznych, ale ze względów strategicznych. Szybkość adopcji git jest znacznie wyższa. Zobacz, ile znanych projektów open source przechodzi z cvs / svn na Mercurial i ile przechodzi na Git. Zobacz, ilu dostawców hostingu kodów / projektów możesz znaleźć dzięki obsłudze git w porównaniu do hostingu Mercurial.
źródło
Po przeczytaniu, że Mercurial jest łatwiejszy (co nadal uważam, mimo opinii społeczności internetowej), kiedy zacząłem współpracować z Git i Mercurial, poczułem, że Git jest stosunkowo łatwiejszy do przystosowania się (zacząłem z Mercurial z TortoiseHg) podczas pracy z wiersza poleceń, głównie dlatego, że polecenia git zostały odpowiednio nazwane według mnie i jest ich mniej. Mercurial ma różne nazwy dla każdego polecenia wykonującego odrębne zadanie, natomiast polecenia Git mogą być uniwersalne w zależności od sytuacji (np.
checkout
). Podczas gdy Git był wtedy trudniejszy, teraz różnica nie jest znacząca. YMMV .. Przy dobrym kliencie GUI, takim jak TortoiseHg, prawda, praca z Mercurialem była o wiele łatwiejsza i nie musiałem pamiętać o nieco mylących poleceniach. Nie będę szczegółowo omawiał, jak różni się każde polecenie dla tej samej akcji, ale oto dwie obszerne listy: 1 z własnej strony Mercurial i 2 z wikivs .Git zapisuje wewnętrznie zapis każdej wersji zatwierdzonych plików, a Hg zapisuje tylko zestawy zmian, które mogą mieć mniejszą powierzchnię. Git ułatwia zmianę historii w porównaniu do Hg, ale z drugiej strony jest to funkcja nienawiści lub miłości. Lubię Hg dla pierwszego i Git dla drugiego.
W Hg tęsknię za funkcją podmodułu Git. Hg ma subrepos, ale to nie jest dokładnie submoduł Git.
Ekosystem wokół nich może również wpływać na wybór: Git musi być bardziej popularny (ale to banalne), Git ma GitHub, podczas gdy Mercurial ma BitBucket , Mercurial ma TortoiseHg, dla którego nie widziałem odpowiednika tak dobrego dla Git.
Każda z nich ma swoje zalety i wady, a żadnej z nich nie stracisz.
źródło
Sprawdź post Scott Chacon jakiś czas temu.
Myślę, że git ma reputację „bardziej skomplikowanej”, choć z mojego doświadczenia nie jest bardziej skomplikowana niż powinna. IMO, model git jest znacznie łatwiejszy do zrozumienia (tagi zawierają zatwierdzenia (i wskaźniki do zerowej lub większej liczby zatwierdzeń nadrzędnych) zawierają drzewa zawierające obiekty BLOB i inne drzewa ... gotowe).
Z mojego doświadczenia wynika, że git nie jest bardziej mylący niż rtęciowy. Poleciłbym ponownie przeczytać ten post na blogu od Scotta Chakona w tej sprawie.
źródło
.hgtags
po sprawdzeniu wersji 1.0. Jednak nie musisz zaglądać do środka,.hgtags
a zobaczysz, żehg tags
wciąż wyświetla wszystkie tagi. Co więcej, takie zachowanie jest prostą konsekwencją przechowywania znaczników w pliku kontrolowanym wersją - ponownie model jest łatwy do uchwycenia i bardzo przewidywalny .Używam Git przez nieco ponad rok w mojej obecnej pracy, a wcześniej użyłem Mercurial przez nieco ponad rok w mojej poprzedniej pracy. Zamierzam przedstawić ocenę z perspektywy użytkownika.
Po pierwsze, oba są rozproszonymi systemami kontroli wersji. Rozproszone systemy kontroli wersji wymagają zmiany sposobu myślenia w stosunku do tradycyjnych systemów kontroli wersji, ale w rzeczywistości działają znacznie lepiej na wiele sposobów, gdy się je zrozumie. Z tego powodu uważam, że zarówno Git, jak i Mercurial są znacznie lepsze od Subversion, Perforce itp. Różnica między rozproszonymi systemami kontroli wersji a tradycyjnymi systemami kontroli wersji jest znacznie większa niż różnica między Git i Mercurial.
Istnieją jednak również znaczne różnice między Git i Mercurial, które sprawiają, że każdy z nich lepiej pasuje do własnego podzbioru przypadków użycia.
Mercurial jest łatwiejszy do nauczenia. Doszedłem do momentu, w którym po kilku tygodniach używania Mercurial rzadko musiałem odwoływać się do dokumentacji lub notatek; Nadal muszę regularnie korzystać z notatek w Git, nawet po roku używania. Git jest znacznie bardziej skomplikowany.
Wynika to częściowo z tego, że Mercurial jest po prostu czystszy. Rzadko trzeba rozgałęziać się ręcznie w Mercurial; Mercurial automatycznie utworzy dla ciebie anonimowy oddział, jeśli będziesz go potrzebować. Nazewnictwo rtęciowe jest bardziej intuicyjne; nie musisz się martwić różnicą między „pobieraniem” a „wyciąganiem”, tak jak w przypadku Git. Mercurial jest nieco mniej buggy. Występują problemy z rozróżnianiem wielkości liter w nazwach plików, które powodowały problemy podczas przesyłania projektów między platformami za pomocą Git i Mercurial; zostały naprawione w Mercurial jakiś czas temu, podczas gdy nie zostały naprawione w Git, kiedy ostatnio sprawdzałem. Możesz powiedzieć Mercurial o nazwach plików; z Gitem, jeśli nie wykryje automatycznie zmiany nazwy - z mojego doświadczenia wynika, że jest to trafienie trafne lub brakujące - zmiana nazwy nie może być w ogóle śledzona.
Innym powodem dodatkowych komplikacji Gita jest to, że wiele z nich jest potrzebnych do obsługi dodatkowych funkcji i mocy. Tak, bardziej skomplikowana jest obsługa rozgałęziania w Git - ale z drugiej strony, kiedy już masz gałęzie, nie jest zbyt trudno robić rzeczy z tymi gałęziami, które są praktycznie niemożliwe w Mercurial. Odbudowywanie gałęzi jest jedną z tych rzeczy: możesz przesunąć gałąź tak, aby jej podstawa, zamiast być stanem pnia podczas rozgałęzienia, jest teraz stanem pnia; znacznie upraszcza to historię wersji, gdy wiele osób pracuje na tej samej podstawie kodu, ponieważ każdy przekaz do pnia może wyglądać sekwencyjnie, a nie spleciony. Podobnie o wiele łatwiej jest zwinąć wiele zatwierdzeń w oddziale w jednym zatwierdzeniu,
Ostatecznie myślę, że wybór między Mercurial i Git powinien zależeć od tego, jak duże są twoje projekty kontroli wersji, mierzone liczbą osób pracujących nad nimi jednocześnie. Jeśli masz grupę kilkunastu lub więcej pracujących nad pojedynczą monolityczną aplikacją internetową, na przykład potężniejsze narzędzia do zarządzania oddziałami Git sprawią, że będzie ona znacznie lepiej dopasowana do Twojego projektu. Z drugiej strony, jeśli Twój zespół opracowuje heterogeniczny system rozproszony, z tylko jednym lub dwoma programistami pracującymi nad jednym komponentem w dowolnym momencie, użycie repozytorium Mercurial dla każdego projektu komponentowego pozwoli na bardziej płynny rozwój przy mniejszym nakładzie pracy koszty zarządzania repozytorium.
Konkluzja: jeśli masz duży zespół opracowujący jedną ogromną aplikację, użyj Git; jeśli twoje indywidualne aplikacje są małe, z dowolną skalą pochodzącą od liczby, a nie wielkości takich aplikacji, użyj Mercurial.
źródło
Jedna różnica całkowicie niezwiązana z samymi DVCS:
Git wydaje się być bardzo popularny wśród programistów C. Git to de facto repozytorium dla jądra Linuksa i może to być powód, dla którego jest tak popularny wśród programistów C. Dotyczy to szczególnie tych, którzy mają luksus pracy tylko w świecie Linux / Unix.
Deweloperzy Java wydają się faworyzować Mercurial nad Git. Są prawdopodobnie dwa powody: Jednym z nich jest to, że wiele bardzo dużych projektów Java jest hostowanych na Mercurial, w tym sam JDK. Innym jest fakt, że struktura i przejrzysta dokumentacja Mercurial przemawia do osób pochodzących z obozu Java, podczas gdy tacy ludzie uważają Git za niespójne nazywanie poleceń wrt i brak dokumentacji. Nie twierdzę, że to prawda, mówię, że ludzie przyzwyczaili się do czegoś ze swojego zwykłego środowiska, a następnie wybierają z tego DVCS.
Zakładam, że programiści Python prawie wyłącznie faworyzują Mercurial. W rzeczywistości nie ma żadnego racjonalnego powodu innego niż fakt, że Mercurial jest oparty na Pythonie. (Używam również Mercurial i naprawdę nie rozumiem, dlaczego ludzie robią tyle zamieszania na temat języka implementacji DVCS. Nie rozumiem słowa Python i jeśli nie z tego powodu, że jest gdzieś tam wymienione jest oparty na Pythonie, więc bym nie wiedział).
Nie sądzę, żebyś mógł powiedzieć, że jeden DVCS pasuje do języka lepiej niż inny, więc nie powinieneś wybierać z tego. Ale w rzeczywistości ludzie wybierają (częściowo) na podstawie tego, na jakie DVCS są najbardziej narażeni w ramach swojej społeczności.
(nie, nie mam statystyk użytkowania, aby poprzeć powyższe twierdzenia… wszystko opiera się na mojej subiektywności)
źródło