Почему коммиты git не содержат название ветки, на которой они были созданы?

20

При работе с git в команде, использующей ветви функций, мне часто трудно понять структуру ветвей в истории.

Пример:

Допустим, была ветка Feature / Make-Coffee , и исправление ошибок продолжалось на master параллельно с веткой Feature.

История может выглядеть так:

*     merge feature/make-coffee
|\
| *   small bugfix
| |
* |    fix bug #1234
| |
| *    add milk and sugar
| |
* |    improve comments
| |
* |    fix bug #9434
| |
| *    make coffe (without milk or sugar)
| |
* |    improve comments
|/
*

проблема

На первый взгляд, мне трудно сказать, с какой стороны находится ветвь функции. Мне обычно нужно просмотреть несколько комментариев с обеих сторон, чтобы понять, что есть что. Это становится более сложным, если есть несколько ветвей объектов параллельно (особенно если они предназначены для тесно связанных объектов), или если произошло объединение в обоих направлениях между ветвью объекта и мастером.

В отличие от этого, в Subversion это значительно проще, потому что имя ветки является частью истории, поэтому я могу сразу сказать, что изначально была сделана фиксация на «feature / make-coffee».

Git может упростить эту задачу, включив имя текущей ветви в метаданные коммита при создании коммита (вместе с автором, датой и т. Д.). Однако git этого не делает.

Есть ли какая-то фундаментальная причина, почему это не сделано? Или это просто, что никто не хотел эту функцию? Если это последнее, есть ли другие способы понять цель исторических ветвей, не видя названия?

sleske
источник
1
Смежный вопрос: найти ветку коммита . Речь идет о том, как найти эту информацию, несмотря на то, что git не записывает ее явно.
Слёске
1
Примечание для себя: Интересно, что в Mercurial фиксация действительно содержит имя ветви. Так что, похоже, разработчики Mercurial приняли другое дизайнерское решение, чем разработчики git. См. Например, felipec.wordpress.com/2012/05/26/… для получения подробной информации.
Слеське

Ответы:

14

Возможно, потому что имена ветвей имеют смысл только в одном хранилище. Если я в make-coffeeкоманде и отправляю все свои изменения через привратник, моя masterветвь может быть перетащена в ветвь привратника make-coffee-gui, которую он объединит со своей make-coffee-backendветвью, прежде чем перейти к make-coffeeветке, которая объединится с центральной masterветвью.

Даже в одном репозитории имена ветвей могут изменяться и изменяться по мере развития вашего рабочего процесса. masterможет позже измениться development, например, на вызов .

Как отмечал CodeGnome, у git есть сильная философия дизайна, заключающаяся в том, чтобы не запекать что-либо в данные, если это не нужно. Ожидается, что пользователи будут использовать параметры git logи git diffвыводить данные по своему усмотрению после факта. Я рекомендую попробовать, пока вы не найдете формат, который работает лучше для вас. git log --first-parentНапример, не будет отображать коммиты из ветки, в которой происходит слияние.

Карл Билефельдт
источник
2
Следует отметить, однако, что первый родитель обычно не тот. Потому что обычно кто-то просто втягивает мастера в то, над чем он работает, и выталкивает, делая свою работу первым родителем, а мастер вторым.
Ян Худек
1
@JanHudec: На самом деле, это зависит :-). Если человек, выполняющий работу, объединяет ее, тогда да. Если слияние происходит позже, может быть, после рецензирования, то, скорее всего, рецензент извлек мастер и объединяет ветвь функций в мастер, проверяет ее и отправляет.
слеске
5

Отслеживание истории веток с помощью --no-ff

В Git коммит имеет предков, но «ветвь» на самом деле является просто текущим руководителем некоторой линии разработки. Другими словами, коммит является моментальным снимком рабочего дерева в определенный момент времени и может принадлежать любому количеству ветвей одновременно. Это часть того, что делает ветвление Git таким легким по сравнению с другими DVCS.

Коммиты Git не несут информацию о ветвях, потому что они не нужны для истории Git. Тем не менее, слияния, которые не являются ускоренными, могут, безусловно, содержать дополнительную информацию о том, какая ветвь была объединена. Вы можете убедиться, что ваша история содержит эту информацию, всегда передавая --no-ffфлаг вашим слияниям. git-merge (1) говорит:

   --no-ff
       Create a merge commit even when the merge resolves as a
       fast-forward. This is the default behaviour when merging an
       annotated (and possibly signed) tag.

Как правило, это создает сообщение о слиянии, подобное тому Merge branch 'foo', что вы можете найти информацию о «ветвях предков» со строкой, подобной следующей:

$ git log --regexp-ignore-case --grep 'merge branch'
CodeGnome
источник
Спасибо, но это (в основном) не отвечает на мой вопрос. Я не спрашиваю, как еще можно найти оригинальную ветку, но почему информация не включена в качестве обычных метаданных - это скорее вопрос дизайна.
Слёске
1
@sleske Я думаю, что мой ответ был отзывчивым: Git не отслеживает его, потому что история Git не нуждается в нем; Я не думаю, что это становится более фундаментальным, чем это. Вам нужно было бы посмотреть на источник для уточнения, но история эффективно рассчитывается в обратном направлении от кончика текущей ветви. Вы всегда можете сравнить это с некоторыми другими DVCS, которые рассматривают ветви как первоклассные объекты, и посмотрите, нравится ли вам эта философия дизайна. YMMV.
CodeGnome
1
Последний должен быть git log --merges.
Дан
3

Самый простой ответ заключается в том, что названия ветвей эфемерны. Что если вы скажете переименовать ветку ( git branch -m <oldname> <newname>)? Что будет со всеми коммитами против этой ветки? Или что, если два человека имеют филиалы с одинаковыми именами в разных локальных репозиториях?

Единственное, что имеет значение в git - это контрольная сумма самого коммита. Это основная единица отслеживания.

Информация есть, вы просто не просите об этом, и его не совсем там.

Git хранит контрольную сумму главы каждого филиала в .git/refs/heads. Например:

... /. git / refs / head $ ls test 
-rw-rw-r-- 1 michealt michealt 41 30 сентября 11:50 тест
... /. git / refs /глав $ cat test 
87111111111111111111111111111111111111d4

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

Просматривая это и отслеживая каждый коммит, который имеет это как родитель, или родительский родитель или родительский родитель ... вы можете узнать, в каких ветвях находится данный коммит. Это просто большой график для рендеринга.

Хранение, где конкретно имя ветви (которая может измениться, как упомянуто выше) в коммите, находится в самом коммите, это дополнительные издержки на коммите, которые ему не помогают. Сохраните родительский (ые) коммит и его товар.

Вы можете увидеть ветви, выполнив команду git log с соответствующим флагом.

git log --branches --source --pretty = oneline --graph
git log --all --source --pretty = oneline --graph

Есть много разных способов выбрать то, что вы хотите для этого - посмотрите документацию git log - -allраздел и несколько опций, которые следуют.

* 87111111111111111111111111111111111111d4 test Объединить ветку 'test1' в тест
| \  
| * 42111111111111111111111111111111111111e8 test1 обновление: добавить материал
* | dd11111111111111111111111111111111111159 test Объединить ветку 'test3' в тест
| \ \  

Эти 'test', 'test1' и 'test2' являются ветвями, которым они были посвящены.

Обратите внимание, что документация журнала git огромна, и вполне возможно получить из нее практически все, что вы захотите.


источник
3

Почему коммиты git не содержат название ветки, на которой они были созданы?

Просто дизайнерское решение. Если вам нужна эта информация, вы можете добавить ловушку prepare-commit-msg или commit-msg, чтобы применить ее к одному репозиторию.

После аварии на BitKeeper Линус Торвальдс разработал git, соответствующий процессу разработки ядра Linux. Там, пока патч не принят, он пересматривается, редактируется, полируется несколько раз (все через Mail), подписывается (= редактирование коммита), выбирается вишня, бродит по ветвям лейтенанта, может быть, часто перебазируется, больше правок, вишня -выборы и так далее, пока они окончательно не слились вверх по течению от Линуса.

В таком рабочем процессе может не быть определенного источника коммита, и часто коммит просто создается в какой-то временной ветке отладки в каком-то неважном частном случайном репозитории с забавными именами ветвей, когда распространяется git.

Возможно, это дизайнерское решение произошло случайно, но оно точно соответствует процессу разработки ядра Linux.

villekulla
источник
2

Потому что в Git коммиты типа "сделать кофе" считаются частью обеих ветвей, когда ветка функции объединяется. Есть даже команда, чтобы проверить это:

% git branch --contains @
  feature/make-coffee
  master

Кроме того, филиалы дешевые, местные и эфирные; их можно легко добавлять, удалять, переименовывать, отправлять и удалять с сервера.

Git следует принципу все можно сделать, поэтому вы можете легко удалить ветку с удаленного сервера и переписать историю.

Допустим, я был в ветке «master» и сделал два коммита: «сделай кофе» и «добавь молоко и сахар», затем я решил использовать для этого новую ветку, поэтому я вернул «master» обратно в «origin» /мастер'. Не проблема, вся история по-прежнему чиста: «варить кофе» и «добавлять молоко и сахар» не являются частью мастера, только функция / приготовление кофе.

Mercurial - это противоположность; он не хочет ничего менять. Ветви постоянны, история переписывания осуждается, вы не можете просто удалить ветку с сервера.

Вкратце: Git позволяет вам делать все, Mercurial хочет упростить задачу (и делает действительно трудным позволить вам делать то, что вы хотите).

FelipeC
источник