Как стать автором
Обновить

Комментарии 33

Так что теперь нельзя будет вливать develop в свою ветку без геморроя? Или я чего-то недопонял?
Все можно. Просто по умолчанию теперь оно будет просить отредактировать сообщение коммита (как при git commit после разрешения конфликта в merge). Это поведение можно подавить ключом --no-edit или переменной окружения MERGE_AUTOEDIT.

Основная задумка — заставить людей писать почему они делают тот или иной merge (не все направления слияний одинаково полезны)

Почему это важно — новое поведение по-умолчанию может сломать старые скрипты
Ага. Ну в принципе да, полезная фича. Особенно если кодер вливает соседнюю ветку (если вливаемая ветка не develop) в свою — мне как проверяющему коммиты\мержи\и т.п. было бы интересно узнать зачем чел это сделал.
Да. А еще может люди задумаются, что иногда сделать, к примеру rebase своей фичи полезнее чем мерджить апстрим в нее
а чем полезнее-то? Ну вот делаю я изменения в file1 который зависит от кода в file2 и file3 и тут народ наделал изменений в file2 допустим и замерджил изменения в общую ветку. И я тогда мерджу общую ветку себе и имею измененный file2. Что ж тут неправильно-то? И что мне в этом случае даст rebase?
Основная идеология работы с ветками — каждая ветка содержит «чистую» одну единицу функциональности. Т.е. то что кто-то в file2 внес изменения, не нужные для работы вашей функциональности не является поводом для слияния.

В то же время человеку осуществляющему merge вашей ветки с апстримом может быть сложно разрешить конфликты (т.к. он не знает вашего кода). В таком случае полезно делать rebase вашей ветки относительно общей, чтобы сохранялись два принципа:
1. В вашей ветке — только коммиты относящиеся к новой одной единице функциональности
2. Ветка без проблем может быть влита в мастер
«каждая ветка содержит «чистую» одну единицу функциональности» — да, да. Тут я понял и со всем могласен. А как быть со случаем когда каждая ветка содержит «чистую» одну единицу функциональности, но только над одной единицей функциональности работает, допустим, 3 человека?
Ну это же гит, ё-маё! Он же ДЕцентрализованный. И никто не запрещает этим разработчикам обмениваться апдейтами напрямую. И только когда функционал готов — кто-то один из них отсывает (ветку/набор патчей/pull request — подставить нужное) тимлиду или кто там у вас главный.

Горячо рекумендую — посмотрите «Linus Torvalds on Git». Оно есть и с русским переводом если что, но в оригинале есть непередаваяемя экспрессия в речи Линуса. В своё время, лично мне именно это видео дало наибольший толчок в понимании гита.
Ну как вегда — rebase даёт «красивую» историю коммитов, не более того.
Кстати, одно из неудобных вещей в git, это то, что когда из master-ветки вливаются изменения в «функциональную» (как бы это ни было неправильно, это часто необходимо), потом просмотр истории коммитов «фукнциональной» ветки (например, в веб-интерфейсе) теряет смысл. Ибо он, действительно, представляет собой свалку несвязанных между собой коммитов. Я плохо знаю устройство git'а изнутри, поэтому не знаю возможно ли это, но было бы неплохо иметь возможно смотреть «чистую» историю ветки. То есть, чтобы показывались коммиты, совершенные только непосредственно в этой ветке.
К сожалению так сделать нельзя. «Ветка» в git — это просто именованный указатель на какой-то коммит (голова ветки). Вычислить принадлежность того или иного коммита в истории этой ветки к «самой ветке» архитектурно невозможно.
Поскольку у нас над «функциональными» ветками обычно работает 1 человек, мы просто делаем rebase ветки относительно апстрима
Это было бы возможно, если бы в каждом коммите была некая запись, которая сохраняла название «оригинальной» ветки, в которой был совершен коммит. Такая запись влияла бы только на просмотр истории изменений. Интересно, почему разработчики так не сделали.
Насколько я понимаю, так работают тэги в меркуриале — крутые бранчи )
Не только теги, named branches (то есть обычные неанонимные ветки) работают так же.
Сколько пользуюсь гитом, а что такое rebase так и не разобрался :)
Rebase, мне кажется, проще всего понять, если понаблюдать за тем, как именно он происходит, т.е. за сообщениями, которые выдаёт Гит. В двух словах, rebase ветки feature на ветку master — это:
1. Переместить указатель feature на master.
2. Применить все коммиты, которые были в feature и не были в master, один за другим, как патчи. Одновременно двигать указатель feature.

Этим и достигается линейность истории — одна из основных причин использования rebase вместо merge.

Довольно хорошо rebase расписан в популярной книге Pro Git: progit.org/book/ch3-6.html
(Есть и русская онлайн версия книги)
А rebase патчи жестко накладывает на основную ветку или нет? Опишу ситуацию: ветвимся, в масетере в file1 есть код. Мы с воей ветке резвимся и правим этот код. Кто-то раньше нас вливает в мастер изменения и file1 немного поменялся. И тут мы делаем rebase. Файл умело сольется, как это происходит при мердже или будет заменен нашим патчем?

Если 2 вариант, то rebase не такой уж и безобидный.
rebase — это тот же merge, просто записывается в историю он так, чтобы история выглядела линейной. Поэтому разрешение конфликтов никто не отменял — если гит не сможет разрулить ваш конфликт автоматически, он попросит вас сделать это вручную.

Ну а вообще я бы рекомендовал перед любыми операциями, которые переписывают историю, делать копию вашего локального репозитория рядом (на всякий случай). Особенно если вы только что познакомились с rebase и еще не знаете, как отменить неудачный rebase, а плюс к этому всему в вашем репозитории много новейших коммитов, бакапа которых нигде нет.
> делать копию

Зачем копию?
Это ж git!

git br saved_branch

И работайте с вашей текущей веткой как хотите.
Ну, я гитом практически не пользуюсь, чтобы такие тонкости знать, да и скопировать папку целиком как-то надежнее поначалу :)
Если репозиторий занимает более гигабайта, это нереально.
А вообще, даже сохранять указатель на бранч не обязательно — есть reflog, в котором все ходы прописаны.
Что значит «будет заменен нашим патчем»? Вероятно, у вас неверное понимание того, как гит работает.

Во-первых, rebase работает с любыми ветками. Всё зависит только от ваших потребностей и фантазии.

Во-вторых, гит не работает «файлами», и потому ничего не будет «замещаться». Гит работает чендж-сетами — фактически, это набор изменений в наборе файлов. Т.е. такой себе монолитный, неразрывный патч, обо всех изменениях в конкретном коммите.

Для освежения памяти (вы же прочитали man по rebase, верно?...) — позволю себе утащить оттуда картинку:

# было
         A---B---C topic
        /
    D---E---F---G master

# любая из этих команд приведёт к ....
git rebase master
git rebase master topic

# стало
                 A'--B'--C' topic
                /
    D---E---F---G master



Когда делается rebase, то гит последовательно для всех указанных вами коммитов (т.е. фактически — чендж-сетов) — в данном случае: A, B, C — делает cherry-pick на временную ветку (назовём её topic'), и когда процесс закончится — ваша ветка удаляется, а временная переименовывается в используемое ранее имя.

По сути своей, cherry-pick — это тот же merge, но не со всей веткой от указанного коммита, только с одним, явно указанным чендж-сетом. Как и при любом другом слиянии, тут могут возникнуть конфликты. И если вы меняли file1, а кто-то в master'е менял этот же файл в тех же строках — конфликт будет, как и всегда в таких случаях. Если же чендж-сет в master'е для коммита с изменениями в file1 не пересекается с вашим чендж-сетом, то слияние будет беспроблемным.

А по поводу безобидности… Ну вы же слияния делаете, и опасными их не считаете? Так тут по сути то же самое. Хотя как и везде — обязательно найдётся кто-то, кто оправдает поговорку про «и #$% разобъёт, и руки порежет» :)

Надеюсь, это прольёт свет на ваши вопросы.
Спасибо. Общий принцип rebase я знал и знаю, но вот интересовали тонкости. С гитом тоже уже довольно давно знаком и работаю.
Можно сделать git log branch1..branch2 — тогда будут показаны только те коммиты ветки branch2, которые не присутствуют в ветке branch1.
Но, вроде бы, ничего не покажется если в branch2 только-что вливали branch1.
Покажутся те коммиты, которых нет в branch1. Не важно, были ли они сделаны до или после «вливания».

Из «man git-log»:
"
git log release..test
Show the commits that are in the «test» branch but not yet in the «release» branch
"
> Я плохо знаю устройство git'а изнутри…

Символично…
Ваш ник какбэ намекает ;)
git merge options:
-m Set the commit message to be used for the merge commit (in case one is created)

Или это не то?
И да и нет. Ключ -m позволяет заранее задать сообщение для merge-коммита. Поведение по-умолчанию — создать стандартное сообщение.
Теперь же если -m (или -no-edit) не указано, поведение по-умолчанию — вывести редактор для создания соощения
Понятно. Спасибо
Здравая вещь. Мне всегда было странно почему, merge не является причиной для commit. Теперь все по-уму.
> merge не является причиной для commit

Это как?!?! Ещё как является! Просто раньше сообщение к коммиту подставлялось уже готовое, и редактор для него не вызывался — потому коммит проходил тихо и незаметно. Чтоб поменять это сообщение (что за всё время работы с гитом мне понадобилось сделать ровно один раз) — нужно было сразу после git merge явно делать git commit --amend, и менять сообщение вручную. Теперь просто поменяли поведение по умолчанию, и git merge будет подставлять точно такое же сообщение, как и раньше, и сразу, до фиксации коммита, будет вызывать редактор. Вам решать — менять его или нет. И только после этого будет зафиксирован коммит.

> Здравая вещь.
Кому как. Меня текущее поведение устраивало в 99.999% случаев, и этот (теперь) обязательный вызов редактора для меня просто лишняя трата времени. Так что надо будет сконфигурить алиас в ~/.gitconfig для вызова merge --no-edit.
Ох и весело щас будет ребятам из git-flow одновременно поддерживать два разных поведения системы контроля версий. :)
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории