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
.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ę 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 bisect
polecenie w Mercurial (wcześniej rozszerzenie dwusieczne ) zostało zainspirowane git bisect
poleceniem w Git, a pomysł git bundle
zainspirowany 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 .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
lub tags
, na przykład local-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 (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, ^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”
- 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..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 zachowanie A..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 temat A...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; 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 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 w git 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:
- „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