Jakie jest dokładne znaczenie „nasz” i „ich” w git?

323

Może to zabrzmieć jak zbyt podstawowe pytanie, ale szukałem odpowiedzi i teraz jestem bardziej zdezorientowany niż wcześniej.

Co oznaczają „nasze” i „ich” w git, gdy łączę moją gałąź z moją inną? Obie gałęzie są „nasze”.

Czy w konflikcie scalania „nasza” jest zawsze wyświetlana górna z dwóch wersji?

Czy „nasz” zawsze odnosi się do gałęzi, na którą HEAD wskazywał, kiedy rozpoczęło się scalanie? Jeśli tak, to dlaczego nie zastosować wyraźnego odniesienia dzierżawczego, takiego jak „gałąź obecna” zamiast zaimka dzierżawczego, takiego jak „nasz”, który jest referencyjnie niejednoznaczny (ponieważ obie gałęzie są technicznie nasze)?

Lub po prostu użyj nazwy oddziału (zamiast „nasz”, po prostu powiedz „lokalny mistrz” lub podobny)?

Najbardziej mylące dla mnie jest to, że podam w pliku .gitattributes określonej gałęzi. Powiedzmy, że w gałęzi testowej mam następujący plik .gitattributes:

config.xml merge=ours

Teraz sprawdzam i kieruję HEAD do opanowania, a następnie łączę w teście . Skoro master jest nasz, a testy .gitattributes nie są sprawdzane, czy to w ogóle da efekt? Jeśli to zadziała , skoro mistrz jest teraz „nasz”, to co się stanie?

CommaToast
źródło

Odpowiedzi:

374

Podejrzewam, że jesteś zdezorientowany, ponieważ jest to zasadniczo mylące. Co gorsza, cała nasza / ich rzeczy zmieniają role (stają się zacofane), kiedy robisz rebase.

Ostatecznie, w czasie git merge, w „nasz” oddział odnosi się do oddziału jesteś łączących się :

git checkout merge-into-ours

a gałąź „ich” odnosi się do (pojedynczej) gałęzi, którą scalasz:

git merge from-theirs

a tutaj „nasz” i „ich” ma jakiś sens, ponieważ mimo że „ich” i tak prawdopodobnie należy do ciebie, „ich” nie jest tym, w którym byłeś podczas biegu git merge.

Chociaż używanie rzeczywistej nazwy oddziału może być całkiem fajne, rozpada się w bardziej złożonych przypadkach. Na przykład zamiast powyższego możesz wykonać:

git checkout ours
git merge 1234567

gdzie scalasz według surowego identyfikatora zatwierdzenia. Gorzej, możesz nawet to zrobić:

git checkout 7777777    # detach HEAD
git merge 1234567       # do a test merge

w takim przypadku nie są zaangażowane żadne nazwy oddziałów!

Wydaje mi się, że jest to mało pomocna, ale w rzeczywistości w gitrevisionsskładni można odwoływać się do indywidualnej ścieżki w indeksie według numeru podczas scalania

git show :1:README
git show :2:README
git show :3:README

Etap nr 1 jest wspólnym przodkiem plików, etap nr 2 to wersja gałęzi docelowej, a etap nr 3 to wersja, z której się łączysz.


Powodem, dla którego zmieniają się pojęcia „nasze” i „ich”, rebasejest to, że rebase działa, wykonując serię wiśniowych wyborów, w anonimowej gałęzi (odłączony tryb HEAD). Oddział docelowy jest oddziałem anonimowym, a oddział scalania z jest oddziałem pierwotnym (przedrebase): więc „--ours” oznacza, że ​​buduje się anonimowy rebase, podczas gdy „--heirs” oznacza „rebasing naszej gałęzi” .


Jeśli chodzi o wpis gitattributes: może to mieć skutek: „nasz” naprawdę oznacza „użyj etapu nr 2” wewnętrznie. Ale, jak zauważysz, nie jest on w tym czasie na miejscu, więc nie powinien mieć tutaj wpływu ... no cóż, chyba że skopiujesz go do drzewa roboczego przed rozpoczęciem.

Nawiasem mówiąc, dotyczy to wszystkich zastosowań naszego i ich, ale niektóre są na poziomie całego pliku ( -s oursdla strategii scalania; git checkout --ourspodczas konfliktu scalania), a niektóre są na zasadzie kawałek po kawałku ( -X ourslub -X theirspodczas -s recursivełączyć). Co prawdopodobnie nie pomaga w żadnym zamieszaniu.

Jednak nigdy nie wymyśliłem dla nich lepszej nazwy. I: zobacz odpowiedź VonC na inne pytanie, gdzie git mergetoolwprowadza jeszcze więcej nazw, nazywając je „lokalnymi” i „zdalnymi”!

Trek
źródło
28
+1. O naszym i ich odwróceniu podczas rebase, patrz także: stackoverflow.com/a/2960751/6309 i stackoverflow.com/a/3052118/6309
VonC
1
Dwie rzeczy „łączą się” ze sobą. Kiedy nastąpi scalenie, obie strony łączą się „ze sobą”. Uważam, że błędem byłoby twierdzić, że jedna z dwóch stron „nie łączy się w nic”. Jeśli nie ma tu żadnych nazw gałęzi (jak wskazałeś), to są zaangażowane nazwy zatwierdzeń (możesz powiedzieć „7777777's” i „1234567's” zamiast „nasz” i „ich”). Rozumiem, co dzieje się w trakcie naliczania i nie wydaje mi się, żeby było to mylące. Myślę, że „HEAD” i „przychodzące” działałyby lepiej niż „nasze” i „ich”, ponieważ zawsze istnieje „HEAD” (niezależnie od tego, czy jest odłączony, czy nie).
CommaToast,
15
Myślę, że ponieważ głowa jest siedzibą umysłu, który jest źródłem tożsamości, która jest źródłem jaźni, sensowniej jest myśleć o czymkolwiek, co HEAD wskazuje na „moje” („nasze”, ponieważ Chyba mnie, a HEAD tworzy dwa). Jeśli nic więcej, będzie to po prostu dobre urządzenie mnemoniczne.
CommaToast,
1
To powiedziawszy, wciąż lubię robić fizyczną kopię całego repo, zanim zrobię coś takiego jak bazowanie ...: D
CommaToast,
3
„w którym to przypadku nie występują nazwy gałęzi!” ... Więc zamiast tego należy użyć komentarza / skrótu zatwierdzenia. Cokolwiek może dostać w swoje ręce. Praktycznie wszystko byłoby lepsze niż „nasze” i „ich”. Zastanawiam się, ile tysięcy godzin twórczych to zamieszanie wyparowało. odpowiedź gita na „najbardziej irytującą analizę” C ++;)
Jarrod Smith
49

Nasz ” w Git odnosi się do oryginalnej gałęzi roboczej, która ma autorytatywną / kanoniczną część historii git.

Do „ ich ” odnosi się do wersji, która posiada pracę w celu rebased (zmiany do być odtwarzane na obecnym oddziale).

Może się to wydawać zamienione na ludzi, którzy nie są świadomi, że dokonywanie zmiany zasad (np. git rebase) Faktycznie wstrzymuje twoją pracę (która jest ich ), aby powrócić do kanonicznej / głównej historii, która jest nasza , ponieważ zmieniamy naszą zmienia się jako praca strony trzeciej.

Dokumentacja git-checkoutzostała wyjaśniona w Git> = 2.5.1 zgodnie z f303016zatwierdzeniem :

--ours --theirs

Podczas sprawdzania ścieżek z indeksu sprawdź etap nr 2 („nasz”) lub nr 3 („ich”) pod kątem nie połączonych ścieżek.

Zauważ, że podczas git rebasei git pull --rebase„nasze” i „ich” mogą wyglądać na zamienione; --ourspodaje wersję z gałęzi, na której zmiany są oparte, a --theirswersję z gałęzi, w której znajduje się twoja praca, która jest zmieniana.

Wynika to z tego, że rebasejest używany w przepływie pracy, który traktuje historię na pilocie jako współużytkowany kanoniczny i traktuje pracę wykonaną w gałęzi, którą udostępniasz, jako pracę innej firmy, którą chcesz zintegrować, i tymczasowo przejmujesz rolę strażnik historii kanonicznej podczas rebaseu. Jako strażnik historii kanonicznej, musisz przeglądać historię ze zdalnego jako ours(tj. „Nasza wspólna historia kanoniczna”), podczas gdy to, co zrobiłeś na swojej bocznej gałęzi jako theirs(tj. „Praca jednego współautora nad nią”).

Na git-mergeto wytłumaczyć w następujący sposób:

nasz

Ta opcja wymusza automatyczne rozwiązywanie konfliktowych kawałków, faworyzując naszą wersję. Zmiany w drugim drzewie, które nie powodują konfliktu z naszą stroną, są odzwierciedlane w wyniku scalenia. W przypadku pliku binarnego cała zawartość jest pobierana z naszej strony.

Nie należy tego mylić z naszą strategią scalania, która w ogóle nie uwzględnia zawartości drugiego drzewa. Odrzuca wszystko, co zrobiło drugie drzewo, deklarując, że nasza historia zawiera wszystko, co się w nim wydarzyło.

ich

To jest przeciwieństwo naszego.

Ponadto wyjaśniono, jak z nich korzystać:

Mechanizm scalania ( git mergei git pullpolecenia) pozwala wybrać strategie scalania zaplecza z -sopcją. Niektóre strategie mogą również przyjmować własne opcje, które można przekazać, podając -X<option>argumenty git mergei / lub git pull.


Czasami może to być mylące, na przykład:

  • git pull origin mastergdzie -Xoursjest nasz lokalny, -Xtheirsjest ich (zdalny) oddział
  • git pull origin master -rgdzie -Xoursjest ich (zdalnie), -Xtheirsjest nasze

Tak więc drugi przykład jest przeciwny do pierwszego, ponieważ opieramy naszą gałąź na zdalnym, więc nasz punkt początkowy jest zdalny, a nasze zmiany są traktowane jako zewnętrzne.

Podobne dla git mergestrategii ( -X oursi -X theirs).

kenorb
źródło
2
ta odpowiedź wydaje się nieaktualna => „git merge --ours” nie jest prawidłową opcją
Alexander Mills,
@AlexanderMills Odpowiedź nie mówić git merge, ale git pulli git checkoutjako przykład. Jeśli chcesz użyć tego parametru git merge, powinieneś użyć -X ours. Nadal możesz używać --oursskładni dla git checkout. Wyjaśniłem odpowiedź jeszcze bardziej.
kenorb
46

Wiem, że udzielono odpowiedzi, ale ten problem pomieszał mnie tak wiele razy, że założyłem małą stronę referencyjną, aby pomóc mi zapamiętać: https://nitaym.github.io/ourstheirs/

Oto podstawy:

Łączy:

$ git checkout master 
$ git merge feature

Jeśli chcesz wybrać wersję w master:

$ git checkout --ours codefile.js

Jeśli chcesz wybrać wersję w feature:

$ git checkout --theirs codefile.js

Rebases:

$ git checkout feature 
$ git rebase master 

Jeśli chcesz wybrać wersję w master:

$ git checkout --ours codefile.js

Jeśli chcesz wybrać wersję w feature:

$ git checkout --theirs codefile.js

(Dotyczy to oczywiście kompletnych plików)

Nitay
źródło
1
Ta strona jest bardzo pomocna. Styl schematu blokowego i słowa oznaczone kolorami sprawiają, że strona internetowa jest łatwiejsza do zrozumienia niż odpowiedzi SO. Dziękuję Ci.
Ron
10
  • Nasz : jest to gałąź, w której aktualnie się znajdujesz.
  • Ich : To druga gałąź używana w twojej akcji.

Więc jeśli jesteś na oddział uwalniania / 2,5 i scalić gałąź funkcji / New-przyciski do niego, wtedy zawartość, jak znaleźć w wydaniu / 2.5 jest to, co nasz odnosi się do i treści, jak znaleźć na fabularnych / nowych przycisków jest to, co ich dotyczy do. Podczas akcji scalania jest to dość proste.

Jedynym problemem, na który wpada większość ludzi, jest przypadek rebase . Jeśli wykonasz zmianę bazy zamiast normalnego scalenia, role zostaną zamienione. Jak to? Jest to spowodowane wyłącznie sposobem działania bazowania. Pomyśl o rebase, aby działał w ten sposób:

  1. Wszystkie zatwierdzenia dokonane od ostatniego ściągnięcia są przenoszone do własnego oddziału, nazwijmy go BranchX .
  2. Kasa kontrolujesz w bieżącym oddziale, odrzucając wszelkie lokalne zmiany, ale w ten sposób odzyskujesz wszystkie zmiany, które inni pchnęli dla tej gałęzi.
  3. Teraz każde zatwierdzenie w BranchX jest wybierane w sposób staranny do nowego w bieżącym oddziale.
  4. BranchX jest ponownie usuwany i dlatego nigdy nie pojawi się w żadnej historii.

Oczywiście nie o to tak naprawdę chodzi, ale jest to dla mnie miły model umysłu. A jeśli spojrzysz na 2 i 3, zrozumiesz, dlaczego role zostały teraz zamienione. Od 2, twoja obecna gałąź jest teraz gałęzią z serwera bez żadnych twoich zmian, więc to jest nasza (gałąź, w której się znajdujesz). Wprowadzone zmiany znajdują się teraz w innej gałęzi, która nie jest twoja ( BranchX ), a zatem zmiany te (mimo że są zmianami, które wprowadziłeś) należą do nich (druga gałąź używana w twojej akcji).

Oznacza to, że jeśli się połączysz i chcesz, aby twoje zmiany zawsze wygrywały, powiedziałbyś gitowi, aby zawsze wybierał „nasze”, ale jeśli zrobisz bazowanie i chcesz, aby wszystkie twoje zmiany zawsze wygrywały, mówisz gitowi, aby zawsze wybierał „ich”.

Mecki
źródło
3

Wiem, że to nie wyjaśnia znaczenia, ale zrobiłem sobie mały obrazek, aby przypomnieć, którego użyć:

wprowadź opis zdjęcia tutaj

Mam nadzieję, że to pomoże!

PS - sprawdź także link w odpowiedzi Nitay 🙂

Kamafeather
źródło
3

Zamieszczę tutaj moją notatkę, ponieważ muszę tu wracać raz po raz.

SCENARIUSZ 1. Zwykły programista: jesteś programistą, który nie może się łączyć masteri musi grać featuretylko z oddziałami.

Przypadek 1: mistrz jest królem. Chcesz odświeżyć featuregałąź (= rebase to master), ponieważ masterzawiera nowe aktualizacje zależności i chcesz zastąpić swoje skromne zmiany.

git checkout master
git pull

git checkout feature
git rebase -X ours master

Przypadek 2: jesteś królem. Chcesz zmienić swój featureoddział na masterzmiany. Ale zrobiłeś więcej niż koledzy i chciałeś wykorzystać własne zmiany w pierwszej kolejności.

git checkout master
git pull

git checkout feature
git rebase -X theirs master

WAŻNE: Jak widać, normalni programiści powinni preferować rebasei powtarzać go każdego ranka jak ćwiczenia / kawę.

SCENARIUSZ 2. Scalanie sensei: Jesteś liderem zespołu i chcesz połączyć inne gałęzie i przekazać scalony wynik bezpośrednio do mistrza. masterto gałąź, którą zmienisz.

Przypadek 1: mistrz jest królem Chcesz połączyć oddział firmy zewnętrznej, ale masterjest priorytetem. featureto gałąź, którą zrobił twój senior.

git checkout feature
git pull

git checkout master
git merge -X ours master

Przypadek 2: nowe zmiany są królem Gdy twój starszy programista wydał fajne featurei chcesz zastąpić stare s ** t w masteroddziale.

git checkout feature
git pull

git checkout master
git merge -X theirs master

PAMIĘTAJ: Aby zapamiętać w północy, który z nich wybrać: masterjest oursZAWSZE. I theirsto featurewłaśnie zrobili.

DenisKolodin
źródło
2

Z git checkoutużycia:

-2, --ours            checkout our version for unmerged files
-3, --theirs          checkout their version for unmerged files
-m, --merge           perform a 3-way merge with the new branch

Podczas rozwiązywania konfliktów scalania można to zrobić git checkout --theirs some_filei git checkout --ours some_filezresetować plik odpowiednio do bieżącej wersji i wersji przychodzących.

Jeśli zrobiłeś git checkout --ours some_filelub git checkout --theirs some_filechciałbyś zresetować plik do wersji 3-kierunkowej, możesz to zrobić git checkout --merge some_file.

Joshua Ryan
źródło