Вы никогда не можете ожидать слияния от одного diff
Чтобы увидеть результат слияния, вам нужны два сравнения1.
Вам также нужно найти базу слияния (или попросить Git сделать это за вас). Это связано с тем, что слияние — это объединение изменений, а чтобы объединить изменения двух людей, мы должны найти общее место, с которого они оба начали. Эта отправная точка позволяет нам (или Git) выяснить, «что сделали мы» и «что сделали они».
Затем вы можете запустить два дифференциала: git diff merge-base tip1 и git diff merge-base tip2. Выполнение слияния — это «слияние» как глагол — затем объединит эти два различия в одно большое изменение, которое применяется к базе слияния.
Эквивалентно, вы можете думать об этом так: найдите элементы во втором различии, которых еще нет в первом различии, и добавьте их к результату применения первого различия, т. е. к tip1. Это предполагает, что вы собираетесь сделать новое слияние как фиксацию, расширяющую tip1.
Например, если вы находитесь в ветке main и выполняете слияние в ветке fix, tip1 — это идентификатор фиксации main, а tip2 — идентификатор фиксации fix. решает. Как только слияние (как глагол) завершится, вы сделаете новую фиксацию слияния — это «слияние» как прилагательное — на main, так что main теперь будет называть новую фиксацию слияния, которую вы только что сделали. Содержимое нового слияния («слияние» как существительное, означающее «слияние фиксации») создается с помощью процесса слияния как глагола, который объединяет два различия.
1В некоторых достаточно редких и сложных случаях вам потребуется больше двух, но мы их здесь не рассматриваем.
Если это сбивало с толку, я не уверен, что остальное поможет. Но в конце вас ждет награда: быстрый способ запустить git diff, чтобы получить два нужных вам различия. :-)
Определения
Поскольку вы новичок в Git, давайте определим несколько элементов. Они, вероятно, достаточно знакомы, но хорошо иметь конкретные определения.
дерево — это набор файлов. Дерево, над которым вы работаете, является вашим рабочим деревом (также пишется как рабочее дерево, рабочее дерево и т. д.). В вашем рабочем дереве могут быть файлы, которые не фиксируются: это неотслеживаемые файлы. Вы можете заставить Git «игнорировать» (перестать жаловаться) некоторые из этих неотслеживаемых файлов, а также не добавлять их автоматически для отслеживания и фиксации, когда вы используете git add . или git add -A или тому подобное. (Неотслеживаемые файлы не имеют значения для сравнения и слияния, я просто упомянул их для полноты картины.)
Коммит — это постоянный, неизменный снимок дерева, который поставляется вместе с некоторыми столь же постоянными, столь же неизменяемыми метаданными: чье-то имя и адрес электронной почты, отметка времени, сообщение журнала и понятие "родительского" коммита или, для коммитов слияния, двух родителей.2
Чтобы сделать новую фиксацию, вы используете индекс Git, который также называется "областью подготовки" и "кэшем". По сути, это место, где вы создаете следующий коммит. Он начинается с текущей фиксации, и вы обновляете в нем файлы или добавляете новые с помощью git add; затем git commit превращает индекс в новое дерево моментальных снимков, добавляет метаданные коммита, добавляя ваше имя и адрес электронной почты, «сейчас» в качестве метки времени и ваше сообщение журнала.
Каждый коммит имеет уникальный хэш-идентификатор, например d5c49eb32e898663a8e2c396739d831733e945c2. Они слишком большие и уродливые для людей, поэтому мы либо сокращаем их, либо даем им имена. Существует множество форм для имен, но самое главное, что они всегда разрешаются в хэш-идентификатор. Это «настоящие имена».
Всегда есть 3 текущая фиксация, которую вы можете назвать, используя имя HEAD. Обычно HEAD на самом деле содержит имя ветки, а не необработанный хэш-идентификатор фиксации, а имя ветки содержит фактический хэш-идентификатор.
родительский любой новый коммит — это коммит, который был текущим на момент запуска git commit. То есть родителем нового коммита является то, что HEAD было, а затем HEAD принимает новый идентификатор нового коммита. Это верно даже для новых коммитов слияния, даже если у них должно быть как минимум два родителя. Первый и «главный» родитель от HEAD; остальные — из того, что вы объединили.
Вот как Git формирует настоящие ветки. Имена веток эфемерны и существуют только до тех пор, пока вам не все равно. держать их рядом. коммиты постоянны и неизменны, и каждый коммит записывает своего родителя (или родителей)... поэтому мы можем объединить коммиты, работая в обратном порядке, начиная с последнего коммита. .
2Технически два или больше. Фиксация слияния с тремя или более родительскими элементами называется слиянием осьминога. Однако они не делают ничего такого, чего нельзя было бы сделать при обычном слиянии.
Кроме того, к коммитам прикреплены две тройки имя-адрес-почта-временная метка: автор и коммиттер. Для коммитов, которые вы делаете сами, нет такой большой разницы, но для коммитов, которые перебазируются, объединяются или отправляются по электронной почте в виде патчей или чего-то еще, эти отдельные «кто и когда написал этот коммит» от «кто фактически поместил его в репозиторий, и когда".
3Из этого правила есть одно исключение. Очевидно, что в новом, пустом репозитории вообще нет коммитов, поэтому не может быть "текущим коммитом". Git обобщает это до чего-то, что непоследовательно называется либо ветвью-сиротой, либо нерожденной ветвью, в которой HEAD содержит имя ветки, но само имя ветки больше нигде не существует. . Создание новой фиксации в этом состоянии фактически создает имя ветки. Новая фиксация является корневой фиксацией без родителей. После этого это странное неопределенное состояние разрешается, и новые коммиты получают родительские коммиты, как обычно.
Git рисует графики задом наперед; найти базу слияния
Все это означает, что Git (и мы) должны рисовать наши графики с именами веток в конце «новейшей фиксации», указывая на конечную фиксацию каждой ветки. Когда я рисую их горизонтально, я делаю это так:
o <- o <-- master
Здесь имя master указывает на второй и последний ("tip") коммит в ветке master. Этот коммит указывает на первый коммит. Первая фиксация, разумеется, не имеет предыдущей фиксации, поэтому это корневая фиксация, и на этом мы можем остановиться.
Внутренние стрелки назад в большинстве случаев не имеют большого значения, поэтому вместо всего этого я просто рисую эти графики в виде:
o--o--*--o--o <-- master
\
o--o--o <-- fix
Более новые коммиты, как и прежде, находятся справа, поэтому master и fix, которые являются именами ветвей, указывают на верхние фиксации соответствующих фрагментов графа ветки.
В данном случае я отметил один конкретный коммит *. Это ближайшая общая фиксация, когда мы начинаем с обоих советов и работаем в обратном направлении. То есть это первая — в обратном порядке работы Git — коммит в обе ветки. (В терминах теории графов это младший общий предок двух вершин в ориентированном графе, хотя и здесь дуги Git имеют обратный от обычного стиля.)
В любом случае, эта "самая последняя общая фиксация" является фактическим определением базы слияния. В некоторых сложных графах может быть более одной базы слияния, но в простых случаях разветвления и повторного соединения, таких как этот, есть только одна база слияния.
Найти базу (или базы) слияния легко, если у вас есть хороший чистый рисунок графика. Сложные или беспорядочные графики усложняют задачу. Однако у Git есть команда для поиска базы (баз) слияния конкретных коммитов:
git merge-base master fix
Что это делает, так это разрешает master его фиксацию (конец master) и fix его фиксацию (конец fix), а затем проходит граф по мере необходимости, чтобы найти базу слияния.
(Если есть несколько баз слияния, он выбирает одну и печатает ее. Чтобы увидеть все, добавьте --all. Обычно в любом случае есть только одна.)
Быстрый способ просмотра различий на базе слияния
Предположим, вы хотите посмотреть, какие изменения git merge будут объединены при объединении master и side. Вы можете сделать это:
$ git merge-base --all master fix
face0ff1234567... # some big ugly hash
$ git diff face0ff master # see what we changed
$ git diff face0ff fix # see what they changed
Но git diff имеет встроенный способ автоматического поиска базы слияния, используя три точки для разделения имен веток:
$ git diff fix...master # see what we did
$ git diff master...fix # see what they did
Это зависит от того, что процесс поиска базы слияния симметричен: база слияния master и fix является такой же фиксацией, что и база слияния fix и master. Таким образом, независимо от того, как мы перевернем две стороны, мы получим одно и то же основание. Затем Git сравнивает эту базу с фиксацией, указанной справа от этого выражения fix...master или master...fix.
Стоит отметить, что этот синтаксис A...B применим и к git log. Однако в данном случае это означает нечто иное, чем git diff. Обычно A...B означает: Найти каждую фиксацию, достижимую из A, и каждую фиксацию, достижимую из B, а затем отбрасывать каждую фиксацию, достижимую из как A, и B. em> То есть получается симметричная разность (в терминах теории множеств). Но git diff может просматривать только два коммита, а не весь набор; поэтому он крадет этот синтаксис, чтобы означать что-то другое, что полезно для git diff.
person
torek
schedule
20.12.2016