Статьи

Введение в Git — Раунд 2 (Продвинутый)

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

Возможно, вы уже читали сериал « Введение в Git » Шона Хадгстона. Если нет, то я действительно предлагаю вам это сделать. Как следует из названия, это не только отличное введение, но и хороший учебник для этой статьи.

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

  • Экспорт вашего хранилища
  • Базовый ребазинг
  • Изменение порядка набора коммитов
  • Разделение набора коммитов
  • Изменение сообщения фиксации
  • Слияние набора коммитов

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

Экспорт вашего репозитория

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

Архивы из местных репо

Архивирование может быть удобной частью наших процессов развертывания с помощью таких инструментов, как Phing и Capistrano, или инструментов непрерывной интеграции, таких как Hudson и Xinc. (При желании мы можем вызвать это в ответ на хук фиксации, но, возможно, это немного излишне.)

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

  Архив $ git --format = tar --prefix = sitepoint-git-advanced /  
      HEAD> sitepoint-git-advanced.tar |  
      gzip> sitepoint-git-advanced.tar.gz 

В приведенном выше примере я хочу, чтобы формат архива был TAR (вы также можете указать ZIP, если хотите). Затем я указал префикс «sitepoint-git-advanced». Если косая черта не добавляется, то имя присваивается всем файлам в архиве. В этом случае он предоставляется только всему архиву.

Теперь давайте посмотрим на другой пример, в котором выводом является ZIP-файл. Вместо указания формата и последующей передачи вывода в gzip , мы можем использовать параметр --output и предоставить имя с расширением .zip в качестве расширения файла.

  Архив $ git --output = sitepoint-git-advanced.zip   
      --prefix = sitepoint-git-advanced / -9 HEAD 

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

Архивы из удаленных репо

Локальные репозитории — не единственный тип репозиториев, которые мы можем архивировать. С --remote мы можем архивировать репозитории с Gitosis и других серверов Git, которые наша команда может использовать для хранения коллективного кода.

В приведенном ниже примере делается попытка клонировать проект Joind.In. К сожалению, если честно, это не работает (из поисковых форумов я считаю, что Github намеренно отключил их, чтобы помочь им улучшить пользовательский опыт), но я включил его здесь, чтобы показать вам пример команды.

  Архив $ git --remote = git: //github.com/settermjd/joind.in.git  
      --format = tar --prefix = joind.in / HEAD |  
      gzip> joindin.tar.gz 

Базовый ребазинг

Теперь давайте перейдем к некоторым более пикантным аспектам работы с Git. Согласно книге Git SCM, с помощью команды rebase мы можем «взять все изменения, которые были зафиксированы в одной ветви, и воспроизвести их в другой». Короче говоря, это позволяет нам объединять ветви и изменения мощным и гибким способом. Здесь также начинается небольшая дискуссия. Если вы знакомы с другими инструментами управления версиями, такими как CVS, SVN и Mercurial, то вы можете привыкнуть к модели, в которой после выполнения коммита, все — ее нельзя изменить. С Git это не обязательно так.

Изменение порядка коммитов

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

  $ git rebase -i HEAD ~ 5 

Используя приведенную выше команду, я начал сеанс rebase, охватывающий последние пять коммитов, отображаемых git rebase в обратном порядке:

  выберите da4fc8e, изменив значение по умолчанию, чтобы добавить итерацию
 выберите 003ab61 добавив четный итерационный скрипт
 выберите 701e132 переделывать структуру каталогов
 выберите c722b9f, удалив старые файлы
 pick 3a10e1c Добавлен в файлы, которые были забыты в предыдущем коммите 

Предположим, что коммит 5 (3a10e1c) должен быть после коммита 2 (003ab61). Мы можем изменить порядок фиксации в редакторе следующим образом:

  выберите da4fc8e, изменив значение по умолчанию, чтобы добавить итерацию
 выберите 003ab61 добавив четный итерационный скрипт
 pick 3a10e1c Добавлен в файлы, которые были забыты в предыдущем коммите
 выберите 701e132 переделывать структуру каталогов
 выберите c722b9f, удалив старые файлы 

Сохраните буфер и выйдите из редактора, и мы получим следующее:

  Успешно перебазированы и обновлены ссылки / главы / тестирование. 

Запустив git log выдает следующий вывод:

  commit ab97ffb2fe87c25ca48116ed03cdbe486dc0abb5
 Дата: пт 18 января 12:54:00 2012 +0000

     удаление старых файлов

 commit 3b5d6c5b0c6a866f426ff5bf412508ce9d9ae864
 Дата: пт 18 января 12:53:30 2012 +0000

     переделка структуры каталогов

 commit d9ab87677f8e5692b649b650a6de6ce836c72531
 Дата: пн 21 января 10:11:33 2012 +0100

     Добавлен в файлы, которые были забыты в предыдущем коммите

 commit 003ab6124b7f7a59be4fe152df28b9de706383ed
 Дата: пт 18 января 12:44:08 2012 +0000

     добавление четного итерационного скрипта 

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

Изменение сообщения фиксации

Что если вы привыкли писать сообщения о коммитах определенным образом, который, например, вы узнали из предыдущей работы, но теперь вы находитесь в новой организации, и они пишут их по-другому? Вы только что совершили изменение, и старший разработчик, просмотрев его, видит сообщение и хочет, чтобы оно было изменено в соответствии со стандартом компании. С Git вы можете вернуться и изменить сообщение.

Сначала мы должны запустить процесс ребазирования, выполнив следующую команду:

  $ git rebase -i HEAD ~ 2 

Мы просим перебазировать около двух ревизий до HEAD . Терминал отображает в буфере редактирования следующее:

  выберите c722b9f, удалив старые файлы
 выберите bcc1dff, добавив несколько файлов

 # Перебазировать 701e132..bcc1dff на 701e132
 #
 # Команды:
 #
 # p, pick = использовать коммит
 # r, reword = использовать коммит, но редактировать коммит
 # e, edit = использовать коммит, но остановить для внесения изменений
 # s, squash = использовать коммит, но слиться с предыдущим коммитом
 # f, fixup = вроде "squash", но отбрасывать сообщение журнала коммита
 # x, exec = команда run (остаток строки) с использованием shell
 #
 # Если вы удалите строку здесь, то этот коммит будет потерян.
 # Однако, если вы удалите все, ребаз будет прерван.
 # 

Мы видим два коммита наверху. В приведенном ниже списке команд у нас есть опция reword которая позволяет нам изменять сообщение коммита.

Здесь я изменил pick для reword :

  выберите c722b9f, удалив старые файлы
 перефразировать bcc1dff добавить несколько файлов

 # Перебазировать 701e132..bcc1dff на 701e132
 #
 # Команды:
 #
 ... 

Сохранение и выход из буфера позволит нам повторно указать сообщение коммита.

Объединение набора коммитов

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

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

Если бы мы работали с SVN или CVS, это было бы так; история изменений будет исправлена. С помощью Git мы можем открыть историю и объединить коммиты 1 и 3 в один коммит до коммита 2. Давайте пройдемся по процессу.

Мы начинаем процесс rebase, рассматривая последние пять коммитов, которые выглядят следующим образом:

  $ git rebase -i HEAD ~ 5

 выберите da4fc8e, изменив значение по умолчанию, чтобы добавить итерацию
 выберите 003ab61 добавив четный итерационный скрипт
 pick d9ab876 Добавлен в файлы, которые были забыты в предыдущем коммите
 выберите 3b5d6c5 переделывая структуру каталогов
 выберите ab97ffb, удалив старые файлы 

Затем мы изменим порядок так, чтобы 3 предшествовал 2 следующим образом:

  выберите da4fc8e, изменив значение по умолчанию, чтобы добавить итерацию
 pick d9ab876 Добавлен в файлы, которые были забыты в предыдущем коммите
 выберите 003ab61 добавив четный итерационный скрипт
 выберите 3b5d6c5 переделывая структуру каталогов
 выберите ab97ffb, удалив старые файлы 

Затем мы изменим pick на squash на новом коммите № 2:

  выберите da4fc8e, изменив значение по умолчанию, чтобы добавить итерацию
 squash d9ab876 Добавлен в файлы, которые были забыты в предыдущем коммите
 выберите 003ab61 добавив четный итерационный скрипт
 выберите 3b5d6c5 переделывая структуру каталогов
 выберите ab97ffb, удалив старые файлы 

Затем мы снова переводим в режим редактора, показывая нам предыдущие сообщения коммита. Мы добавляем новое сообщение о коммите, которое суммирует два коммита до их объединения. Итак, я изменяю следующее:

  # Это комбинация из 2 коммитов.
 # Сообщение первого коммита: 

 изменение по умолчанию для добавления итерации

 # Это второе сообщение коммита:

 Добавлен в файлы, которые были забыты в предыдущем коммите 

С новым сообщением:

  # Это комбинация из 2 коммитов.
 # Сообщение первого коммита: 

 Объединение двух изменений вместе, как они должны быть вместе. 

После выхода из редактора процесс перебазирования завершается.

Запустив, не разрушительно, процесс перебазирования снова, мы увидим, что эти два коммита были объединены. Теперь у нас есть пять коммитов, первый из которых предшествует первому ранее:

  выберите f5cac8d, добавив верхнюю документацию
 выберите e50970f, изменив значение по умолчанию, чтобы добавить итерацию
 выберите 3c2b3a5, добавив четный итерационный скрипт
 выберите 3b136c1 переделывая структуру каталогов
 выберите 01ad46f удаление старых файлов 

Разделение набора коммитов

Но что, если мы хотим пойти в противоположном направлении? Какой разработчик молодой и, возможно, немного небрежный, или что, если вы сами немного недисциплинированы? Я знаю, что время от времени страдаю от этого.

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

  $ git commit -m "нужно быстро закончить"
 [тестирование e6a98bb] нужно быстро закончить
  0 файлов изменено
  режим создания 100644 о.php
  режим создания 100644 contact-us.php
  режим создания 100644 default.php
  режим создания 100644 login.php 

В приведенном выше примере я зафиксировал набор файлов, три страницы бизнес-модуля ( about.php , contact-us.php и default.php ) и страницу пользовательского модуля ( login.php ). Давайте разделим их и сделаем все правильно.

Начиная ребаз с последних 3 коммитов, мы видим следующее:

  выберите 3b136c1 переделывая структуру каталогов
 выберите 01ad46f удаление старых файлов
 выбрать e6a98bb надо быстро закончить 

Измените команду pick для edit на последнем коммите (e6a98bb) и выйдите из редактора, чтобы получить следующий вывод:

  Остановился на e6a98bb ... нужно быстро закончить
 Вы можете изменить коммит сейчас, с

     git commit --amend

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

     git rebase - продолжение 

с помощью git reset HEAD^ мы перематываем коммит, распаковывая файлы. Теперь мы можем зафиксировать их правильно, добавив бизнес-и пользовательские страницы двумя отдельными коммитами.

  $ git add about.php contact-us.php default.php
 $ git commit -m "Добавление новых бизнес-страниц"
 [detached HEAD a189c9b] Добавление новых бизнес-страниц
  0 файлов изменено
  режим создания 100644 о.php
  режим создания 100644 contact-us.php
  режим создания 100644 default.php

 $ git add login.php
 $ git commit -m "добавление новой страницы входа пользователя"
 [detached HEAD 9efcab9] добавление новой страницы входа пользователя
  0 файлов изменено
  режим создания 100644 login.php 

Затем закончите, запустив git rebase --continue ключом --continue :

  $ git rebase --continue
 Успешно перебазированы и обновлены ссылки / главы / тестирование. 

Слово предупреждения

Теперь процитирую часто цитируемую фразу:

С большой властью приходит большая ответственность

Пожалуйста, помните, что если вы можете что-то сделать, это не значит, что вы должны это делать. Особенно, если вы сотрудничаете в командной среде, если вы вносите эти изменения в свой репозиторий, а затем объединяетесь с главным репозиторием, вы, среди прочего, можете вызвать путаницу с вашей командой. Хорошо, если есть веская причина, и это случается не слишком часто. Но если это случится неоднократно, я уверен, что вы не будете слишком популярны слишком долго.

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

Вывод

Я надеюсь, что после прочтения этой статьи вы увидите, сколько силы и гибкости предоставляет Git, но вы также понимаете, что с этой мощью также должно прийти понимание, когда и когда ее не применять.

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