git rebase continue что делать

Обзор Git Rebase

Удаление и перемещение коммитов в git опасны потерей данных или истории изменений. Git Rebase выполняет эти и другие операции. Владение этой командой повышает уверенность при работе с репозиторием.

Введение

Системы контроля версиями полезны, когда они могут рассказать историю всех изменений. Эта история может быть как реальный рассказ о жизни и развитии программной системы. Но может быть и кучкой коммитов, разобраться в которых нельзя и которые не несут пользы.

Вести аккуратную историю помогает команда git rebase. Основная ее цель “перетаскивать” коммиты из одного места в другое. Также с помощью нее можно избавляться от ненужных коммитов, склеивать одни и менять порядок других.

Умение пользоваться командой git rebase придает уверенности при работе с репозиторием.

Предостережение

Ребейзинг может “удалить” коммиты. Ребейзинг может испортить историю коммитов.

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

О структуре коммитов

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

Указатели на коммиты

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

Проще говоря, ветка указывает на коммит. Поэтому если ответвить 5 веток от master, то все они будут указывать на один и тот же коммит. Однако новые коммиты будут свои в каждой из веток.

Создание коммита

Каждый коммит (кроме начального) имеет родительский коммит, который для него аналог “предыдущего”. Из одного коммита может выходить несколько дочерних коммитов. Это делается с помощью ветвления. А так как ветки могут соединяться в одну, то у коммита может быть и несколько родительских коммитов. Обычно их два, но есть возможность сделать merge трех и более коммитов одновременно.

Иногда коммит бывает создан не в том месте и не в то время. Не в том месте означает, что он был создан не в той ветке, а не в то время означает, что коммит был создан, но потом ветка разработки обогатилась новым кодом и хочется пересоздать коммит, начиная с более свежего кода.

Пересоздание коммитов

Что же делать? Подтягивать изменения. Можно слить ветку develop в ветку с задачей. Безопасно, но история будет подпорчена. Делается ребейзинг

Предполагается, что develop уже содержит новые коммиты, то есть, что уже были сделаны fetch/pull.

Как работает команда git rebase? В простом случае, это работает так:

Ниже приведены три дерева коммита

Ветка с задачей исходит из актуального коммита

Код разработки обновился, ветка с задачей исходит из старого коммита

Выполнен ребейзинг, ветка с задачей исходит из актуального коммита

Стоит обратить внимание на хеш коммита до ребейзинга (8f26890) и после (3b16148). Разумеется, по старому хешу можно найти старый коммит.

Создадим ветку, указывающую на старый коммит

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

Потеря коммитов

Чтобы избавиться от риска потерять коммиты, перед ребейзингом следует создать дополнительную ветку

Простой Rebase

Формат команды такой

Но в Merge все наоборот!

Поэтому при ребейзинге придется дважды переключаться с ветки на ветку

Однако если использоваться слияние для подтягивания изменений, то сценарий похожий

Разница есть только со сценарием завершения задачи

Таким образом, для того, чтобы определить “что и куда”, надо задать вопрос “какую ветку надо изменить?”. Находиться следует в той ветке, которую надо изменить.

Интерактивный Rebase

Ребейзинг позволяет также переписывать историю своих коммитов.

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

Rebase и коммиты удаленного репозитория

Конфликты

Конфликты случаются везде, где накладываются изменения из разных мест. Это происходит при слиянии (git merge), при отмене коммитов (git revert) и даже при переключении (git checkout, git stash). Во всех командах конфликты разрешаются по общим правилам. Поэтому в ребейзинге разрешение конфликтов такое же как и при слиянии.

При слиянии создается специальный мерж-коммит, в котором хранятся все изменения, сделанные в отдельной ветке. Поэтому все конфликты разрешаются в этом же коммите. В истории хранятся все коммиты из ветки с задачей и мерж-коммит. Последний можно рассматривать как завершающий штрих.

В помощниках вроде TortoiseGit процесс разрешения конфликтов почти ничем не отличается от слияния. В консоли используются следующие команды.

Детальный Rebase

Существует еще одна форма команды ребейзинга

FROM, TO, START – хеши коммитов или названия веток/тегов. Команда копирует коммиты из диапазона FROM..TO в START.

Стандартная команда, выполненная, находясь внутри ветки feature/A/super_code

Может быть заменена на

Примеры

Необходимо скопировать последний коммит из ветки с задачей в develop

git можно указать на родительский коммит с помощью значка шапочки)

Коммит сделан в ветке feature/A, а должен был быть в ветке bug/B.

Чистая история коммитов

Рефакторинг привыкли относить только к коду, но хорошая и наглядная история коммитов в репозитории может дать больше информации разработчику. Правило бойскаута из книги “Чистый код” Роберта Мартина «оставь место стоянки чище, чем оно было до твоего прихода» применимо и к истории коммитов. Поэтому использование Git Rebase также полезно в работе с репозиторием, как инструменты рефакторинга в IDE для работы с кодом.

Читайте также:  что делать если лагает вар тандер на слабом пк

Источник

Правим историю Git с помощью интерактивного rebase

Система контроля версий — неотъемлемый инструмент в рабочем процессе любого разработчика. С его помощью вы можете сохранять состояния вашего проекта, переключаться между ними и поддерживать разработку несколькими людьми. Самой популярной системой контроля версий на текущий момент является git.

В этом посте мы не будем изучать основы git — есть множество туториалов, в том числе интерактивных. Предполагается, что вы знаете как создавать коммиты, просматривать историю и выполнять другие базовые команды. Мы займемся не самой распространенной проблемой при использовании git. Бывают ситуации, когда по невнимательности или чьей-то некомпетентности в репозитории оказывается нежелательная информация. Возможно даже, что после этого она была удалена и в текущей версии проекта ее нет, но она осталась в истории git и, откатившись к определенной версии, ее можно будет восстановить. Изменять историю мы будем с помощью git-команды rebase в режиме interactive.

Какие проблемы будем решать

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

Предостережение

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

Исправить опечатку в commit message

Для демонстрации возможностей interactive rebase я создал тестовый репозиторий, в котором буду моделировать описанные выше проблемы.

Начнем с ситуации, когда вы сделали коммит и сразу осознали, что допустили ошибку в его message:

Итак, после коммита с опечаткой было сделано несколько других изменений:

Здесь в дело вступает интерактивный rebase. Команда rebase позволяет перемещать коммиты между ветками, в данном случае мы будем их перемещать на то же самое место. А благодаря интерактивному режиму (флаг —interactive/-i), каждый из перемещаемых коммитов можно редактировать, изменяя текст сообщения, используемые файлы и их содержимое.

Необходимо вызвать rebase на коммите, предшествующем тому, в котором нужно, что-то изменить. Для этого нужно либо передать хэш этого коммита (972078a), либо насколько он отстает от текущего (HEAD

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

Вновь откроется дефолтный редактор, в котором необходимо выбрать коммиты для изменения.

Как можно увидеть, вся необходимая информация описана в этом файле. Изначально все коммиты берутся без изменений (об этом говорит слово pick). Для тех коммитов, которые требуют исправлений, замените pick на соответствующий вариант. Так как мы хотим изменить сообщение коммита 0be0764, заменим pick на reword либо в сокращенном варианте – r:

Удалить приватную информацию из файла

Допустим, в какой-то момент мы добавили в публичный доступ логин и пароль к нашему сервису. Так выглядит история:

Снова воспользуемся interactive rebase. Вызов на коммите bfe4560, откроет редактор со следующим содержимым:

У нас есть два варианта. Если коммит b94ffdb содержит и другие изменения помимо нежелательных, то следует заменить pick на edit, что означает исправление данного коммита, и переименовать коммит соответствующим образом. В случае, если это единственная правка в коммите, то его следует удалить (для этого используйте слово drop).

Исправьте состояние файла на текущем коммите:

В случае удаления коммита процесс будет аналогичным.

Избавиться от ненужных файлов

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

Для этого для начала найдем, в каких коммитах файл с логами менялся (в первую очередь нас интересует, когда он появился). Это можно сделать с помощью команды git log. Укажите путь к файлу, который ищем (используйте —follow, если файл мог быть переименован).

Теперь, зная к какому коммиту откатываться, воспользуемся интерактивным rebase.

Далее во всех коммитах, в которых этот файл изменялся, необходимо удалять его из stage-области (git reset HEAD path_to_file) и продолжать процесс. В итоге вы очистите историю от ненужного файла, а сам файл в своем конечном состоянии останется на диске.

Другие возможности interactive rebase

С помощью интерактивного rebase можно существенно изменить историю git-репозитория. Из других наиболее полезных возможностей этой команды я бы выделил объединение и разделение коммитов. Благодаря этим приемам историю можно сделать более аккуратной. С полным списком возможностей можно ознакомиться в документации.

Источник

Git Rebase: руководство по использованию

Rebase — один из двух способов объединить изменения, сделанные в одной ветке, с другой веткой. Начинающие и даже опытные пользователи git иногда испытывают нежелание пользоваться ей, так как не видят смысла осваивать еще один способ объединять изменения, когда уже и так прекрасно владеют операцией merge. В этой статье я бы хотел подробно разобрать теорию и практику использования rebase.

Теория

Итак, освежим теоретические знания о том, что же такое rebase. Для начала вкратце — у вас есть две ветки — master и feature, обе локальные, feature была создана от master в состоянии A и содержит в себе коммиты C, D и E. В ветку master после отделения от нее ветки feature был сделан 1 коммит B.

После применения операции rebase master в ветке feature, дерево коммитов будет иметь вид:

Обратите внимание, что коммиты C’, D’ и E’ — не равны C, D и E, они имеют другие хеши, но изменения (дельты), которые они в себе несут, в идеале точно такие же. Отличие в коммитах обусловлено тем, что они имеют другую базу (в первом случае — A, во втором — B), отличия в дельтах, если они есть, обусловлены разрешением конфликтных ситуаций, возникших при rebase. Об этом чуть подробнее далее.

Такое состояние имеет одно важное преимущество перед первым, при слиянии ветки feature в master ветка может быть объединена по fast-forward, что исключает возникновение конфликтов при выполнении этой операции, кроме того, код в ветке feature более актуален, так как учитывает изменения сделанные в ветке master в коммите B.

Процесс rebase-а детально

Давайте теперь разберемся с механикой этого процесса, как именно дерево 1 превратилось в дерево 2?

Напомню, перед rebase вы находтесь в ветке feature, то есть ваш HEAD смотрит на указатель feature, который в свою очередь смотрит на коммит E. Идентификатор ветки master вы передаете в команду как аргумент:

Для начала git находит базовый коммит — общий родитель этих двух состояний. В данном случае это коммит A. Далее двигаясь в направлении вашего текущего HEAD git вычисляет разницу для каждой пары коммитов, на первом шаге между A и С, назовем ее ΔAC. Эта дельта применяется к текущему состоянию ветки master. Если при этом не возникает конфликтное состояние, создается коммит C’, таким образом C’ = B + ΔAC. Ветки master и feature при этом не смещаются, однако, HEAD перемещается на новый коммит (C’), приводя ваш репозитарий состояние «отделеной головы» (detached HEAD).

Успешно создав коммит C’, git переходит к переносу следующих изменений — ΔCD. Предположим, что при наложении этих изменний на коммит C’ возник конфликт. Процесс rebase останавливается (именно в этот момент, набрав git status вы можете обнаружить, что находитесь в состоянии detached HEAD). Изменения, внесенные ΔCD находятся в вашей рабочей копии и (кроме конфликтных) подготовлены к коммиту (пунктиром обозначена stage-зона):

Далее вы можете предпринять следующие шаги:

1. Отменить процесс rebase набрав в консоли

При этом маркер HEAD, будет перенесен обратно на ветку feature, а уже добавленные коммиты повиснут в воздухе (на них не будет указывать ни один указатель) и будут вскоре удалены.

При этом, если все конфликты действительно разрешены, будет создан коммит D’ и rebase перейдет к следующему, в данном примере последнему шагу.

После применения изменений ΔDE будет создан последний коммит E’, указатель ветки feature будет установлен на коммит E’, а HEAD станет показывать на ветку feature — теперь, вы находитесь в состоянии на втором рисунке, rebase окончен. Старые коммиты C, D и E вам больше не нужны.

При этом коммиты, созданные в процессе rebase-а, будут содержать данные как об оригинальном авторе и дате изменений (Author), так и о пользователе, сделавшем rebase (Commiter):

С небес на землю — rebase в реальных условиях

На самом деле обычно вы работаете не с двумя ветками, а с четырьмя в самом простом случае: master, origin/master, feature и origin/feature. При этом rebase возможен как между веткой и ее origin-ом, например feature и origin/feature, так и между локальными ветками feature и master.

Rebase ветки с origin-ом

Если вы хотите начать работать с rebase, то лучше всего начать с ребейза своих изменений в ветке относительно ее копии в удаленном репозитарии. Дело в том, что когда вы добавляете коммит, и в удаленном репозитарии добавляется коммит, для объединения изменений по-умолчанию используется merge. Выглядит это примерно так:

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

Как поделиться веткой, к которой применен rebase, с коллегой

Тут все просто, наберите в консоли команду:

Force-режим просто копирует отсутствующие родительские коммиты ветки feature на origin и насильно устанавливает указатель ветки на тот же коммит, что и ваш локальный.

Будьте внимательны! Если вы забудете указать идентификатор ветки, то force-push будет выполнен для всех локальных веток, имеющих удаленный оригинал. При этом нужно понимать, что некоторые локальные ветки могут быть в неактуальном состоянии. То есть измененения, которые вы не успели затянуть будут удалены в origin-е. Конечно, сами коммиты не будут удалены — сбросятся только указатели ветки. Эта ситуация поправима — достаточно для каждой ветки найти человека, который последним пушил изменения в нее или уже успел их забрать. Он может сделать обычный push, вновь передав их на origin. Но вся эта морока вам ни к чему, так что лучше просто будьте внимательны.

Реинтеграция тематической ветки в master

Мы рассмотрели все необходимые операции для работы с ветками в стиле rebase. Осталось только переключиться в ветку master и сделать git merge feature. Ветка, подготовленная rebase-ом вольется в master по fast-forward, то есть указатель будет просто перемещен вперед.

В данном случае, на мой взгляд, merge-коммиты полезны и несут в себе информацию о моменте объединения веток. Этот граф выглядит как учебный пример, но такая структура вполне реальна при соблюдении некоторых простых правил всеми членами команды.

Заключение

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

В данной статье сделано одно допущение. Все это верно при простой модели ветвления — есть одна главная ветка master и несколько тематических, которые создаются от нее. Когда от тематической ветки создается другая тематическая ветка, есть свои нюансы при rebase-е первичной и вторичной ветки. О них можно прочитать в том самом официальном руководстве.

Иногда споры, что же лучше merge или rebase доходят до холивара. От себя могу сказать, что в конечном счете выбор за вами, однако этот выбор не может быть продиктован уровнем владения тем или иным инструментом. Обоснованный выбор можно сделать, только когда для вас не составит труда работать и в том и в другом стиле. Я не агитирую за повсеместное использование rebase-а, а просто объясняю как им пользоваться. Надеюсь, это статья поможет вам снять вопросы, связанные с механизмом работы rebase и его применением в ежедневной работе.

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

Источник

Переписывание истории с помощью Git Rebase

Russian (Pусский) translation by Sergey Zhuk (you can also view the original English article)

Основной рабочий процесс Git выглядит следующим образом: вы делаете задачу в отдельной ветке, затем по завершению сливаете ее в основную ветку. Это делает git merge неотъемлемым инструментом для объединения веток. Однако это не единственный инструмент, который предлагает Git.

Слияние веток объединением.

Слияние веток с помощью git rebase

Необходимые условия

Эта статья предполагает, что вы знакомы с основами Git. Вы должны уметь сохранять и фиксировать изменения, разработку задач в отдельных ветках, соединять ветки, а так же сливать и заливать ветки из удаленных репозиториев.

1. Сдвиг для получения линейной истории

Первый вариант использования, который мы будем изучать, включает в себя расходящаяся история проекта. Рассмотрим репозиторий в котором основная ветка ушла вперед, пока вы работаете над задачей в другой ветке.

Например, рассмотрим, что произойдет, если вы будете использовать слияние вместо сдвига.

Слияние коммитов, находящихся выше.

Это же можно увидеть при слиянии и в другом направлении. Без использования сдвига, слияние ветки feature в ветку master так же требует коммита слияния. Хотя это и кажется значимым коммитом (он представляет отдельную законченную задачу), в итоге история будет полна ответвлений:

Слияние законченной задачи с помощью merge

Сдвиг перед слиянием

Разрешение конфликтов

Команда git merge позволяет вам разрешить все конфликты в конце слияния, что является одной из основных целей создания коммита слияния. Однако все это происходит немного по-другому при использовании сдвига. Конфликты разрешаются после каждого коммита. Таким образом, если git rebase находит конфликт, то процедура сдвига приостанавливается и выводится сообщение с предупреждением:

Визуально вот как выглядит история проекта, когда git rebase обнаруживает конфликт:

Для разрешения конфликта следует открыть файл с конфликтами (в нашем примере это readme.txt), найти затрагиваемые строки, и вручную внести необходимые изменения. Затем сообщить Git, чтобы конфликт разрешен, зафиксировав изменения в файле:

Оставшиеся коммиты по одному будут перемещены, если снова возникнут конфликты, то следует повторить процесс их разрешения.

2. Сдвиг для очищения от локальных коммитов

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

Сжимаем второй коммит с помощью интерактивного сдвига.

3. Опасности сдвига

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

Имя это в виду, вам никогда не следует делать сдвиг коммитов, которые были залиты в публичный репозиторий, до тех пор пока вы не будете уверены, что никто их сейчас в своей работе не использует.

Заключение

Источник

Сказочный портал