Mercurial: изменяем историю / Хабр

Когда я познакомился с Mercurial, то все свои знания я почерпнул из статей Спольского (перевод на Хабре), которые подробно описывают основные принципы работы Mercurial и ежедневную работу с ним. Долгое время я использовал Mercurial в пределах, которые не превышали объема этих статей. Наверно, для одиночного разработчика этого почти достаточно. Почти. Но Mercurial сегодня значительно шире и обладает возможностями допускающими редактирование истории изменений, наличие которых, в общем-то, не очевидно, хотя возможности эти достаточно ценны. А из комментариев к разным статьям по системам управления версиями видно, что многие разработчики об этих возможностях не знают. Ниже я хочу провести обзор ряда возможностей Mercurial связанных с изменением истории.

О чем пойдет речь:

  • фазы
  • hg commit –amend
  • hg strip
  • hg rebase

Ежедневная работа Mercurial заключается в создании новых наборов изменений (они же ревизии). Любой набор, как только он создан, навеки прописывается в репозитории. Неважно полезен ли этот отдельный набор, или он часть никому не нужной тупиковой ветви развития, он сохраняется и копируется во все репозитории. По крайней мере, так выглядит Mercurial на первый взгляд. С другой стороны иногда бывает действительно нужно удалять или заменять наборы изменений. Поэтому в Mercurial появился ряд инструментов, которые могут изменять историю. Изменять ревизии, которые известны другим репозиториям считается опасно, поскольку эти ревизии могут использоваться в других репозиториях, скажем, быть родителями новых ветвей. Поэтому удаление ревизий никогда не затрагивает внешние репозитории. Удаление локально. При синхронизации все ревизии, которые вы удалили у себя, будут вновь затянуты и создадут путаницу. Поэтому замена истории в Mercurial — это действие локального характера, которое проводиться только в пределах изменений, которых никто кроме вас не видит. Mercurial пытается автоматически отслеживать публичность или приватность наборов изменений при помощи механизма фаз.
Каждый набор изменений принадлежит к одной из трех фаз:

  • если набор изменений уже был куда-то отправлен, либо получен из внешнего репозитория, то его фаза public (публичная), изменять набор нельзя.
  • если набор создан локально, и никуда еще не отправлялся, то его фаза draft (черновик), изменять пока можно, однако при первой возможности (push или внешний pull) набор будет опубликован и станет public.
  • если мы не хотим, чтобы набор стал публичным, то мы можем вручную отнести его к фазе secret (секретная). Такой набор будет опубликован, только если вручную вернуть его фазу на draft или public. Изменять набор можно смело.

Итак, когда мы создаем новый набор изменений при помощи hg commit, этот набор относится к фазе draft. Этот набор есть только у нас, однако, при первой возможности все изменения будут отправлены в общий репозиторий. Фаза при этом изменится на public. Если мы хотим пока работать локально, чтобы об изменения не публиковались, то мы можем отнести изменения явно к фазе secret. Тогда изменения будут оставаться в локальном репозитории до тех пор, пока мы явно не изменим фазу на draft или public.

Проверяется и изменяется фаза командой hg phase. К примеру, возьмем репозиторий, в котором есть только один набор изменений:

hg log
changeset:   0:adfd3246d8b4
tag:         tip
user:        Пользователь
date:        Sat Nov 07 11:12:43 2015 +0300
summary:     initial commit

Проверяем, какая сейчас фаза у набора изменений 0:

hg phase -r 0
0: draft

Чтобы изменить фазу к команде добавляется параметр –draft, —public или –secret (они же –d, -p, -s). Изменяем фазу на секретную:

hg phase --secret –-force -r 0

hg phase -r 0
0: secret

Обратите внимание, что для того, чтобы увеличить фазу (в направлении от публичной до секретной) нужно использовать ключ —force. Уменьшение фазы в обратном направлении всегда безопасно. Чаще всего нужно только помечать наборы изменений как секретные, либо возвращать их к фазе draft. Механизм фазы задуман таким образом, чтобы не требовать особого внимания пользователя. Напоминаю, что изменять наборы изменений можно, только если они не принадлежат к публичной фазе.то же самое в TortoiseHgФазу видно из главного окна TortoiseHg. изменить ее можно при помощи контекстного меню.

Наверное, каждому случалось через мгновение после коммита обнаруживать ошибку в сообщении или сталкиваться с тем, что только что созданный коммит сломал билд. Как раз для этих случаев команда hg commit имеет опцию amend. Когда используется эта опция вместо создания отдельного набора изменений, вносится коррекция в последний из наборов (точнее в текущий набор). Все настолько просто, что рассказывать нечего. Создаем коммит с ошибкой в текстовом описании:

hg commit -m "Првый коммит"

Замечаем оплошность и тут же исправляем ее:

hg commit -m "Первый коммит" --amend
saved backup bundle to D:\work\Habr\hg1\.hg\strip-backup/54b061ad6202-amend-backup.hg

Результат:

hg log
changeset:   0:88779cfe79c1
tag:         tip
user:        Пользователь
date:        Sat Nov 07 11:12:43 2015 +0300
summary:     Первый коммит

Изменяется не только описание. Можно вносить правки в исходники, и они добавятся в новый набор изменений. Из вывода команды можно заметить, что Mercurial сделал бакап, на случай если мы сделали какую-то глупость. Восстановить бакап можно командой hg unbundle. И еще добавлю: commit —amend работает только с наборами изменений, у которых нет дочерних элементов. то же самое в TortoiseHg

Для начала нужно TortoiseHg переключить режим фиксации. После этого кнопка «Фиксировать» получит название «Отмена» (Перевод сбивает с толку. По смыслу должно быть «Перефиксировать»). При ее нажатии будет запускаться commit —amend со всеми плюшами – можно изменить сообщение, можно исправить ошибки в файлах.

Commit —amend доступно всегда, а вот команды hg rebase и hg strip является стандартными расширениями, которые по умолчанию отключены. Чтобы включить расширения нужно добавить в файл Mercurial.ini (либо в файл .hg/hgrc, чтобы включить расширения только в отдельном репозитории) следующие строки:

[extensions]
rebase = 
strip =

то же самое в TortoiseHG

Команда strip удаляет ревизию и всех ее потомков из репозитория:

hg strip 8
saved backup bundle to D:\work\Habr\hg0\.hg\strip-backup/92f6544e0370-backup.hg

Забавно, что команда strip удаляет, но не подменяет историю, поэтому ее допускается использовать с наборами изменений любой фазы. Однако если удалить наборы, которые засветились в других репозиториях, то при следующем затягивании изменений все удаления восстановятся.
Понять команду Rebase проще всего из примеров. Основная задача rebase – превратить две различные ветви в линейную историю.
Пока мы работали над веткой X, Y, Z, во внешнем репозитории возникли ревизии D, E.

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

Локальные наборы изменений X, Y и Z удаляются (сохраняются в .hg/strip-backup, а вместо них вставляются аналогичные наборы изменений X2, Y2, Z2).

Rеbase делается следующей командой:

hg rebase --source 4 --dest 8
saved backup bundle to D:\work\Habr\hg0\.hg\strip-backup/1ab1a1cc3d8d-backup.hg

Есть и другие варианты использования команды. Сокращенное написание команды:

hg rebase -s 4 -d 8

Использование —base вместо —source:

hg rebase --base 6 --dest 8

Когда применена опция —base, то Mercurial спускается от указанной ревизии до общего предка, за исключением самого общего предка. В нашем случае —base 6 означает то же, что и —source 4.

Если указать только одну из опций: base, source или dest, то вместо отсутствующего параметра используется текущая ревизия.

Опускаем опцию —dest, используем текущую ревизия в качестве dest.

hg up 8
hg rebase --source 4

Опускаем опции —source и —base, используем текущую ревизию в качестве base.

hg up 4
hg rebase --dest 8

то же самое в TortoiseHg

Результат операции

Несколько сценариев использования из документации Mercurial.

Превращаем две ветви в одну

Простое перемещение ветви:

hg rebase --dest E --base C. 

Сдвигаем начало ветви

Пунктом назначения не обязательно должна быть конечная ревизия:

hg rebase --dest D --base C. 

Избавляемся от слияния

Немного более сложная структура:

hg rebase --dest C --source D. 

Набор изменений слияния F перестает существовать за ненадобностью.

Еще более интересный случай

hg rebase --dest I --source D

Ревизия H удаляется, это ревизия слияния, а в результате работы rebase все наборы и так уже содержат все нужные изменения.

Полная линеаризация истории

hg rebase --dest I --source B

Удаляются ревизии слияния D и H.

Перенос другой ветви

hg rebase --dest B --source C

Перенос части другой ветви

hg rebase --dest I --source G

Коллапс

Иногда все изменения нужно вместить в одну ревизию. Для этого у команды rebase есть опция —сollapse.

hg rebase --dest B --base E –collapse

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

  1. Обычно линейная история предпочтительнее, чем сложный граф, содержащий множество слияний. Однако иногда во время слияния производится сложная ручная работа по разрешению конфликтов из двух наборов. После применения rebase результат этой работы сохраняется, но сама ревизия соответствующая слиянию исчезает и соответственно, нельзя проверить либо исправить ошибки, допущенные в результате ручного слияния.
  2. Как rebase, так и pull —rebase, дает ошибку, если в репозитории находятся незафиксированные изменения. Перед тем как пользоваться расширениями, нужно сделать что-либо из списка:
  1. Расширение MQ. Позволяет редактировать историю, однако считается устаревшим и не рекомендуется к использованию, поскольку именно для замены MQ созданы команды rebase, strip, histedit, graft, commit –amend.
  2. Расширение HistEdit. Позволяет редактировать историю в ручном режиме, производя отдельные операции с отдельными наборами изменений.
  3. Расширение RebaseIf. Делает то же самое что и Rebase, но стремится сохранять нетривиальные слияния. Не входит в стандартную поставку Mercurial.
  4. Расширение Evolve. Экспериментальное расширение, которое добавляет еще больше команд по редактированию истории. Например: uncommit (отмена коммита), fold (объединение наборов изменений), prune (удаление наборов изменений из истории). Работа этих команд обеспечивается тем, что к каждому набору изменения присваивается маркер устаревания. Благодаря этому маркеру настоящего удаления наборов не происходит, наборы лишь помечаются как устаревшие. Это означает, что операции редактирования истории могут работать даже с наборами в публичной фазе. Расширение экспериментальное и не входит в стандартную поставку Mercurial.
  5. Команда hg graft. Вообще говоря, не изменяет историю, но делает нечто похожее. hg graft копирует изменения из одной ветви в другую, при этом в старой ветви изменения не удаляются. После работы команды появляется несколько дубликатов наборов.

Команды меркуриала hg

Теперь о командах Меркуриала. Я покажу вам список блатных команд. Есть мануалы в которых описаны команды, которые вы очень редко будете использовать. Для начала нужно осмотреться. Установите hg — меркуриал. Я покажу вам установку на дебианоподобные операционные системы.


#установка hg на debian, ubuntu
sudo apt-get install mercurial

# файл помощи
hg -h

# описание одной команды
hg add -h

hg version
#Mercurial Distributed SCM (version 4.0)

Запустим в тестовом проекте hg. Теперь создадим несколько файлов для теста.


# создание репозитория, если вы внутри репозитория, то выполняйте эту команду
hg init

# создание репозитория project, если вы внутри репозитория, 
# то выйдите на уровень выше cd ..
hg init project

# создаем файл
echo "test mercurial" > README.me

#если у вас линукс, то установите утилиту tree
sudo apt-get install tree

.hg
├── 00changelog.i
├── requires
└── store

# проверка состояния
hg status
#вывод: ? README.me

Теперь нужно добавить файлы в индекс. Индекс — это файлы добавленные для последующего фиксирования. Если случится коммит, то файлы из индекса попадут в коммит. Перед коммитом всегда проверяют файлы в индексе. Перед коммитом нужно сохранить настройки пользователя: имя пользователя + email. Без этих настроек не получится сделать коммит.


# добавляем файлы в репозиторий
hg add
#вывод: A README.me

# добавляет неотслеживаемые файлы и помечает отсутствующие файлы как удаленные
hg addremove

#Отметьте указанные файлы, чтобы они больше не отслеживались
hg forget file

echo "[ui]" > ~/.hgrc
echo "username = Ivan Ivanov " >> ~/.hgrc

#создание первого коммита
hg commit -m "first revision"

#создание коммита. вам придётся делать описание коммиту своими руками
hg commit

#временное сохранение изменений, аналог git stash:
hg shelve

#вывести список сохраненных изменений
hg shelve --list

#вернуть изменения в рабочий каталог
hg unshelve

#для сохранений можно задать собственные имена
hg shelve --name 
hg unshelve 

Теперь осмотр файлов. Лог — это просмотр коммитов. Комманда hg log выдаст список коммитов. Самый первый коммит который вы увидите — это самый последний коммит. Поледний коммит — самый свежий коммит. Например, changeset: 7:b43f03eb72cc — 7 — это номер коммита, b43f03eb72cc — хеш сумма. По ней вы будете просматривать изменения и откатываться к нужному состоянию. Можно использовать номер коммита или хеш-сумму.

Осмотрим логи


#просмотр логов
hg log

#просмотр логов с подробностями
hg log -v

#просмотр логов c демонстрацией кода
hg log -p

#просмотр несколких коммитов
hg log -r 0:2

#показывает изменение последнего коммита
hg tip

#показ с мельчайшими подробностями
hg tip -vp

#последние изменения с подробностями
hg log -p -r -1

#смена визуального стиля вывода
hg log --style coal
hg log --style gitweb
hg log --style monoblue
hg log --style paper
hg log --style spartan

#просмотр изменений с подробностями
hg export b9a405b8937e
hg log -r b9a405b8937e -p

#чтение файла
hg cat command.sh

#чтение файла из 8 ревизии
hg cat -r 8 command.sh

#чтение файла между 2 ревизиями
hg cat -r 9:8 command.sh

Просмотр изменений не в индексе. Если вы уже добавили файл в индекс, то смотрите при помощи команды hg status


#просмотр изменений
hg diff

#просмотр изменений выбранного файла
hg diff command.sh

echo 'select * from table1;' > text1.txt

#вывод
diff -r 2b2ac0459d10 text1.txt
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/text1.txt Fri May 03 20:41:56 2019 +0300
@@ -0,0 +1,1 @@
+select * from table1;

Команда hg remove — помечает файлы как запланированные для удаления из репозитория. Файлы на диске не будут удалены до тех пор, пока вы не зафиксируете изменения. Ради понимания переключайтесь с одного коммита на другой hg update 0, затем hg update 1. Вы должны в коммитах создать разные по имени файлы.


#удаление файла
hg remove

#перебегаем на самый первый коммит
hg update 0
#вывод
.
└── README.me

#возвращаемся на последний коммит
hg update 1
#вывод
.
├── file6.txt
├── README.me
├── text1.txt
├── text2.txt
├── text3.txt
├── text4.txt
└── text5.txt

Теперь немного о работе с ветками. Нужно уметь создавать ветки hg branch my и переключаться между ветками hg update my.


#обновление до новой головной ревизии
hg update

#рабочий каталог проверяется на наличие незафиксированных изменений
hg update -c

#сброс индекса, файлы с кодом не удаляются
hg update --clean

#отменить незафиксированное слияние (потеря изменения), применять при мержах
hg update --clean my

#Для объединения двух голов
hg merge

#если вы находитесь на ветке default и у вас есть изменения в ветке my,  
#то вы можете принять изменения из ветки my
hg merge my

#коммит после merge
hg commit -m 'Merged changes'

#текущая ветка
hg branch
#default

#создание новой ветки
hg branch my

#список всех веток
hg branches

#Отзыв набора изменений
hg backout

#Отзыв последней ревизии (tip)
hg backout -m 'back out second change' tip

#Отзыв ревизии, не являющейся последней
hg backout --merge -m 'back out second change' 1

#откат выбранного файла до фиксированного изменения
hg revert command.sh

#откат всех файлов до зафиксированного состояния
hg revert --all
hg revert -a


просмотры: 2219,
уровень: лёгкий уровень,
рейтинг: 5,
дата: 2019-05-04 16:51:50

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

MonoRay.ru — Блог — Разработка

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

    Когда человек работает с репозиторием один — проблем, как правило, не возникает. Непонятки начинаются, когда с репозиторием работают 2 или более человек. Добавляет бардака «визуальный» софт — TortoiseHg, например. Люди привыкли тыкать одну кнопочку и чтобы «всё было хорошо». А тут куча кнопочек, еще и с невнятным переводом (если используется руссифицированная версия).

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

    Самая основная концепция, которую необходимо понять: HG — это децентрализованная система контроля версий. В любой момент времени есть, как минимум, два полноценных репозитория: на удаленном сервере и локальный, в папке проекта. Все изменения, в первую очередь, происходят в локальном репозитории. Чтобы обновить репозиторий на сервере необходимы дополнительные шаги.

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

hg pull -u

Командой hg pull мы обновляем с сервера наш локальный репозиторий (только репозиторий! файлы проекта не трогаются). За обновление файлов проекта отвечает флаг -u. Это всё делается на случай, если были какие-то изменения в коде.

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

hg commit -m «Исправил ошибку #58»

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

    К концу рабочего дня у нас имеется локальный репозиторий с несколькими коммитами в нём.
Теперь нам надо отправить всё наше добро на удаленный сервер — чтобы наши правки были доступны остальным разработчикам. Выполняем команду:

hg push

Этой командой мы отправляем все изменения из локального репозитория в удаленный. Если в удаленном репозитории с утра не было никаких изменений — то все проходит нормально.

Но мы рассмотрим случай с конфликтом. Поэтому в ответ мы получаем:

pushing to …
searching for changes
abort: push creates new remote heads on branch ‘default’!
(you should pull and merge or use push -f to force)

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

hg pull

Этой командой обновляем локальный репозиторий из удаленного. Получаем сообщение:

pulling from …
searching for changes
adding changesets
adding manifests
adding file changes
added 2 changesets with 1 changes to 1 files (+1 heads)
(run ‘hg heads’ to see heads, ‘hg merge’ to merge)

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

hg merge

И если слияние произошло без конфликтов — у нас получается код проекта, к которому применены все изменения.
Мы должны зафиксировать эти изменения:

hg commit -m «Слияние»

И протолкнуть их на сервер:

hg push

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

    Утилит слияния много, не буду останавливаться на какой-то конкретно, расскажу общие принципы.
Все они отличаются немного внешним видом, управлением, некоторые отличаются кривостью (встроенная мержилка в NetBeans 6.9.1 выводит меня из себя своим неудобством, поэтому использую meld).

    Итак, отображаются 3 версии файла: local, base, remote (в некоторых есть еще и 4 версия — merged). Именно BASE/MERGED вводит всех в ступор.

Расшифрую, что к чему:
LOCAL — файл с вашими правками
REMOTE — файл с сервера
BASE — исходный файл, «не правленный», к которому была попытка применения изменений (локальных и с сервера). 

Тут мы подходим к очень деликатному моменту. Как я говорил выше — у нас есть две ветки. В данном случае ветви анонимные — то есть у них нет названия и возникли они из-за конфликта. После слияния ветвление исчезнет и ветви сольются в один «ствол». Поэтому все изменения вносим в файл LOCAL — то есть в наш текущий проект.

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

    Смотрим и исправляем все конфликты, сохраняемся и выходим из программы.

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

hg commit -m «Слияние»
hg push

Рабочий день закончен, с чистой совестью идём домой. Всем спасибо!

PS: Обсудить, задать вопросы по HG можно в специальной теме на нашем форуме. 

Часть 3. Привыкаем работать в команде / Хабр

Это третья часть из серии Hg Init: Учебное пособие по Mercurial от Джоэля Спольски (Joel Spolsky). Предыдущие части:

Одно из преимуществ использования Mercurial — возможность работать командой над одним кодом. Mercurial позволяет каждому работать независимо и помогает объединять сделанные изменения.

Часть 3. Привыкаем работать в команде


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

Проще всего создать центральный репозиторий при помощи встроенного в Mercurial веб-сервера. Вам нужно лишь создать репозиторий при помощи hg init и открыть к нему доступ при помощи hg serve. По умолчанию репозиторий будет доступен на 8000-ом порту.

hg serve

запускает веб-сервер и делает текущий репозиторий доступным в сети Интернет.

Так как сервер запущен на компьютере joel.example.com, то я могу просто открыть joel.example.com:8000 в браузере и увидеть, что сервер работает, правда репозиторий абсолютно пуст.

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

hg clone

делает полную копию всего репозитория.

Теперь я создам файл guac, в котором запишу мой знаменитый рецепт гуакамоле.

Я добавлю и закоммичу этот файл в репозиторий. Это будет первая официальная версия:

Напишу комментарий к коммиту:

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

И зафиксирую изменения:

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

Хорошо, что у нас есть? К настоящему времени у меня есть центральный репозиторий и мой персональный клон этого репозитория. Я сделал два изменения и зафиксировал их, но эти изменения хранятся в моем клоне. В центральном репозитории их пока нет. Так что все выглядит так:

А сейчас я воспользуюсь командой hg push, которая протолкнет мои изменения из локального в центральный репозиторий:

hg push

проталкивает свежие изменения из текущего репозитория в центральный.

Ну, отлично. Ясно видно, что так не сработает. Не хочу думать о безопасности и последствиях запуска какого-то веб-сервера с разрешением всем и каждому проталкивать в него свои тупые изменения. Потерпите немного, я собираюсь настроить сервер так, чтобы он разрешал делать всем что угодно. Нужно отредактировать файл .hg\hgrc на сервере:

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

Хорошо, пора вновь запустить сервер:

Теперь у меня должно получиться протолкнуть изменения:

Ага! Теперь все выглядит так:

Я знаю, о чем вы думаете. Вы думаете: «Господи, Джоэль, это все странно. Почему в репозиториях лежат изменения, а не файлы? Где тот файлик guac?».

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

Воспользуемся браузером и снова заглянем в центральный репозиторий:

Там именно то, что ожидалось.

Теперь я позову Розу помочь мне в работе над рецептом. Роза из команды тестеров. Любой подтвердит, что она напоминает одну из тех бабулек, что можно увидеть в Вегасе, часами сидящих с отвисшей челюстью перед «одноруким бандитом» и бросающих монетку за монеткой в заветную щелку. Все отличие в том, что Роза программы тестирует. Вы можете подкинуть ей новую версию программы, и она проверит ее на 23 дистрибутивах Linux. Проверит по очереди на каждом. Не выказывая никаких эмоций, не делая лишних движений. Останавливаясь только для того, чтобы сообщить вам, что пропущена точка над i в турецкой версии Ubuntu Linux. Роза отлично тестирует, но, клянусь, иногда ведет себя как зомби.

Роза воспользовалась командой hg clone для создания своей собственной полной копии репозитория. hg clone принимает два аргумента: URL репозитория и имя каталога, в который вы хотите склонировать. У Розы свой каталог recipes.

Обратите внимание, что при выполнении hg log она видит всю историю. То есть Роза скачала весь репозиторий с полной историей всего, что уже произошло.

Сейчас Роза сделает изменение и внесет его в репозиторий:

Вот, коммитит. Обратите внимание, что она может работать даже если сервер не работает: коммит полностью выполняется на ее машине.

Пока Роза делала свои изменения, я тоже кое-что сделал.

После того, как я зафиксирую свои изменения, станет видно, что в моем логе под номером два указано не то же, что у Розы.

Истории в наших репозиториях начали отличаться.

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

Роза может продолжать работать без подключения к серверу, делая сколько угодно изменений. Она может фиксировать или откатывать изменения в своем репозитории. Однако настанет момент, когда она решит поделиться своими изменениями с остальными. Она может выполнить команду hg outgoing и увидеть список изменений, ожидающих отправки в центральный репозиторий. Это те изменения, которые будут отправлены при выполнении hg push.

hg outgoing

отображает список изменений ждущих отправки в текущем репозитории.

hg outgoing это просто список всех таких изменений в текущем репозитории, которых нет в центральном репозитории.

Хорошо, вот Роза проталкивает свои изменения в центральный репозиторий.

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

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

ААААА!!! Ошибка! Да, кстати, видите сообщение? То, в котором написано используйте ключ -f для принудительного проталкивания (use push -f to force)? Это ужасный совет. Никогда и ни за что не используйте ключ -f. Вы пожалеете о том, что использовали его. Просто поверьте мне в данный момент.

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

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

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

Тут какая-то тарабарщина про +1 голову (+1 heads). Это потому, что мой репозиторий, в котором раньше были аккуратно уложены три изменения, стал двухголовым монстром. На вершине репозитория опасно расположены два разных изменения. Вот как это выглядит:

У меня в репозитории теперь обе версии. Вот моя:

А вот версия Розы:

И я должен слить эти версии воедино. К счастью, это просто:

Глядите-ка! Команда hg merge взяла и объединила обе мои «головы» (изменения на вершине репозитория) в одну. Так как в данном случае мы с Розой изменили разные части файла, то конфликтов при слиянии не было и все прошло без сучка без задоринки.

hg merge

производит слияние (объединение) двух «голов».

Мне по-прежнему надо сделать коммит. Это важно. Если бы слияние не удалось, то я всегда мог бы откатиться и попробовать снова. Но, так как слияние было успешным, то я сделаю коммит. После этого я смогу протолкнуть мои изменения в центральный репозиторий.

Теперь в центральном репозитории то же, что в моем:

Хорошо, у меня есть изменения Розы и мои собственные изменения, но у Розы пока нет моих изменений.

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

Розе нужно вытянуть (pull) свежие входящие изменения из репозитория, чтобы получить мои изменения.

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

Видите, Она по-прежнему работает с кукурузными чипсами. С кукурузными чипсами!

У нее есть мои последние изменения где-то в репозитории…

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

hg parent

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

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

Запомните, что команда hg up без аргументов приведет рабочий каталог к «макушке» (tip), то есть применит все изменения до самого верхнего набора изменений. В данном случае, это четвертый набор изменений:

Теперь Роза видит самую свежую версию с изменениями от обоих нас.

Когда вы работаете в команде, то рабочий процесс будет выглядеть во многом так:

  1. Забрать свежую версию, с которой все работают, если вы давненько этого не делали, выполнив:
  2. Внести изменения
  3. Зафиксировать изменения (локально)
  4. Повторить пункты 2-3 до тех пор, пока у вас не получится хороший код, который вы хотите вывалить на всех остальных
  5. Когда вы готовы поделиться, выполнить:
    • hg pull для получения чужих изменений (если есть)
    • hg merge для слияния этих изменений со своими
    • тестирование! для того, чтобы удостовериться, что при слиянии ничего не попортилось
    • hg commit (для фиксации результата слияния)
    • hg push

Проверь себя

Вот все, что вы должны уметь делать на данный момент:

  1. Настроить центральный репозиторий и дать членам команды возможность делать его клоны
  2. Проталкивать изменения в центральный репозиторий
  3. Вытягивать изменения из центрального репозитория
  4. Делать слияние изменений от разных авторов

Продолжение здесь:
Hg Init: Часть 4. Исправляем ошибки

Mercurial: изменяем историю / Хабр

Когда я познакомился с Mercurial, то все свои знания я почерпнул из статей Спольского (перевод на Хабре), которые подробно описывают основные принципы работы Mercurial и ежедневную работу с ним. Долгое время я использовал Mercurial в пределах, превышающих объем этих статей. Наверно, для одиночного разработчика этого почти достаточно. Почти. Возможности Mercurial сегодня значительно шире и возможности позволяют редактировать истории изменений, наличие, в общем-то, не очевидно, хотя возможности эти достаточно ценны.А из комментариев к разным статьям по системам управления версиями видно, что многие разработчики об этих возможностях не знают. Ниже я хочу провести обзор ряда возможностей Переменчивое связанное с изменением истории.

О чем пойдет речь:

  • фазы
  • hg commit –amend
  • полоса
  • hg rebase

Ежедневная работа Mercurial заключается в создании новых наборов изменений (они же ревизии).Любой набор, как только он создан, навеки прописывается в репозитории. Неважно полезен ли этот отдельный набор, или он часть никому не нужной тупиковой ветви развития, он сохраняется и копируется во все репозитории. По крайней мере, так выглядит Mercurial на первый взгляд. С другой стороны иногда бывает действительно нужно удалить или заменять наборы изменений. Поэтому в Mercurial появился ряд инструментов, которые могут анализировать историю. Изменять ревизии, известные которым другим репозиториям считается опасно, поскольку эти ревизии говорят в других репозиториях, скажем, быть родителями новых ветвей.Поэтому удаление ревизий никогда не занимается внешние репозитории. Удаление локально. При которые синхронизируются все ревизии, вы удалили у себя, будут вновь затянуты и создадут путаницу. Поэтому замена истории в Mercurial — это действие локального характера, которое проводит только в пределах изменений, которые никто не видит. Mercurial автоматически отслеживает публичность или приватность наборов изменений при помощи механизма фаз.
Каждый набор изменений принадлежит к одной из трех фаз:

  • если набор изменений уже был куда-то отправлен, либо получен из внешнего репозитория, то его фаза public (публичная), эксперт набор нельзя.
  • если набор создан локально, и никуда еще не отправлялся, то его фаза черновик (черновик), эксперт пока можно, при первой возможности (push или external pull) набор будет опубликован и станет публичным.
  • , если мы не хотим, чтобы набор был публичным, то мы можем вручную отнести его к фазе secret (секретная). Такой набор будет опубликован, только если вручную вернуть его фазу на draft или public. Изменять набор можно смело.

Итак, когда мы создаем новый набор изменений при помощи hg commit, этот набор относится к фазе draft. Этот набор есть только у нас, однако при первой возможности все изменения будут отправлены в общий репозиторий. Фаза при этом изменится на общественности. Мы хотим пока работать локально, чтобы мы могли отнести изменения явно к фазе секрета. Тогда изменения будут оставаться в локальном репозитории до тех пор, пока мы явно не изменим фазу на призыв или публику.

Проверяется и изменяется фаза команды hg phase. К примеру, возьмем репозиторий, в котором есть только один набор изменений:

  hg log
набор изменений: 0: adfd3246d8b4
тег: подсказка
пользователь: Пользователь
дата: 7 ноя, сб, 11:12:43 2015 +0300
сводка: начальная фиксация  

Проверяем, какая сейчас фаза у набора изменений 0:

  hg phase -r 0
0: черновик
  

Чтобы изменить фазу к команде добавляется параметр –draft, —public или –secret (они же –d, -p, -s).Изменяем фазу на секретную:

  hg phase --secret –-force -r 0

hg phase -r 0
0: секрет
  

Обратите внимание, что для того, чтобы увеличить фазу (в направлении от публичной до секретной) нужно использовать ключ —force. Уменьшение фазы в обратном направлении всегда безопасно. Чаще всего нужно только помечать наборы изменений как секретные, либо возвращать их к фазе черновика. Механизм фазы задуман таким образом, чтобы не требовать особого внимания пользователя. Напоминаю, что исправлять наборы изменений можно, только если они не принадлежат к публичной фазе. то же самое в TortoiseHg Фазу видно из главного окна TortoiseHg. изменить ее можно при помощи контекстного меню.

Наверное, каждому случалось через мгновение после коммита обнаружила ошибку в сообщении или сталкивался с тем, что только что созданный коммитал билд. Как раз для этих случаев команда hg commit имеет опцию поправки. Когда используется эта опция вместо создания отдельного набора изменений, вносится коррекция в последний из наборов (точнее в текущий набор).Все настолько просто, что рассказывать нечего. Создаем коммит с ошибкой в ​​текстовом описании:

  hg commit -m "Првый коммит"
  

Замечаем оплошность и тут же исправляем ее:

  hg commit -m "Первый коммит" --amend
сохраненный пакет резервных копий в D: \ work \ Habr \ hg1 \ .hg \ strip-backup / 54b061ad6202 -mend-backup.hg
  

Результат:

  hg log
набор изменений: 0: 88779cfe79c1
тег: подсказка
пользователь: Пользователь
дата: 7 ноя, сб, 11:12:43 2015 +0300
резюме: Первый коммит
  

Изменяется не только описание.Можно вносить правки в исходники, и они добавятся в новый набор изменений. Из вывода команды можно заметить, что Mercurial сделал бакап, на случай если мы сделали какую-то глупость. Восстановить бакап можно командой hg unbundle. И еще добавлю: commit —amend работает только с наборами изменений, у которых нет дочерних элементов. то же самое в TortoiseHg

Для начала нужно TortoiseHg переключить режим фиксации. После этой кнопки «Фиксировать» получит название «Отмена» (Перевод сбивает с толку.По смыслу должно быть «Перефиксировать»). При ее нажатии будет запускаться commit —amend со всеми плюшами — можно изменить сообщение, можно исправить ошибки в файлах.

Commit —amend доступно всегда, а вот команды hg rebase и hg strip являются стандартными расширениями, которые по умолчанию отключены. Чтобы включить расширение нужно добавить в файл Mercurial.ini (либо в файл .hg / hgrc, чтобы включить расширение только в отдельном репозитории) следующие строки:

  [extension]
rebase =
полоса =
  

то же самое в TortoiseHG

Команда strip удаляет ревизию и всех ее потомков из репозитория:

  hg strip 8
сохраненный бэкап в D: \ work \ Habr \ hg0 \.hg \ strip-backup / 92f6544e0370-backup.hg
  

Забавно, что команда strip удаляет, но не подменяет, поэтому ее можно использовать с наборами изменений любой фазы. Однако если удалить наборы, которые засветились в других репозиториях, при следующем затягивании изменений все удаления восстановятся.
Понять команду Rebase — это проще всего из примеров. Основная задача rebase — превратить две различные ветви в линейную историю.
Пока мы работали над веткой X, Y, Z, во внешнем репозитории возникли ревизии D, E.

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

Локальные наборы изменений X, Y и Z удаляются (сохраняются в .hg / strip-backup, а вместо них вставляются аналогичные наборы изменений X2, Y2, Z2).

Rеbase делается командой:

  hg rebase --source 4 --dest 8
сохраненный пакет резервных копий в D: \ work \ Habr \ hg0 \ .hg \ strip-backup / 1ab1a1cc3d8d-backup.hg
  

Есть и другие варианты использования команды.Сокращенное написание команды:

  hg rebase -s 4 -d 8
  

Использование —base вместо —source:

  hg rebase --base 6 --dest 8
  

Когда применена опция —base, то Mercurial спускается от ревизии до общего предка, за исключением самого общего предка. В нашем случае —base 6 означает то же, что и —source 4.

Если указать только одну из опций: base, source или dest, то вместо отсутствующего менеджера используется текущая ревизия.
Опускаем опцию —dest, используемую ревизия в качестве dest.

  hg up 8
hg rebase --source 4
  

Опускаем опции —source и —base, используем текущую ревизию в качестве base.

  рт. Ст. Вверх 4
hg rebase --dest 8
  

то же самое в TortoiseHg

Результат операции

Несколько сценариев использования из документации Mercurial.

Превращаем две ветви в одну

Простое ветви:

  hg rebase --dest E - base C. 

Сдвигаем начало ветви

Пунктом назначения не обязательно должна быть конечная ревизия:

  hg rebase --dest D --base C.
  

Избавляемся от слияния

Немного более сложная структура:

  hg rebase --dest C --source D.
  

Набор изменений слияния F перестает существовать за ненадобностью.

Еще более интересный случай

  hg rebase --dest I --source D
  

Ревизия H удаляется, это ревизия слияния, в результате работы rebase все наборы и так уже содержат все нужные изменения.

Полная линеаризация истории

  hg rebase --dest I --source B
  

Удаляются ревизии слияния D и H.

Перенос другой ветви

  hg rebase --dest B --source C
  

Перенос части другой ветви

  hg rebase --dest I - source G
  

Коллапс

Иногда все изменения нужно вместить в одну ревизию. Для этого у команды rebase есть опция —сollapse.

  hg rebase --dest B --base E –collapse
  

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

  1. Обычно линейная история предпочтительнее, чем сложный граф, совокупное слияний. Однако иногда во время слияния создается сложная ручная работа по разрешению конфликтов из двух наборов. После применения перезагрузки результата работы сохраняется, но сама ревизия соответствующая слиянию проверить исчезает и соответственно, нельзя либо исправить ошибки, допущенные в результате ручного слияния.
  2. Как rebase, так и pull —rebase, выдает ошибку, если в репозитории находятся незафиксированные изменения. Перед тем как пользоваться расширениями, нужно сделать что-либо из списка:
  1. Расширение MQ. Позволяет редактировать историю, считается устаревшим и не рекомендуется к использованию, поскольку именно для замены MQ созданной команды rebase, strip, histedit, graft, commit –amend.
  2. Расширение HistEdit.Позволяет редактировать историю в ручном режиме, производя операции с отдельным набором изменений.
  3. Расширение RebaseIf. Делает то же самое что и Rebase, но стремится нетривиальные слияния. Не входит в стандартную поставку Mercurial.
  4. Расширение Evolve. Экспериментальное расширение которое, сэр еще больше команд по редактированию истории. Например: uncommit (отмена коммита), fold (объединение наборов изменений), prune (удаление наборов изменений из истории).Работа этих команд обеспечивается тем, что для каждого набору изменений присваивается маркер устаревшая. Благодаря этому маркеру настоящего удаления наборов не происходит, наборы лишь помечаются как устаревшие. Это означает, что операции редактирования истории могут работать даже с наборами в публичной фазе. Расширение экспериментальное и не входит в стандартную поставку Mercurial.
  5. Команда hg graft. Вообще говоря, не изменяет историю, но делает нечто похожее. hg-трансплантат копирует из одной ветви в другую.После работы команды появляется несколько дубликатов наборов.

.

Команды меркуриала hg

Теперь о командах Меркуриала. Я покажу вам список блатных команд. Есть мануалы в которых используются команды, которые вы очень редко используете. Для начала нужно осмотреться. Установить hg — меркуриал. Я покажу вам установку на дебианоподобные операционные системы.

 
# установка hg на debian, ubuntu
sudo apt-get install mercurial

# файл помощи
hg -h

# описание одной команды
hg добавить -h

версия hg
# Mercurial Distributed SCM (версия 4.0)
  

Запустим в тестовом проекте hg. Теперь создадим несколько файлов для теста.

 
# создание репозитория, если вы внутри репозитория, то выполняйте эту команду
hg init

# создание репозитория project, если вы внутри репозитория,
# то вы на уровне выше cd ..
проект hg init

# создаем файл
echo "test mercurial"> README.me

# Если у вас линукс, то установите утилиту дерево
дерево установки sudo apt-get

.hg
├── 00changelog.i
├── требуется
└── магазин

# проверка состояния
статус hg
# вывод:? ПРОЧТИ МЕНЯ.мне
  

Теперь нужно добавить файлы в индекс. Индекс — это файлы добавленные для последующего фиксирования. Если случится коммит, то файл из индекса попадут в коммит. Перед коммитом всегда проверяют файлы в индексе. Перед коммитом нужно сохранить настройки пользователя: имя пользователя + email. Без этих настроек не получится сделать коммит.

 
# добавляем файлы в репозиторий
hg добавить
# вывод: A README.me

# Cetre неотслеживаемые файлы и помечает отсутствующие файлы как удаленные
hg addremove

# Отметьте файлы, чтобы они больше не отслеживались
hg забыть файл

echo "[ui]"> ~ /.hgrc
echo "username = Иван Иванов" >> ~ / .hgrc

# создание первого коммита
hg commit -m "первая редакция"

# создание коммита. вам придётся делать описание коммиту своими руками
hg commit

# временное сохранение изменений, аналог git stash:
полка hg

# вывести список сохраненных изменений
hg shelve - список

# вернуть изменения в рабочий каталог
hg без полки

# для сохранений можно задать собственные силы
hg shelve - имя
hg unshelve  

Теперь осмотр файлов. Лог — это просмотр коммитов.Комманда hg log выдаст список коммитов. Самый первый коммит который последний коммит. Поледний коммит — самый свежий коммит. Например, набор изменений: 7: b43f03eb72cc — 7 — это номер коммита, b43f03eb72cc — хеш сумма. По ней вы будете просматривать изменения и откаты к нужному состоянию. Можно использовать номер коммита или хеш-сумму.

Осмотрим логи

 
# просмотр логов
журнал hg

# просмотр логов с подробностями
hg log -v

# просмотр логов c демонстрацией кода
hg log -p

# просмотр несколких коммитов
hg log -r 0: 2

# показывает изменение последнего коммита
hg подсказка

# показ с мельчайшими подробностями
hg tip -vp

# последние изменения с подробностями
hg log -p -r -1

# смена визуального стиля вывода
hg log - стиль уголь
hg log - стиль gitweb
hg log - стиль моно-синий
hg log - стиль бумаги
hg log - стиль спартанский

# просмотр изменений с подробностями
экспорт hg b9a405b8937e
hg log -r b9a405b8937e -p

# чтение файла
команда hg cat.ш

# чтение файла из 8 ревизии
hg cat -r 8 command.sh

# чтение файла между 2 ревизиями
hg cat -r 9: 8 command.sh
  

Просмотр изменений не в индексе. Если вы уже добавили файл в индекс, то смотрите при помощи команды hg status

 
# просмотр изменений
hg diff

# просмотр изменения файла
hg diff command.sh

echo 'выберите * из таблицы1;' > text1.txt

# вывод
diff -r 2b2ac0459d10 text1.txt
--- / dev / null Чт, 01 января, 00:00:00 1970 +0000
+++ b / text1.txt Пт 3 мая 20:41:56 2019 +0300
@@ -0,0 +1,1 @@
+ выбрать * из таблицы1;
  

Команда hg remove — помечает файлы как запланированные для удаления из репозитория.Файлы на диске не удалены до тех пор, пока вы не зафиксируете изменения. Ради понимания переключайтесь с одного коммита на другой hg update 0, затем hg update 1. Вы должны в коммитах создать разные по имени файлы.

 
# удаление файла
hg remove

# перебегаем на самый первый коммит
hg update 0
# вывод
.
└── README.me

# возвращаемся на последний коммит
hg update 1
# вывод
.
├── file6.txt
├── README.me
├── text1.txt
├── text2.txt
├── text3.txt
├── text4.txt
└── text5.txt
  

Теперь немного о работе с ветками.Нужно уметь создать ветки hg branch my и переключаться между ветками hg update my.

 
# обновление до новой головной ревизии
обновление hg

# рабочий каталог проверяется на наличие незафиксированных изменений
hg update -c

# сброс индекса, файлы с кодом не удаляются
hg update --clean

# отменить незафиксированное влияние (потеря изменения), применить при мержах
hg update - очистить мой

# Для объединения двух голов
hg слияние

# если вы находитесь на ветке default и у вас есть изменения в ветке my,
# то вы можете принять изменения из ветки моей
hg слить мой

# коммит после merge
hg commit -m 'Объединенные изменения'

# текущая ветка
hg филиал
#дефолт

# создание новой ветки
hg ветка моя

# список всех веток
ртутные ветви

# Отзыв набора изменений
hg backout

# Отзыв последней ревизии (подсказка)
hg backout -m совет, возвращающий второе изменение

# Отзыв ревизии, не являющейся последней
hg backout --merge -m 'назад второе изменение' 1

# откат выбранного файла до фиксированного изменения
hg revert команда.ш

# откат всех файлов до зафиксированного состояния
hg revert - все
hg revert -a
  

просмотров: 2220,
уровень: лёгкий уровень,
рейтинг: 5,
дата: 2019-05-04 16:51:50

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

.

Часть 4. Исправляем ошибки / Хабр

Это четвертая часть из серии Hg Init: Учебное пособие по Mercurial от Джоэля Спольски (Джоэля Спольски). Предыдущие части:

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

Часть 4. Исправляем ошибки

Mercurial позволяет свободно экспериментировать.Представьте, что во время работы вы что-то не то сделали в редакторе, и случилось нечто ужасное:

Emacs, как же я тебя люблю. Как бы то ни было, все можно исправить. Наиболее распространенным способом справиться с такими распространениями использование команды hg revert :

hg revert
возвращает файлы к состоянию, зафиксированному в репозитории.

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

А что если все зашло слишком далеко и вы уже закоммитили?

Есть команда hg rollback , которая спасет вашу шкуру, но только если вы еще не протолкнули (протолкнули) ошибочный коммит в другой репозиторий. Эта команда отменяет один коммит.

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

Представьте, что вы хотите поставить большой эксперимент в свободное время. Ваш босс нанял нового дизайнера, Джима. С тех пор дизайны, которые вы получаете, стали просто абсурдны. В них кислотный зеленый текст, ничего не выровнено (на это есть «художественные» причины, ага) и юзабилити хромает. Вы хотите прийти к заключению в выходной и все переделать, но боитесь коммитить свои изменения, так как не уверены на 100%, что ваши идеи лучше, чем у этого рехнувшегося дизайнера. Джим курит траву практически все время с момента пробуждения до момента отхода ко сну.Вы не хотите использовать это против него, да и все думают, что эта привычка никого не касается до тех пор, пока дизайны в порядке. Но всему есть предел. Так ведь? И дизайны у Джима не в порядке, и вообще он дерзкий какой-то.

При работе с Mercurial вы можете просто создать клон всего репозитория:

Это не настолько расточительно, как может показаться. Так как в репозиториях рецептов и рецептов-экспериментов хранится одно и то же (пока), то Mercurial воспользуется «жёсткими ссылками» (жесткие ссылки).А значит, копия репозитория будет создана быстро и займет много дополнительного места на диске.

Теперь можно сделать ряд изменений в экспериментальной ветке:

Начинаем мой великий эксперимент над рецептом гуакамоле:

В экспериментальном репозитории можно коммитить без опасений:

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

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

Но если все получилось, то вам нужно лишь протолкнуть ваши новые правки:

И куда же они протолкнулись?

пути hg
отображает список известных удаленных (удаленных) репозиториев.

Строчка, начинающаяся с «default», содержит путь к репозиторию, в который hg push проталкивает изменение, если вы явно не укажете другой репозиторий.Обычно в этой строчке указан путь к репозиторию, с которым вы делали клон. В данном случае это локальный каталог, но в качестве пути может быть и URL.

Не забывайте, что проталкивание изменений в этом репозиторий …

… не приводит к тому, что изменения появляются в рабочем каталоге.

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

Видите? Правки про «Кесо» в пятом наборе изменений.Но в моем основном репозитории работа остановилась на четвертом наборе изменений. От того, что кто-то протолкнул изменения в репозиторий , рабочий каталог не обновился, и пятый набор изменений в нем не появился. Так что я по-прежнему работаю с четвертым набором изменений.

Если я захочу, что в пятом наборе изменений, мне нужно будет использовать команду hg update :

Видите, что произошло? Изменения были получены, но они были после той версии, с которой я работал.Команды push и pull просто пересылают изменения между репозиториями. Эти команды не работают на то, с чем я работаю в данный момент.

Сейчас репозитории выглядят так:

Ртутный гибок в пересылки изменений из репозитория в репозиторий. Можно протолкнуть изменение прямо из экспериментального в центральном репозиторий:

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

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

Дизайнер Джим, после того как ему предложили работу, пообещал приступить к делам сразу же. Однако он не появлялся на работе еще два месяца.Почти все уже забыли и о нем, и о том, что предложить ему всю такую ​​загорелый впервые появился в офисе, честно сказать, никто толком не мог понять, кто он и что вообще происходит. Это было достаточно забавно. Внешность у него типическая. В конце концов, во всем разобрались, но так как он был новеньким, все постеснялись спросить у него, что, черт побери, произошло. И про шрамы и синяки на лице тоже не спросили. Неважно. Просто мы ненавидим этого парня.

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

Картофельные чипсы? Чё за ..?!

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

Матерь божья, что это было?

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

Проверь себя

Вот то, что вы должны уметь делать после прочтения данной части:

  1. Откатить случайные изменения. До того, как они зафиксированы в репозитории, и после.
  2. Локально склонировать репозиторий для экспериментов.
  3. Проталкивать изменения в разные репозитории.
  4. Откатить старую ошибку, которая давным-давно была зафиксирована в репозитории.

Продолжение здесь:
Hg Init: Часть 5. Процесс слияния

.