Каково точное значение «наших» и «их» в git?


323

Это может звучать как слишком простой вопрос, но я искал ответы, и теперь я в замешательстве, чем раньше.

Что означают «наши» и «их» в git при объединении моей ветви с другой веткой? Обе ветви "наши".

В конфликте слияния всегда отображается "наша" верхняя из двух версий?

Всегда ли наша относится к ветви, на которую указывал HEAD, когда началось слияние? Если так, то почему бы не использовать ясную притяжательную ссылку, такую ​​как «текущая ветвь», вместо использования притяжательного местоимения, такого как «наше», которое является неоднозначным (поскольку обе ветви технически являются нашими)?

Или просто использовать название ветви (вместо того, чтобы сказать «наш», просто сказать «местный мастер» или что-то подобное)?

Самая запутанная часть для меня, если я укажу в файле .gitattributes определенной ветви. Допустим, в тестовой ветке у меня есть следующий файл .gitattributes:

config.xml merge=ours

Теперь я проверяю и указываю HEAD, чтобы освоить, а затем слить в тесте . Поскольку мастер - наш, а тестовые .gitattributes не проверены, будет ли он иметь эффект? Если это действительно имеет эффект, так как мастер теперь "наш", то что произойдет?

Ответы:


375

Я подозреваю, что вы здесь запутались, потому что это в корне запутанно. Что еще хуже, весь наш / их материал меняет роли (становится задом наперед), когда вы делаете ребазинг.

В конечном счете, во время git merge, филиал «наш» относится к отрасли вы сливаясь в :

git checkout merge-into-ours

и ветвь "их" относится к (единственной) ветке, которую вы объединяете:

git merge from-theirs

и здесь «наши» и «чужих» имеет некоторый смысл, так как даже если «их», вероятно , ваш так или иначе, «их» не один ты на когда вы запускали git merge.

Хотя использование фактического имени ветки может быть довольно классным, оно разваливается в более сложных случаях. Например, вместо вышеупомянутого вы можете сделать:

git checkout ours
git merge 1234567

где вы сливаетесь по необработанному коммит-идентификатору. Хуже, вы даже можете сделать это:

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

в этом случае нет ни одного названия филиалов , участвующего!

Я думаю, что это мало поможет, но на самом деле в gitrevisionsсинтаксисе вы можете ссылаться на отдельный путь в индексе по номеру во время конфликтующего слияния

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

Стадия № 1 является общим предком файлов, стадия № 2 - версия целевой ветви, а стадия № 3 - версия, с которой вы объединяетесь.


Причина, по которой понятия «наш» и «их» меняются местами, rebaseзаключается в том, что ребаз работает, выполняя серию «вишенок», в анонимную ветвь (режим отсоединенного HEAD). Целевая ветвь - это анонимная ветвь, а ветвь слияния - это ваша исходная ветвь (pre-rebase): так что «--ours» означает, что анонимный ребаз строит, а «--theirs» означает «наша ветвь перебазируется» ,


Что касается записи gitattributes: она может иметь эффект: «наш» действительно означает «использовать этап # 2» внутри. Но, как вы заметили, в данный момент он на самом деле не на месте, поэтому он не должен иметь здесь никакого эффекта ... ну, если вы не скопируете его в рабочее дерево перед началом работы.

Кроме того, кстати, это относится ко всем нашим и их использованию, но некоторые находятся на уровне целого файла ( -s oursдля стратегии слияния; git checkout --oursво время конфликта слияния), а некоторые - по частям ( -X oursили -X theirsво время -s recursiveслияния). Что, вероятно, не поможет ни с какой путаницей.

Я никогда не придумал лучшего названия для них. И: см . Ответ VonC на другой вопрос, где git mergetoolвводятся еще несколько имен для них, называя их «локальными» и «удаленными»!


28
+1. О наших и их обращении во время ребазинга см. Также: stackoverflow.com/a/2960751/6309 и stackoverflow.com/a/3052118/6309
VonC

1
Две вещи «сливаются» друг с другом. Когда происходит слияние, обе стороны сливаются друг с другом. Я чувствую, что было бы неправильно говорить, что одна из двух сторон «не сливается ни с чем». Если не задействованы имена ветвей (как вы указали), тогда будут задействованы имена коммитов (вы можете сказать «7777777» и «1234567» вместо «наши» и «их»). Я понимаю, что происходит во время перебазирования, и я не нахожу это в замешательстве. Я думаю, что «ГОЛОВА» и «входящие» будут работать лучше, чем «наши» и «их», потому что всегда есть «ГОЛОВА» (независимо от того, отсоединена она или нет).
CommaToast

15
Я полагаю, так как голова - это место ума, которое является источником идентичности, которая является источником себя, имеет больше смысла думать о том, на что указывает ГОЛОВА как «моя» («наша», так как Я предполагаю, что и ГОЛОВА делает два). Если не более того, это будет просто мнемоническое устройство.
CommaToast

1
При этом я все еще хотел бы сделать физическую копию всего репо, прежде чем делать что-либо вроде перебазирования ...: D
CommaToast

3
msgstr "в этом случае имена ветвей не задействованы!" ... Так что вместо этого следует использовать комментарий комментирования / хэш. Все, что он может получить в свои руки. Практически все было бы лучше, чем «наши» и «их». Интересно, сколько тысяч часов разработки испарилось? ответ git на «самый неприятный разбор» C ++;)
Джаррод Смит

49

« Наши » в Git относятся к оригинальной рабочей ветке, которая имеет авторитетную / каноническую часть истории Git.

« Их » относится к версии , которая держит работу для того , чтобы быть нормированной (изменения , чтобы быть воспроизведено на текущую ветвь).

Это может показаться заменой людям, которые не знают, что перебазирование (например git rebase) фактически приостанавливает вашу работу (которая принадлежит им ), чтобы воспроизвести каноническую / основную историю, которая принадлежит нам , потому что мы перебираем нашу меняется как сторонняя работа.

Документация для git-checkoutбыла дополнительно разъяснена в Git> = 2.5.1 в соответствии с f303016коммитом :

--ours --theirs

При проверке путей из индекса, проверьте этап № 2 («наш») или № 3 («их») для необработанных путей.

Обратите внимание, что во время git rebaseи git pull --rebase, «наши» и «их» могут выглядеть поменялись местами; --oursдает версию из ветви, на которую были перебазированы изменения, а --theirsверсию из ветви, которая содержит вашу работу, которая перебазируется.

Это связано с тем, что rebaseон используется в рабочем процессе, который обрабатывает историю на удаленном сервере как общую каноническую и рассматривает работу, выполненную в ветви, которую вы перебираете, как работу третьей стороны, которую нужно интегрировать, и вы временно принимаете на себя роль Хранитель канонической истории во время перебазирования. Как хранитель канонической истории, вам необходимо просматривать историю с удаленного компьютера как ours(то есть «нашу общую каноническую историю»), в то время как то, что вы делали на своей боковой ветке, как theirs(т.е. «работа одного участника поверх него»).

Ибо git-mergeэто объяснить следующим образом:

наш

Эта опция заставляет конфликтующие фрагменты автоматически разрешаться автоматически в пользу нашей версии. Изменения в другом дереве, которые не конфликтуют с нашей стороной, отражаются на результате слияния. Для бинарного файла все содержимое взято с нашей стороны.

Это не следует путать с нашей стратегией слияния, которая даже не смотрит на то, что вообще содержит другое дерево. Он отбрасывает все, что делало другое дерево, заявляя, что наша история содержит все, что в нем произошло.

их

Это противоположность нашей.

Более подробно, здесь объясняется, как их использовать:

Механизм объединения ( git mergeи git pullкоманды) позволяет выбирать стратегии объединения с -sопцией. Некоторые стратегии также могут иметь свои собственные опции, которые можно передать, указав -X<option>аргументы git mergeи / или git pull.


Так что иногда это может сбивать с толку, например:

  • git pull origin masterгде -Xoursнаш местный, -Xtheirsэто их (удаленный) филиал
  • git pull origin master -rгде -Xoursих (удаленный), -Xtheirsнаш

Таким образом, 2-й пример противоположен 1-му, потому что мы перемещаем нашу ветку поверх удаленной, поэтому наша отправная точка является удаленной, а наши изменения рассматриваются как внешние.

Похоже на git mergeстратегии ( -X oursа -X theirs).


2
этот ответ кажется устаревшим => «git merge --ours» недопустим
Александр Миллс

@AlexanderMills Ответ не говорил о git merge, но git pullи git checkoutкак пример. Если вы хотите использовать этот параметр с git merge, вы должны использовать -X ours. Вы все еще можете использовать --oursсинтаксис для git checkout. Я уточнил ответ еще больше.
Кенорб

46

Я знаю, что на этот вопрос уже дан ответ, но эта проблема смущала меня так много раз, что я создал небольшой справочный сайт, чтобы помочь мне вспомнить: https://nitaym.github.io/ourstheirs/

Вот основы:

Слияния:

$ git checkout master 
$ git merge feature

Если вы хотите выбрать версию в master:

$ git checkout --ours codefile.js

Если вы хотите выбрать версию в feature:

$ git checkout --theirs codefile.js

Rebases:

$ git checkout feature 
$ git rebase master 

Если вы хотите выбрать версию в master:

$ git checkout --ours codefile.js

Если вы хотите выбрать версию в feature:

$ git checkout --theirs codefile.js

(Это для полных файлов, конечно)


1
Этот сайт очень полезен. Стиль блок-схемы и слова с цветовой кодировкой значительно упрощают понимание веб-сайта, чем ответы SO. Спасибо.
Рон

10
  • Наши : Это та ветка, в которой вы сейчас находитесь.
  • Theirs : Это другая ветвь, которая используется в вашем действии.

Так что, если вы находитесь на выпуске ветки / 2.5 и объединяете в нем функцию / новые кнопки ветки , то контент, найденный в выпуске / 2.5, - это то, к чему относится наш, и контент, найденный на функции / новые кнопки, - то, к чему они относятся к. Во время действия слияния это довольно просто.

Единственная проблема, к которой относится большинство людей - это случай перебазирования . Если вы сделаете повторную базу вместо обычного слияния, роли поменяются местами. Как это? Ну, это вызвано исключительно тем, как работает перебазировка. Подумайте о rebase, чтобы работать так:

  1. Все коммиты, которые вы сделали со времени последнего пулла, перемещены в собственную ветку, назовем ее BranchX .
  2. Вы извлекаете заголовок вашей текущей ветки, отбрасывая все локальные изменения, которые у вас были, но таким образом извлекаете все изменения, которые другие подтолкнули к этой ветке.
  3. Теперь каждый коммит на BranchX выбирается по порядку, от старого к новому в вашей текущей ветке.
  4. BranchX снова удаляется и, следовательно, никогда не будет отображаться ни в одной истории.

Конечно, это не совсем то, что происходит, но это хорошая модель для меня. И если вы посмотрите на 2 и 3, вы поймете, почему роли поменялись местами. Начиная с 2, ваша текущая ветвь теперь является веткой с сервера без каких-либо изменений, так что это наша (ветвь, в которой вы находитесь). Внесенные вами изменения теперь относятся к другой ветви, отличной от вашей текущей ( BranchX ), и, таким образом, эти изменения (несмотря на то, что вы сделали изменения) принадлежат им (другая ветвь, используемая в вашем действии).

Это означает, что если вы объединяетесь и хотите, чтобы ваши изменения всегда побеждали, вы должны указать git всегда выбирать «наши», но если вы сделаете ребаз и хотите, чтобы все ваши изменения всегда побеждали, вы скажете git всегда выбирать «их».


3

Я знаю, что это не объясняет смысла, но я сделал себе небольшое изображение, чтобы напомнить, какой использовать:

введите описание изображения здесь

Надеюсь, поможет!

PS - Проверь также ссылку в ответе Нитья 🙂


3

Я опубликую свою записку здесь, потому что я должен возвращаться сюда снова и снова.

СЦЕНАРИЙ 1. Обычный разработчик: вы - разработчик, который не может объединяться masterи должен играть featureтолько с ветками.

Случай 1: хозяин - король Вы хотите обновить свою featureветку (= rebase to master), потому что она masterсодержит новые обновления зависимостей и вы хотите перезаписать свои скромные изменения.

git checkout master
git pull

git checkout feature
git rebase -X ours master

Случай 2: ты король. Вы хотите изменить свою featureветку на masterизменения. Но вы сделали больше, чем ваши коллеги, и хотите использовать свои собственные изменения в приоритете.

git checkout master
git pull

git checkout feature
git rebase -X theirs master

ВАЖНО: Как видите, нормальные разработчики должны предпочитать rebaseи повторять это каждое утро, как упражнения / кофе.

СЦЕНАРИЙ 2. Объединение сэнсэя: Вы являетесь руководителем группы и хотите объединить другие ветви и передать объединенный результат непосредственно мастеру. masterэто ветка, которую вы измените.

Случай 1: мастер - это король. Вы хотите объединить стороннюю ветку, но masterэто приоритет. featureэто ветка, которую сделал ваш старший.

git checkout feature
git pull

git checkout master
git merge -X ours master

Случай 2: новые изменения - король Когда ваш старший разработчик выпустил классную версию featureи вы хотите перезаписать старый s ** t в masterветке.

git checkout feature
git pull

git checkout master
git merge -X theirs master

ПОМНИТЕ: Для того, чтобы помнить , в полночь , который один на выбор: masterесть oursВСЕГДА. И theirsэто, featureчто их сделали.


2

От git checkoutиспользования:

-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

При разрешении конфликтов слияния вы можете сделать git checkout --theirs some_fileи git checkout --ours some_fileсбросить файл до текущей версии и входящих версий соответственно.

Если вы сделали git checkout --ours some_fileили git checkout --theirs some_fileхотите сбросить файл до трехсторонней версии файла слияния, вы можете это сделать git checkout --merge some_file.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.