Git and Mercurial - Porównaj i kontrastuj


520

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:


451

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

  • Struktura repozytorium: Mercurial nie pozwala na scalanie ośmiornic (z więcej niż dwoma rodzicami), ani oznaczanie obiektów niezatwierdzonych.
  • Tagi: Mercurial używa wersji .hgtagspliku 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ę w refs/tags/przestrzeni nazw, a domyślnie są automatycznie pobierane podczas pobierania i wymagają jawnego wypychania.
  • Oddziały: W Mercurial podstawowy obieg pracy oparty jest na anonimowych głowach ; Git używa lekkich nazwanych gałęzi i ma specjalny rodzaj gałęzi (gałęzi zdalnego śledzenia ), które podążają za gałęziami w zdalnym repozytorium.
  • Nazwy wersji i zakresy: Mercurial podaje numery wersji lokalnych do repozytorium i bazuje na względnych wersjach (licząc od końcówki, tj. Bieżącej gałęzi) i zakresach wersji na podstawie tej lokalnej numeracji; Git zapewnia sposób odwoływania się do wersji w odniesieniu do wierzchołka gałęzi, a zakresy wersji są topologiczne (na podstawie wykresu wersji)
  • Mercurial korzysta ze śledzenia zmian nazw , podczas gdy Git wykorzystuje wykrywanie zmian nazw, aby radzić sobie ze zmianami nazw plików
  • Sieć: Mercurial obsługuje „inteligentne” protokoły SSH i HTTP oraz statyczny protokół HTTP; nowoczesny Git obsługuje „inteligentne” protokoły SSH, HTTP i GIT oraz „głupi” protokół HTTP (S). Oba mają obsługę plików pakietów do transportu off-line.
  • Mercurial używa rozszerzeń (wtyczek) i ustalonego API; Git ma skryptowalność i ustalone formaty.

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 bisectpolecenie w Mercurial (wcześniej rozszerzenie dwusieczne ) zostało zainspirowane git bisectpoleceniem w Git, a pomysł git bundlezainspirowany przez hg 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 w refs/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 w refs/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 .hgtagspliku 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, remoteslub tags, na przykład local-tagsdla 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ć .hgtagsspecjalnie (plik w drzewie można przenosić, ale zwykły jest wersjonowany), lub mieć tagi tylko lokalne ( .hg/localtagsnie 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/bookmarksplik 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.defaultzmiennej 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ć --allopcji 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 (z refs/heads/przestrzeni nazw) i przechowuje je w refs/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):

  • Pełna nazwa obiektu SHA1 (40-bajtowy ciąg szesnastkowy) lub taki ciąg znaków, który jest unikalny w repozytorium
  • Symboliczna nazwa odniesienia, np. „Master” (odnosząca się do gałęzi „master”) lub „v1.5.0” (odnosząca się do tagu), lub „origin / next” (odnosząca się do gałęzi zdalnego śledzenia)
  • Przyrostek ^parametru rewizji oznacza pierwszego rodzica obiektu zatwierdzenia, ^noznacza n-tego rodzica zatwierdzenia scalania. Przyrostek ~nparametru 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”
  • Wyjście „git opisz”, tj. Najbliższy znacznik, opcjonalnie po nim myślnik i pewna liczba zatwierdzeń, po którym następuje myślnik, „g” i skrócona nazwa obiektu, na przykład „v1.6.5.1-75- g5bf8097 ”.

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 ):

  • Zwykła liczba całkowita jest traktowana jako numer wersji. Należy pamiętać, że numery wersji są lokalne dla danego repozytorium ; w innym repozytorium mogą się różnić.
  • Ujemne liczby całkowite są traktowane jako sekwencyjne przesunięcia od końcówki, gdzie -1 oznacza końcówkę, -2 oznacza rewizję przed końcówką i tak dalej. Są również lokalne dla repozytorium.
  • Unikalny identyfikator wersji (40-cyfrowy ciąg szesnastkowy) lub jego unikalny prefiks.
  • Nazwa znacznika (nazwa symboliczna powiązana z daną rewizją) lub nazwa zakładki (z rozszerzeniem: nazwa symboliczna powiązana z daną nagłówkiem, lokalna dla repozytorium) lub „nazwana gałąź” (etykieta zatwierdzenia; wersja podana przez „nazwaną gałąź” to tip (zatwierdzenie bezdzietne) wszystkich zatwierdzeń z podaną etykietą zatwierdzenia, z największym numerem wersji, jeśli istnieje więcej niż jedna taka wskazówka)
  • Zastrzeżona nazwa „tip” to specjalny znacznik, który zawsze identyfikuje najnowszą wersję.
  • Nazwa zarezerwowana „null” wskazuje wersję zerową.
  • Nazwa zastrzeżona „.” wskazuje nadrzędny katalog roboczy.

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..Bskł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 Bktórego dla poleceń przejścia historii oznacza wszystko zatwierdzenia osiągalne z B, wyłączając te osiągalne z A. Oznacza to, że zachowanie A..Bzakresu jest całkowicie przewidywalne (i całkiem przydatne), nawet jeśli A nie jest przodkiem B: A..Boznacza 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:Bskł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 temat A...Bskł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...Bsymetrycznej różnicy poprawek; oznacza A 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 addremoveaby 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 --followopcji śledzenia nazw podczas wyświetlania historii pojedynczego pliku. Obie mogą zmieniać nazwy podczas wyświetlania historii pliku w git blame/ hg annotate.

W Git git blamepolecenie 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-servewymagany 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:

  • „inteligentne” protokoły , które obejmują dostęp przez SSH i niestandardowy protokół git: // (przez 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.
  • „głupie” protokoły , które obejmują HTTP i FTP (tylko do pobierania) oraz HTTPS (do wypychania przez WebDAV), nie wymagają git zainstalowanego na serwerze, ale wymagają, aby repozytorium zawierało dodatkowe informacje generowane przez 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


32
Można dodać, że hg bardzo stara się zniechęcić do przepisywania historii (można to zrobić tylko z rozszerzeniami: mq, histedit, rebase), podczas gdy git robi to od razu po wyjęciu z pudełka (i wygląda na to, że jest częścią społeczności nawet zachęca to).
tonfa

80
Myślę, że „przepisywanie historii” brzmi niepotrzebnie negatywnie. Co mogę zachęcić ludzi w git jest rozważenie historię ich publikowania. Inni ludzie muszą skonsumować tę historię. Nikt (nawet ty) nie jest zainteresowany wszystkimi twoimi „ups, zapomniałem pliku”. Nikt też nie dba o serię połączeń przychodzących, które przeszedłeś podczas śledzenia oddziału podczas pracy nad nową funkcją. Tego rodzaju rzeczy znacznie utrudniają zrozumienie historii (i powiązanych narzędzi) i nie zapewniają żadnej wartości.
Dustin

5
@Jakub: nazwane gałęzie to coś, co nie istnieje w git. Jest to po prostu pole w opisie zestawu (i jest to część historii, więc jest niezmienne, chyba że zmienisz skróty itp.). Coś w rodzaju gałęzi git to zakładki („nazwane głowy”), ale obecnie nie można ich przenosić zdalnie (nie importujesz zdalnych zakładek podczas ciągnięcia). stevelosh.com/blog/entry/2009/8/30/… wyjaśnia to bardzo dobrze.
tonfa

28
„Mercurial początkowo obsługiwał tylko jedną gałąź w przepływie pracy repozytorium i to pokazuje”. O nie. Mercurial początkowo nie obsługiwał nazwanych gałęzi, ale zawsze mogłeś mieć tyle anonimowych gałęzi, ile tylko zapragnie twoje serce w jednym repo. Porównaj to z git, który sprawia, że ​​anonimowe rozgałęzianie jest ogromnym bólem. To dość dużo mają wymyślić nazwy dla każdego małego oddziału, jeśli chcesz dostać coś zrobić (i uniknąć swoją śmieci Prace zebrane).
Steve Losh

17
@ SteveLosh: wydaje ci się, że posiadanie wielu anonimowych oddziałów w Mercurial jest dobrą rzeczą, ale dla mnie wydaje się okropne. Jak odróżnić je wszystkie od siebie? I wydaje ci się, że nazywanie gałęzi w Git to ogromna trudność, ale jeśli masz cel, aby utworzyć gałąź, to masz gotową nazwę. Jeśli nie masz żadnego celu, nie rozgałęziaj się. Nie rozumiem, w jaki sposób Mercurial oferuje tutaj jakąkolwiek korzyść. Widzę tylko ból i zamieszanie.
iconoclast

57

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.


8
Polecam przeczytanie wszystkich komentarzy na tej stronie kodowej Google. Informacje są nieco stronnicze i nie pasują do moich doświadczeń. Lubię hg i używałem go intensywnie przez około rok. Używam git prawie wyłącznie teraz. Są rzeczy, które muszę osiągnąć, że git czyni łatwym, a hg prawie niemożliwym (chociaż niektórzy lubią to nazywać „komplikacją”). Podstawowy git jest tak łatwy jak base hg.
Dustin

11
Dustin, może wymień niektóre z tych „cholernie łatwych, hg nie tak bardzo” przypadków?
Gregg Lind,

1
@knittl nie, nie ma. Głównie dlatego, że wdrożenie ich byłoby utrudnione, ponieważ git nie ma inteligentnego protokołu HTTP (większość frontonów Google jest oparta na http).
tonfa

2
@tonfa: Aktualnie opracowywany jest inteligentny protokół HTTP dla Git (jak w: łatki znajdują się na liście mailingowej git i znajdują się w 'pu' = proponowana gałąź aktualizacji w repozytorium git.git).
Jakub Narębski

4
Obecnie Google Code obsługuje także Git.
Andrej Kirejeŭ

30

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/


@ Steve Losh: Chciałem skomentować ten wpis na blogu (o nienazwanej gałęzi aka odłączony HEAD oraz o git-fetch pobierającej wszystkie gałęzie, a nie jednej), ale dostałem błąd serwera 500.
Jakub Narębski

1
@Jakub Narębski Założę się, że problemem jest postać inna niż ASCII w twoim imieniu. Jestem prawie pewien, że napotkałem ten sam problem na innej stronie i okazało się, że dławienie wiązania Python Askimet na Unicode. Spojrzę na to.
Steve Losh

@ Steve Losh: Dzięki za informację, po „unidecoding” moje imię było w stanie komentować. Bardzo dobry opis rozgałęzień w Mercurial (ale nadal uważam, że jest gorszy ;-))
Jakub Narębski

@ SteveLosh Zachęcam do rozszerzenia tej odpowiedzi na pełniejszą recenzję rtęci. W tej chwili najważniejszą odpowiedzią jest niestety w dużej mierze reklama git, ponieważ jej autor nie używał zbyt często rtęci i nie rozumie, jak z niej efektywnie korzystać. Byłoby miło, gdyby kolejna odpowiedź zawierała merkurialny punkt widzenia, że ​​tak powiem.
Warren Dew

25

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.


2
Zobacz także ten post, aby uzyskać dobre wyjaśnienie na temat czterech rodzajów oddziałów w Mercurial: stevelosh.com/blog/entry/2009/8/30/…
Martin Geisler


11

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.


9
Rdzeń rtęciowy jest napisany również w C dla FYI (ale jest to prawdopodobnie mniejszy rdzeń niż git).
tonfa

1
Korzystam z git-svn w systemie Windows bez żadnych problemów. To używa Cygwina (jedyny właściwy sposób używania git w systemie Windows, jeśli mnie o to poprosisz). Nie można mówić za msysgit.
Dan Molding

@Dan Molding: Tak, mam problemy z msysgit. Może powinienem spróbować wypróbować port cygwin (wcześniej miałem trochę kiepskiego doświadczenia z używaniem cygwina, więc tego uniknąłem). Dzięki za radę!
elder_george

Ja osobiście nie lubię włamań cygwina do rejestru w celu przechowywania danych użytkownika. Jest to PITA, aby uruchomić go z klucza USB i zachować synchronizację lokalnej kopii dysku c: \, gdy chcę uruchomić szybciej niż mój klucz USB może przejść. : - /
Chris K

1
Używam wspomnianej wyżej wtyczki Git do programu Visual Studio, a wydajność bieżącej wersji jest dobra. Odpowiada za narzędzia wiersza polecenia, aby wykonać pracę, więc nie sądzę, aby znacznie straciła wydajność w dużych projektach.
Stuart Ellis,

11

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.


Istnieje również TortoiseGit, jeśli nie lubisz używać wiersza poleceń. (Ale wymaga zainstalowania msysgit.)
Ben James

2
Nasza firma ostatecznie wybrała git ze względu na świetne wsparcie dla systemu Windows - sprawdź rozszerzenia Git . Jestem stronniczy, ponieważ jestem teraz współpracownikiem, ale nie byłem, kiedy zaczęliśmy go używać.
Jacob Stanley

11

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               ║                Mercurial                                                                       ║
╠═════════════════════════════╬════════════════════════════════════════════════════════════════════════════════════════════════╣
║ git pull                    ║ hg pull -u                                                                                     ║
║ git fetch                   ║ hg pull                                                                                        ║
║ git reset --hard            ║ hg up -C                                                                                       ║
║ git revert <commit>         ║ hg backout <cset>                                                                              ║
║ git add <new_file>          ║ hg add <new_file> (Only equivalent when <new_file> is not tracked.)                            ║
║ git add <file>              ║ Not necessary in Mercurial.                                                                    ║
║ git add -i                  ║ hg record                                                                                      ║
║ git commit -a               ║ hg commit                                                                                      ║
║ git commit --amend          ║ hg commit --amend                                                                              ║
║ git blame                   ║ hg blame or hg annotate                                                                        ║
║ git blame -C                ║ (closest equivalent): hg grep --all                                                            ║
║ git bisect                  ║ hg bisect                                                                                      ║
║ git rebase --interactive    ║ hg histedit <base cset> (Requires the HisteditExtension.)                                      ║
║ git stash                   ║ hg shelve (Requires the ShelveExtension or the AtticExtension.)                                ║
║ git merge                   ║ hg merge                                                                                       ║
║ git cherry-pick <commit>    ║ hg graft <cset>                                                                                ║
║ git rebase <upstream>       ║ hg rebase -d <cset> (Requires the RebaseExtension.)                                            ║
║ git format-patch <commits>  ║ hg email -r <csets> (Requires the PatchbombExtension.)                                         ║
║   and git send-mail         ║                                                                                                ║
║ git am <mbox>               ║ hg mimport -m <mbox> (Requires the MboxExtension and the MqExtension. Imports patches to mq.)  ║
║ git checkout HEAD           ║ hg update                                                                                      ║
║ git log -n                  ║ hg log --limit n                                                                               ║
║ git push                    ║ hg push                                                                                        ║
╚═════════════════════════════╩════════════════════════════════════════════════════════════════════════════════════════════════╝

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.


8

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.


1
Model Mercurial jest w rzeczywistości prawie identyczny: dziennik zmian wskazuje manifest wersji do zmian pliku / obiektu blob ... gotowe. Jeśli porównywałeś format na dysku, prawdopodobnie nie uwzględniłeś pliku paczek, który jest trudniejszy do wyjaśnienia niż prosty format dziennika z hg.
tonfa

Cóż, ten uproszczony model ignoruje tagowanie, które w praktyce jest znacznie bardziej obłąkane (chociaż twierdzę, że tag git jest nieco mylący, ponieważ domyślnie nie tworzy obiektu tagu). Format na dysku był szczególnie drogi w przypadku obu projektów, które miały wiele nazw plików.
Dustin

1
Nie sądzę, że model ignoruje oznaczanie: oznaczanie jest trywialne w Mercurial - jak wiadomo, to tylko plik, który nadaje nazwy skrótom SHA-1. Nie ma zgadywania, jak tagi przepływają w systemie: poruszają się wraz z popychaniami i pociągnięciami. A jeśli występuje konflikt znaczników, to również trywialne jest jego rozwiązanie: rozwiązujesz go jak każdy inny konflikt. W końcu to tylko linia w pliku tekstowym. Myślę, że prostota tego modelu jest bardzo fajną funkcją.
Martin Geisler

Dustin: Tak, użytkownicy są często zdezorientowani faktem, że nie można zobaczyć znacznika 1.0 .hgtagspo sprawdzeniu wersji 1.0. Jednak nie musisz zaglądać do środka, .hgtagsa zobaczysz, że hg tagswciąż 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 .
Martin Geisler

1
Martin Geisler Twierdziłbym , że reguły dla znaczników w Mercurial, wymagane, ponieważ używa on pliku sterowanego wersją do transportu, z warstwą na specjalnych zasadach, aby znaczniki nie były wersjonowane, jest łatwe do uchwycenia.
Jakub Narębski

5

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.


4

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)

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.