Страницы

Поиск по вопросам

понедельник, 18 февраля 2019 г.

Как из некоторых снимков сделать отдельную ветку?


Есть существующая старая ветка old в которой вся история из результирующих и промежуточных снимков. Необходимо выбрать из неё только результирующие снимки и создать на их основе отдельную «чистую» ветку, например, master Решение не обязательно должно соответствовать рисункам, возможно, есть более грамотный вариант, не знаю. Рис. 1 — старая ветка. Рис. 2 — вариант со слиянием. Рис. 3 — вариант с копированием. Чёрные — результирующие снимки. Белые — промежуточные снимки.


Ответ

Как работать, чтобы такая проблема не возникала?
«Промежуточные» коммиты нужны и полезны. Очень удобно бывает сохраниться где-то посреди разработки: чтобы попробовать другое решение, чтобы перенести работу на другую машину, просто для спокойствия.
Но в итоговой истории они не очень-то интересны. Более того, я лично не хотел бы, чтобы кто-то через месяцы и годы смотрел, как я изобретал велосипеды, писал по строчке в час и делал дурацкие ошибки. Нет, я хочу один финальный коммит, как будто я сел, возложил руки на клавиатуру и создал шедевр. Возможно, вам тоже так будет удобнее.
Что делать-то?
1. Используйте фичеветки (feature branches)
Для работы над каждой задачей делайте отдельную ветку от master. Делайте в ней сколько душе угодно коммитов. Когда результат будет готов — вы сможете собрать все эти коммиты в один или несколько осмысленных (инструкция ниже) и замержить в master
Мержить рекомендую с --no-ff. Так получается более информативная история: видно, где закончились коммиты одной фичи и начались коммиты другой.
Подробнее о фичеветках Про разные модели работы, в том числе с фичеветками.
2. Пользуйтесь commit --amend для промежуточных коммитов
Исправили одну строчку в фичеветке и снова нужно сделать коммит? Проще переписать старый.
git add path/filename git commit --amend --no-edit
Здесь --no-edit означает, что мы не хотим менять сообщение коммита — оставим старое.
Важно: Нужен хотя бы один новый коммит в ветке, который вы будете переписывать. Если вы только что сделали новую ветку от master, пока что нельзя делать --amend. Иначе вы перепишете коммит из master Важно: commit --amend, rebase -i и другие операции по переписыванию истории нельзя выполнять в общих (стабильных) ветках вроде master
Как объединить коммиты по группам в новой ветке?
Предположим, у нас есть такая история коммитов. «Промежуточные» коммиты обозначены как bullshit, а «результативные» — result x. Самый новый коммит — сверху.
git log --oneline --graph --decorate
* 71e8ed5 (HEAD -> oldbranch) result 2 * 0955502 bullshit * cf30c6f bullshit * d590b3d result 1 * 8266a62 bullshit * ce5b35c bullshit
Пересобрать их в более красивую (что очень субъективно) историю нам поможет команда rebase -i
Сначала сделаем новую ветку, в которой будет результат операции.
git checkout -b newbranch
Поскольку здесь мы хотим заребейзить всю ветку целиком, добавляем --root
git rebase -i --root
Если нужно переписать историю только до какого-то коммита (не включая его), указываем хеш этого коммита.
git rebase -i ce5b35c
Открывается редактор с вот таким содержимым. Здесь порядок коммитов обратный: самый новый коммит — снизу
pick ce5b35c bullshit pick 8266a62 bullshit pick d590b3d result 1 pick cf30c6f bullshit pick 0955502 bullshit pick 71e8ed5 result 2
# Rebase 71e8ed5 onto f7569aa (6 commands) ...
Что в этой ситуации можно сделать с коммитами? Нам интересны две команды:
# p, pick = use commit # оставить коммит как есть
# s, squash = use commit, but meld into previous commit # слить содержимое коммита с ПРЕДЫДУЩИМ коммитом
Объединяем (squash) коммиты группами: первый «промежуточный» после каждого результата станет основой нового результата.
pick ce5b35c bullshit s 8266a62 bullshit s d590b3d result 1 pick cf30c6f bullshit s 0955502 bullshit s 71e8ed5 result 2
Когда вы сохраните этот текст и выйдете из редактора, откроется новый, с текстом сообщения для нового коммита result 1, потом для result 2 и так далее — столько раз, сколько коммитов вы хотите в итоге оставить. Первым будет самый старый, последним — самый новый. По умолчанию вам предлагается вот такой шаблон:
# This is a combination of 3 commits. # This is the 1st commit message: bullshit
# This is the commit message #2:
bullshit
# This is the commit message #3:
result 1
# Please enter the commit message for your changes. Lines starting
Когда вы отредактируете и сохраните все новые сообщения, rebase -i завершится. Получится примерно такая история:
* 588a7ac (HEAD -> newbranch) result 2 * 2713fda result 1

Комментариев нет:

Отправить комментарий