Почему коммиты 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 этого не делает.

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


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'

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

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.


2

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

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

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

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

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

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

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

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