Что такое git clone
git clone
Назначение: создание копии проекта для совместной работы в разных репозиториях
Совместная работа в разных репозиториях
Важно понимать, что рабочая копия в Git существенно отличается от рабочей копии, получаемой при загрузке исходного кода из репозитория SVN. В отличие от SVN, в Git нет разницы между рабочими копиями и центральным репозиторием — все они являются полноценными репозиториями Git.
Поэтому совместная работа в Git принципиально отличается от совместной работы в SVN. В SVN работа строится на отношении между центральным репозиторием и рабочей копией, а модель совместной работы в Git основана на взаимодействии между репозиториями. Вместо загрузки рабочей копии в центральный репозиторий SVN в Git вы отправляете коммиты из одного репозитория в другой с помощью команды push или копируете их в обратном направлении с помощью команды pull.
Вы легко можете задавать особую роль определенным репозиториям Git. Например, обозначив один из репозиториев Git как «центральный», вы можете воспроизвести централизованный рабочий процесс с использованием Git. Однако такой подход требует договоренностей, поскольку он не встроен в саму систему контроля версий
Использование
Чаще всего с помощью команды git clone выбирается существующий репозиторий и создается его клон или копия. Это делается в новом каталоге и в другом месте. Исходный репозиторий может находиться в локальной файловой системе или на удаленном устройстве, к которому можно получить доступ с помощью поддерживаемых протоколов. Команда git clone копирует существующий репозиторий Git. Она похожа на команду SVN checkout, но имеет некоторые отличия: так, полученная «рабочая копия» представляет собой полноценный репозиторий Git с собственной историей и файлами, полностью обособленный от исходного репозитория.
Клонирование в конкретную папку
Клонирование репозитория из в директорию
! на локальной машине.
Клонирование конкретного тега
Поверхностное клонирование
Варианты конфигурации
В примере выше клонируется только ветка new_feature из удаленного репозитория Git. Эта опция нужна исключительно для удобства, чтобы не тратить время на получение ссылки HEAD в репозитории и извлечение необходимой ссылки.
Другие варианты конфигурации
Исчерпывающий список опций git clone приведен в официальной документации по Git. В этом документе будут рассмотрены в том числе и другие распространенные опции.
URL-адреса в Git
В Git используется особый синтаксис URL-адресов, с помощью которого в команде можно задать расположение удаленных репозиториев. Поскольку команда git clone чаще всего используется в работе с удаленными репозиториями, здесь будет рассмотрен синтаксис URL-адресов в Git.
URL-протоколы в Git
Secure Shell (SSH) — это популярный сетевой протокол, обеспечивающий защищенную аутентификацию. Большинство серверов настроены для работы с ним по умолчанию. Из-за специфики протокола для входа на центральный сервер вам нужно знать учетные данные. ssh://[user@]host.xz[:port]/path/to/repo.git/
— GIT
Уникальный протокол Git. Вместе с Git поставляется специальный демон, который использует отдельный порт (9418). Этот протокол похож на SSH, однако GIT НЕ ОБЛАДАЕТ средствами аутентификации. git://host.xz[:port]/path/to/repo.git/
— HTTP
Протокол для передачи гипертекста. Этот протокол повсеместно используется во Всемирной паутине. Чаще всего применяется для передачи данных веб-страниц в формате HTML через Интернет. Git можно настроить для работы по HTTP. http[s]://host.xz[:port]/path/to/repo.git/
Резюме
1. Команда git clone предназначена для создания копии целевого репозитория.
2. Целевой репозиторий может находиться в локальной системе или на удаленном устройстве.
3. Git поддерживает несколько сетевых протоколов для установки соединения с удаленными репозиториями.
4. Существует множество вариантов конфигурации команды, которые позволяют изменять содержание копии.
Подробные сведения о возможностях git clone см. в официальной документации по Git. Примеры использования команды git clone на практике также можно найти в нашем руководстве по настройке репозитория.
Готовы изучить Git?
Ознакомьтесь с этим интерактивным обучающим руководством.
2. Основы работы с Git¶
Введение¶
Система спроектирована как набор программ, специально разработанных с учётом их использования в скриптах. Это позволяет удобно создавать специализированные системы контроля версий на базе Git или пользовательские интерфейсы. Например, Cogito является именно таким примером фронтенда к репозиториям Git, а StGit использует Git для управления коллекцией патчей.
Git поддерживает быстрое разделение и слияние версий, включает инструменты для визуализации и навигации по нелинейной истории разработки. Как и Darcs, BitKeeper, Mercurial, SVK, Bazaar и Monotone, Git предоставляет каждому разработчику локальную копию всей истории разработки; изменения копируются из одного репозитория в другой.
Удалённый доступ к репозиториям Git обеспечивается git-daemon, gitosis, SSH- или HTTP-сервером. TCP-сервис git-daemon входит в дистрибутив Git и является наряду с SSH наиболее распространённым и надёжным методом доступа. Метод доступа по HTTP, несмотря на ряд ограничений, очень популярен в контролируемых сетях, потому что позволяет использовать существующие конфигурации сетевых фильтров.
Основы работы с удаленным репозиторием¶
git clone — создание копии (удаленного) репозитория¶
Для начала работы с центральным репозиторием, следует создать копию оригинального проекта со всей его историей локально.
Клонируем репозиторий, используя протокол http:
Клонируем репозиторий с той же машины в директорию myrepo :
Клонируем репозиторий, используя безопасный протокол ssh:
У git имеется и собственный протокол:
Импортируем svn репозиторий, используя протокол http:
-s – понимать стандартные папки SVN (trunk, branches, tags)
git fetch и git pull — забираем изменения из центрального репозитория¶
Для синхронизации текущей ветки с репозиторием используются команды git fetch и git pull.
git fetch — забрать изменения удаленной ветки из репозитория по умолчания, основной ветки; той, которая была использована при клонировании репозитория. Изменения обновят удаленную ветку (remote tracking branch), после чего надо будет провести слияние с локальной ветку командой git merge.
git fetch /home/username/project — забрать изменения из определенного репозитория.
Возможно также использовать синонимы для адресов, создаваемые командой git remote :
git fetch username-project — забрать изменения по адресу, определяемому синонимом.
Команда git pull сразу забирает изменения и проводит слияние с активной веткой.
Забрать из репозитория, для которого были созданы удаленные ветки по умолчанию:
Забрать изменения и метки из определенного репозитория:
git push — вносим изменения в удаленный репозиторий¶
После проведения работы в экспериментальной ветке, слияния с основной, необходимо обновить удаленный репозиторий (удаленную ветку). Для этого используется команда git push.
Отправить свои изменения в удаленную ветку, созданную при клонировании по умолчанию:
Отправить изменения из ветки master в ветку experimental удаленного репозитория:
В удаленном репозитории origin удалить ветку experimental:
В удаленную ветку master репозитория origin (синоним репозитория по умолчанию) ветки локальной ветки master:
Отправить метки в удаленную ветку master репозитория origin:
Изменить указатель для удаленной ветки master репозитория origin (master будет такой же как и develop)
Добавить ветку test в удаленный репозиторий origin, указывающую на коммит ветки develop:
Работа с локальным репозиторием¶
Базовые команды¶
git init — создание репозитория
git add и git rm — индексация изменений
индексация измененного файла, либо оповещение о создании нового:
внести в индекс все изменения, включая новые файлы:
Из индекса и дерева проекта одновременно файл можно удалить командой git rm :
хороший пример удаления из документации к git, удаляются сразу все файлы txt из папки:
внести в индекс все удаленные файлы:
Сбросить весь индекс или удалить из него изменения определенного файла можно
командой git reset :
сбросить весь индекс:
удалить из индекса конкретный файл:
Команда git reset используется не только для сбрасывания индекса, поэтому дальше
ей будет уделено гораздо больше внимания.
git status — состояние проекта, измененные и не добавленные файлы, индексированные файлы
Кроме того, git status указывает на файлы с неразрешенными конфликтами слияния и
файлы, игнорируемые git.
git commit — совершение коммита
Коммит — базовое понятие во всех системах контроля версий, поэтому совершаться
он должен легко и по возможности быстро. В простейшем случае достаточно
после индексации набрать:
Есть несколько ключей, упрощающих работу с git commit :
совершит коммит, автоматически индексируя изменения в файлах проекта. Новые файлы при этом индексироваться не будут! Удаление же файлов будет учтено.
комментируем коммит прямо из командной строки вместо текстового редактора.
внесет в индекс и создаст коммит на основе изменений единственного файла.
git reset — возврат к определенному коммиту, откат изменений, «жесткий» или «мягкий»
Помимо работы с индексом (см. выше), git reset позволяет сбросить состояние проекта до какого-либо коммита в истории. В git данное действие может быть двух видов: «мягкого»(soft reset) и «жесткого» (hard reset).
Обратите внимание на обозначение HEAD^, оно означает «обратиться к предку последнего коммита». Подробней описан синтаксис такой относительной адресации будет ниже, в разделе «Хэши, тэги, относительная адресация». Соответственно, HEAD — ссылка на последний коммит. Ссылка ORIG_HEAD после «мягкого» резета указывает на оригинальный коммит.
Естественно, можно вернуться и на большую глубину коммитов,
Если команда достигнет точки ветвления, удаления коммита не произойдет.
Для команд слияния или выкачивания последних изменений с удаленного репозитория
примеры резета будут приведены в соответствующих разделах.
git revert — отмена изменений, произведенных в прошлом отдельным коммитом
Возможна ситуация, в которой требуется отменить изменения, внесенные отдельным коммитом. git revert создает новый коммит, накладывающий обратные изменения.
Отменяем коммит, помеченный тегом:
Отменяем коммит, используя его хэш:
Для использования команды необходимо, чтобы состояние проекта не отличалось от состояния, зафиксированного последним коммитом.
git log — разнообразная информация о коммитах в целом
Простейший пример использования, в котором приводится короткая справка по всем
коммитам, коснувшимся активной в настоящий момент ветки (о ветках и ветвлении
подробно узнать можно ниже, в разделе «Ветвления и слияния»):
За информацию по созданиям, переименованиям и правам доступа файлов отвечает ключ
—summary :
Чтобы просмотреть историю отдельного файла, достаточно указать в виде параметра
его имя (кстати, в моей старой версии git этот способ не срабатывает,
обязательно добавлять » — » перед «README»):
или, если версия git не совсем свежая:
Далее будет приводится только более современный вариант синтаксиса. Возможно
указывать время, начиная в определенного момента («weeks», «days», «hours», «s»
и так далее):
изменения, касающиеся отдельной папки:
Можно отталкиваться от тегов.
Все коммиты, начиная с тега v1:
Все коммиты, включающие изменения файла README, начиная с тега v1:
Все коммиты, включающие изменения файла README, начиная с тега v1 и заканчивая тегом v2:
Вывести на каждый из коммитов по строчке, состоящей из хэша (здесь — уникального идентификатора каждого коммита, подробней — дальше):
Лаконичная информация о коммитах, приводятся только автор и комментарий:
Более полная информация о коммитах, с именем автора, комментарием, датой создания и внесения коммита:
В принципе, формат вывода можно определить самостоятельно:
git diff — отличия между деревьями проекта, коммитами и т.д.
Показать изменения, не внесенные в индекс:
Изменения, внесенные в индекс:
Изменения в проекте по сравнению с последним коммитом:
Можно сравнивать «головы» веток:
или активную ветку с какой-либо:
git show — показать изменения, внесенные отдельным коммитом
Посмотреть изменения, внесенные любым коммитом в истории, можно командой git show :
git blame и git annotate — команды, помогающие отслеживать изменения файлов
Можно указать и конкретные строки для отображения:
git grep — поиск слов по проекту, состоянию проекта в прошлом
Поиск слова tst в проекте:
Подсчитать число упоминаний tst в проекте:
Поиск в старой версии проекта:
Команда позволяет использовать логическое И и ИЛИ.
Найти строки, где упоминаются и первое слово, и второе:
Найти строки, где встречается хотя бы одно из слов:
Ветвление¶
git branch — создание, перечисление и удаление веток
Работа с ветками — очень легкая процедура в git, все необходимые механизмы сконцентрированы в одной команде:
Просто перечислить существующие ветки, отметив активную:
Создать новую ветку new-branch:
Удалить ветку, если та была залита (merged) с разрешением возможных конфликтов в текущую:
Удалить ветку в любом случае:
Показать те ветки, среди предков которых есть определенный коммит:
git checkout — переключение между ветками, извлечение файлов
Команда git checkout позволяет переключаться между последними коммитами (если упрощенно) веток:
Создаст ветку, в которую и произойдет переключение
Вернуть файл (или просто вытащить из прошлого коммита) позволяет команда вида:
Вернуть somefile к состоянию последнего коммита:
Вернуть somefile к состоянию на два коммита назад по ветке:
git merge — слияние веток (разрешение возможных конфликтов)
Слияние веток, в отличие от обычной практики централизованных систем, в git происходит практически каждый день. Естественно, что имеется удобный интерфейс к популярной операции.
Попробовать объединить текующую ветку и ветку new-feature:
В случае возникновения конфликтов коммита не происходит, а по проблемным файлам расставляются специальные метки а-ля svn; сами же файлы отмечаются в индексе как «не соединенные» (unmerged). До тех пор пока проблемы не будут решены, коммит совершить будет нельзя.
Произошла неудачная попытка слияния:
Смотрим на проблемные места:
Индексируем наши изменения, тем самым снимая метки:
Совершаем коммит слияния:
Вот и все, ничего сложного. Если в процессе разрешения вы передумали разрешать конфликт, достаточно набрать (это вернёт обе ветки в исходные состояния):
Если же коммит слияния был совершен, используем команду:
git rebase — построение ровной линии коммитов
Предположим, разработчик завел дополнительную ветку для разработки отдельной возможности и совершил в ней несколько коммитов. Одновременно по какой-либо причине в основной ветке также были совершены коммиты: например, в нее были залиты изменения с удаленного сервера, либо сам разработчик совершал в ней коммиты.
Предположим, имеется две ветки, master и topic, в каждой из которых было совершенно несколько коммитов начиная с момента ветвления. Команда git rebase берет коммиты из ветки topic и накладывает их на последний коммит ветки master.
Вариант, в котором явно указывается, что и куда накладывается:
на master накладывается активная в настоящий момент ветка:
git cherry-pick — применение к дереву проекта изменений, внесенных отдельным коммитом
Если ведется сложная история разработки, с несколькими длинными ветками разработками, может возникнуть необходимость в применении изменений, внесенных отдельным коммитом одной ветки, к дереву другой (активной в настоящий момент).
Изменения, внесенные указанным коммитом будут применены к дереву, автоматически проиндексированы и станут коммитом в активной ветке:
Прочие команды и необходимые возможности¶
Хэш — уникальная идентификация объектов
В git для идентификации любых объектов используется уникальный (то есть с огромной вероятностью уникальный) хэш из 40 символов, который определяется хэшируюшей функцией на основе содержимого объекта. Объекты — это все: коммиты, файлы, тэги, деревья. Поскольку хэш уникален для содержимого, например, файла, то и сравнивать такие файлы очень легко — достаточно просто сравнить две строки в сорок символов.
Больше всего нас интересует тот факт, что хэши идентифицируют коммиты. В этом смысле хэш — продвинутый аналог ревизий Subversion. Несколько примеров использования хэшей в качестве способа адресации:
найти разницу текущего состояния проекта и коммита за номером… сами видите, каким:
То же самое, но оставляем только шесть первых символов. Git поймет, о каком коммите идет речь, если не существует другого коммита с таким началом хэша:
Иногда хватает и четырех символов:
Читаем лог с коммита по коммит:
Разумеется, человеку пользоваться хэшами не так удобно, как машине, именно поэтому были введены другие объекты — тэги.
git tag — тэги как способ пометить уникальный коммит
Тэг (tag) — это объект, связанный с коммитом; хранящий ссылку на сам коммит, имя автора, собственное имя и некоторый комментарий. Кроме того, разработчик может оставлять на таких тегах собственную цифровую подпись.
Кроме этого в git представленные так называемые «легковесные тэги» (lightweight tags), состоящие только из имени и ссылки на коммит. Такие тэги, как правило, используются для упрощения навигации по дереву истории; создать их очень легко.
Создать «легковесный» тэг, связанный с последним коммитом; если тэг уже есть, то еще один создан не будет:
Пометить определенный коммит:
Создать тэг для последнего коммита, заменить существующий, если таковой уже был:
Обычные тэги имеет смысл использовать для приложения к коммиту какой-либо информации, вроде номера версии и комментария к нему. Иными словами, если в комментарии к коммиту пишешь «исправил такой-то баг», то в комментарии к тэгу по имени «v1.0» будет что-то вроде «стабильная версия, готовая к использованию».
Создать обычный тэг для последнего коммита; будет вызван текстовый редактор для составления комментария:
Создать обычный тэг, сразу указав в качестве аргумента комментарий:
Команды перечисления, удаления, перезаписи для обычных тэгов не отличаются от команд для «легковесных» тэгов.
Относительная адресация
Вместо ревизий и тэгов в качестве имени коммита можно опираться на еще один механизм — относительную адресацию. Например, можно обратиться прямо к предку последнего коммита ветки master:
Если после «птички» поставить цифру, то можно адресоваться по нескольким предкам коммитов слияния:
найти изменения по сравнению со вторым предком последнего коммита в master; HEAD здесь — указатель на последний коммит активной ветки:
Аналогично, тильдой можно просто указывать, насколько глубоко в историю ветки нужно погрузиться:
что привнес «дедушка» нынешнего коммита:
Обозначения можно объединять, чтобы добраться до нужного коммита:
Пример содержимого такого файла:
Серверные команды репозитория¶
; git count-objects : Проверка, сколько объектов будет потеряно и объём освобождаемого места при перепаковке репозитория.
; git gc : Переупаковка локального репозитория.
Рецепты¶
Создание пустого репозитория на сервере
Импорт svn репозитория на Git-сервер
Git Wizardry
1 Введение
В своей прошлой заметке я постарался осветить в общих чертах стиль работы с
распределенной системой контроля версий git и указать на отличия по сравнению с
классическими централизованными СКВ. Целью было прежде всего обобщение опыта
работы с системой без упоминания тонкостей синтаксиса отдельных команд.
Данный же топик задумывался как непосредственное введение в работу с git, нечто
среднее между tutorial и обобщенной справкой, до которого все же рекомендуется
прочитать упомянутое выше введение. Сознательно избегаются технические
подробности работы git, употребляются только общие для СКВ термины и
ограничивается список упоминаемых команд.
2 Работа с локальным репозитарием
Сила любых распределенных систем — в наличии у каждого разработчика локального
репозитария, в котором возможно организовывать произвольную личную схему
разработки. В git есть несколько основных команды для ведения работы на месте и
множество вспомогательных.
2.1 Базовые команды
Базовые команды — те, без которых невозможно обойтись в разработке.
2.1.1 git init — создание репозитария
Команда git init создает в директории пустой репозитарий в виде директория
.git, где и будет в дальнейшем храниться вся информация об истории коммитов,
тегах — ходе разработки проекта:
Другой способ создать репозитарий — команда git clone, но о ней чуть позже.
2.1.2 git add и git rm — индексация изменений
Следующее, что нужно знать — команда git add. Она позволяет внести в индекс — временное хранилище — изменения, которые затем войдут в коммит. Примеры
использования:
git add EDITEDFILE — индексация измененного файла, либо оповещение о
создании нового.
git add. — внести в индекс все изменения, включая новые файлы.
Из индекса и дерева одновременно проекта файл можно удалить командой git rm:
git rm FILE1 FILE2 — отдельные файлы
git rm Documentation/\*.txt — хороший пример удаления из документации к git,
удаляются сразу все файлы txt из папки.
Сбросить весь индекс или удалить из него изменения определенного файла можно
командой git reset:
git reset — сбросить нафиг весь индекс.
git reset — EDITEDFILE — удалить из индекса конкретный файл.
Команда git reset используется не только для сбрасывания индекса, поэтому дальше
ей будет уделено гораздо больше внимания.
2.1.3 git status — состояние проекта, измененные и не добавленные файлы, индексированные файлы
Команда git status, пожалуй, можно считать самой часто используемой наряду с
командами коммита и индексации. Она выводит информацию обо всех изменениях,
внесенных в дерево директорий проекта по сравнению с последним коммитом рабочей
ветки; отдельно выводятся внесенные в индекс и неиндексированные
файлы. Использовать ее крайне просто:
Кроме того, git status указывает файлы с неразрешенными конфликтами слияния и
файлы, игнорируемые git.
2.1.4 git commit — совершение коммита
Коммиты — базовое понятие во всех системах контроля версий, поэтому совершатся
он должен легко и по возможности быстро. В самом своем простом виде достаточно
после индексации набрать:
Если индекс не пустой, то на его основе будет совершен коммит, после чего
пользователя попросят прокомментировать вносимые изменения вызовом команды
edit(например, в Ubuntu обычно вызывается простенький текстовый редактор nano, у
меня же — emacs). Сохраняемся, и вуала! Коммит готов.
Есть несколько ключей, упрощающих работу с git commit:
git commit FILENAME — внесет в индекс и создаст коммит на основе изменений
единственного файла.
2.1.5 git reset — возврат к определенному коммиту, откат изменений, «жесткий» или «мягкий»
Помимо работы с индексом (см. выше), git reset позволяет сбросить состояние
проекта до какого-либо коммита в истории. В git данное действие может быть двух
видов: «мягкого»(soft reset) и «жесткого» (hard reset).
«Мягкий» (с ключом «—soft») резет оставит нетронутыми ваши индекс и все дерево
файлов и директорий проекта, вернется к работе с указанным коммитом. Иными
словами, если вы обнаруживаете ошибку в только что совершенном коммите или
комментарии к нему, то легко можно исправить ситуацию:
Обратите внимание на обозначение HEAD^, оно означает «обратиться к предку
последнего коммита». Подробней описан синтаксис такой относительной адресации
будет ниже, в разделе «Хэши, тэги, относительная адресация». Соответственно,
HEAD — ссылка на последний коммит. Ссылка ORIG_HEAD после «мягкого» резета
указывает на оригинальный коммит.
Естественно, можно вернуться и на большую глубину коммитов,
1 — больше никто и никогда не увидит этот позорный коммит.
3 — вернее, три последних коммита. Никто. Никогда.
Если команда достигнет точки ветвления, удаления коммита не произойдет.
Для команд слияния или выкачивания последних изменений с удаленного репозитария
примеры резета будут приведены в соответствующих разделах.
2.1.6 git revert — отмена изменений, произведенных в прошлом отдельным коммитом
Возможна ситуация, в которой требуется отменить изменения, внесенные отдельным
коммитом. Git revert создает новый коммит, накладывающий обратные изменения:
git revert config-modify-tag — отменяем коммит, помеченный тегом.
git revert 12abacd — отменяем коммит, используя его хэш.
Для использования команды необходимо, чтобы состояние проекта не отличалось от
состояния, зафиксированного последним коммитом.
2.1.7 git log — разнообразная информация о коммитах в целом, по отдельным файлам и различной глубины погружения в историю
Иногда требуется получить информацию об истории коммитов, коммитах, изменивших
отдельный файл; коммитах за определенный отрезок времени и так далее. Для этих
целей используется команда git log.
Простейший пример использования, в котором приводится короткая справка по всем
коммитам, коснувшимся активной в настоящий момент ветки (о ветках и ветвлении
подробно узнать можно ниже, в разделе «Ветвления и слияния»):
За информацию по созданиям, переименованиям и правам доступа файлов отвечает ключ
—summary:
Для исследования истории отдельного файла достаточно указать в виде параметра
его имя (кстати, в моей старой версии git этот способ не срабатывает,
обязательно добавлять » — » перед «README»):
или, если версия git не совсем свежая:
Далее будет приводится только более современный вариант синтаксиса. Возможно
указывать время, начиная в определенного момента («weeks», «days», «hours», «s»
и так далее):
Можно отталкиваться от тегов:
git log v1… — все коммиты, начиная с тега v1.
git log v1… README — все коммиты, включающие изменения файла README, начиная с
тега v1.
git log v1..v2 README — все коммиты, включающие изменения файла README, начиная с
тега v1 и заканчивая тегом v2.
Создание, выведение списка, назначение тегов будет приведено в соответствующем
разделе ниже.
В принципе, формат вывода можно определить самостоятельно:
Определение формата можно поискать в разделе по git log из Git Community Book
или справке. Красивый ASCII-граф коммитов выводится с использованием ключа
—graph.
2.1.8 git diff — отличия между деревьями проекта; коммитами; состоянием индекса и каким-либо коммитом.
Своего рода подмножеством команды git log можно считать команду git diff,
определяющую изменения между объектами в проекте: деревьями (файлов и
директорий):
git diff — покажет изменения, не внесенные в индекс.
git diff HEAD — изменения в проекте по сравнению с последним коммитом
git diff HEAD^ — предпоследним коммитом
Можно сравнивать «головы» веток:
git diff master..experimental
Ну или активную ветку с какой-либо:
git diff experimental
2.1.9 git show — показать изменения, внесенные отдельным коммитом
Посмотреть изменения, внесенные любым коммитом в истории можно командой git
show:
git show COMMIT_TAG
2.1.10 git blame и git annotate — вспомогательные команды, помогающие отслеживать изменения файлов
При работе в команде часто требуется выяснить, кто именно написал конкретный
код. Удобно использовать команду git blame, выводящую построчную информацию о
последнем коммите, коснувшемся строки, имя автора и хэш коммита:
Можно указать и конкретные строки для отображения:
Аналогично работает команда git annotate, выводящая и строки, и информацию о
коммитах, их коснувшихся:
git annotate README
2.1.11 git grep — поиск слов по проекту, состоянию проекта в прошлом
git grep, в целом, просто дублирует функционал знаменитой юниксовой
команды. Однако, он позволяет слова и их сочетания искать в прошлом проекта, что
бывает очень полезно:
git grep tst — поиск слова tst в проекте.
git grep tst v1 — поиск в старой версии проекта.
Команда позволяет использовать логическое И и ИЛИ:
2.2 Ветвление
Операции ветвления и слияния — сердце и душа git, именно эти возможности делают такой
удобной работу с системой.
2.2.1 git branch — создание, перечисление и удаление веток
Работа с ветками — очень легкая процедура в git, все необходимые механизмы
сконцентрированы в одной команде:
git branch — просто перечислит существующие ветки, отметив активную.
git branch new-branch — создаст новую ветку new-branch.
2.2.2 git checkout — переключение между ветками, извлечение отдельных файлов из истории коммитов
Команда git checkout позволяет переключаться между последними коммитами (если
упрощенно) веток:
Вернуть файл (или просто вытащить из прошлого коммита) позволяет команда вида:
git checkout somefile — вернуть somefile к состоянию последнего коммита
git checkout HEAD
2 somefile — вернуть somefile к состоянию на два коммита назад по ветке.
2.2.3 git merge — слияние веток (разрешение возможных конфликтов).
Слияние веток, в отличие от обычной практики централизованных систем, в git
происходит практически каждый день. Естественно, что имеется удобный интерфейс к
популярной операции:
git merge new-feature — попробует объединить текующую ветку и ветку new-feature.
В случае возникновения конфликтов коммита не происходит, а по проблемным файлам
расставляются специальные метки а ля svn; сами же файлы отмечаются в индексе как
«не соединенные» (unmerged). До тех пор пока проблемы не будут решены, коммит совершить
будет нельзя.
Например, конфликт возник в файле TROUBLE, что можно увидеть в git status:
git merge experiment — произошла неудачная попытка слияния.
git status — смотрим на проблемные места.
edit TROUBLE — разрешаем проблемы.
git add. — индексируем наши изменения, тем самым снимая метки.
git commit — совершаем коммит слияния.
Вот и все, ничего сложного. Если в процессе разрешения вы передумали разрешать
конфликт, достаточно набрать:
Если же коммит слияния был совершен, используем команду:
2.2.4 git rebase — построение ровной линии коммитов
Предположим, разработчик завел дополнительную ветку для разработки отдельной
возможности и совершил в ней несколько коммитов. Одновременно по какой-либо
причине в основной ветке также были совершены коммиты: например, в нее были
залиты изменения с удаленного сервера; либо сам разработчик совершал в ней
коммиты.
В принципе, можно обойтись обычным git merge. Но тогда усложняется сама линия
разработки, что бывает нежелательно в слишком больших проектах, где участвует
множество разработчиков.
Предположим, имеется две ветки, master и топик, в каждой из которых было совершенно несколько коммитов начиная с момента ветвления.
Команда git rebase берет коммиты из ветки topic и накладывает их на последний коммит ветки
master:
2.2.5 git cherry-pick — применение к дереву проекта изменений, внесенных отдельным коммитом
Если ведется сложная история разработки, с несколькими длинными ветками
разработками, может возникнуть необходимость в применении изменений, внесенных
отдельным коммитом одной ветки, к дереву другой (активной в настоящий момент).
git cherry-pick BUG_FIX_TAG — изменения, внесенные указанным коммитом будут
применены к дереву, автоматически проиндексированы и станут коммитом в активной
ветке.
2.3 Прочие команды и необходимые возможности
Для удобства работы с git было введено дополнительное понятие: тэг. Кроме того
дальше будет пояснена необходимость в хэшах, и его применение; показан способ
обращаться к коммитам при помощи относительной адресации.
2.3.1 Хэш — уникальная идентификация объектов
В git для идентификации любых объектов используется уникальный (то есть с
огромной вероятностью уникальный) хэш из 40 символов, который определяется
хэшируюшей функцией на основе содержимого объекта. Объекты — это все: коммиты,
файлы, тэги, деревья. Поскольку хэш уникален для содержимого, например, файла,
то и сравнивать такие файлы очень легко — достаточно просто сравнить две строки
в сорок символов.
Больше всего нас интересует тот факт, что хэши идентифицируют коммиты. В этом
смысле хэш — продвинутый аналог ревизий Subversion. Несколько примеров
использования хэшей в качестве способа адресации:
git diff f292ef5d2b2f6312bc45ae49c2dc14588eef8da2 — найти разницу текущего
состояния проекта и коммита за номером… Ну сами видите, каким.
git diff f292ef5 — то же самое, но оставляем только шесть первых символов. Git
поймет, о каком коммите идет речь, если не существует другого коммита с таким
началом хэша.
git diff f292 — иногда хватает и четырех символов.
git log febc32. f292 — читаем лог с коммита по коммит.
Разумеется, человеку пользоваться хэшами не так удобно, как машине, именно поэтому были
введены другие объекты — тэги.
2.3.2 git tag — тэги как способ пометить уникальный коммит
Тэг (tag) — это объект, связанный с коммитом; хранящий ссылку на сам коммит, имя
автора, собственное имя и некоторый комментарий. Кроме того, разработчик может
оставлять на таких тегах собственную цифровую подпись.
Кроме этого в git представленные так называемые «легковесные тэги» («lightweight
tags»), состоящие только из имени и ссылки на коммит. Такие тэги, как правило,
используются для упрощения навигации по дереву истории; создать их очень легко:
git tag stable-1 — создать «легковесный» тэг, связанный с последним
коммитом. Если тэг уже есть, то еще один создан не будет.
git tag stable-2 f292ef5 — пометить определенный коммит.
После создания тэга его имя можно использовать вместо хэша в любых командах
вроде git diff, git log и так далее:
git diff stable-1.1. stable-1
Обычные тэги имеет смысл использовать для приложения к коммиту какой-либо
информации, вроде номера версии и комментария к нему. Иными словами, если в
комментарии к коммиту пишешь «исправил такой-то баг», то в комментарии к тэгу по
имени «v1.0» будет что-то вроде «стабильная версия, готовая к использованию»:
Команды перечисления, удаления, перезаписи для обычных тэгов не отличаются от
команд для «легковесных» тэгов.
2.3.3 Относительная адресация
Вместо ревизий и тэгов в качестве имени коммита можно опираться на еще один
механизм — относительную адресацию. Например, можно обратиться прямо к предку
последнего коммита ветки master:
Если после «птички» поставить цифру, то можно адресоваться по нескольким предкам
коммитов слияния:
git diff HEAD^2 — найти изменения по сравнению со вторым предком последнего
коммита в master. HEAD здесь — указатель на последний коммит активной ветки.
Аналогично, тильдой можно просто указывать, насколько глубоко в историю ветки
нужно погрузиться:
git diff master^^ — что привнес «дедушка» нынешнего коммита.
Обозначения можно объединять, чтобы добраться до нужного коммита:
Иногда по директориям проекта встречаются файлы, которые не хочется постоянно
видеть в сводке git status. Например, вспомогательные файлы текстовых
редакторов, временные файлы и прочий мусор.
Заставить git status игнорировать можно, создав в корне или глубже по дереву
(если ограничения должны быть только в определенных директория) файл
.gitignore. В этих файлах можно описывать шаблоны игнорируемых файлов
определенного формата.
Пример содержимого такого файла:
#не нужны объектники и архивы
Существуют и другие способы указания игнорируемых файлов, о которых можно узнать
из справки git help gitignore.
3 «Вместе мы — сила», или основы работы с удаленным репозитарием
Естественно, что большая часть проектов все-таки подразумевает работу по крайней
мере двух разработчиков, которым требуется обмениваться кодом. Далее будут
перечислены команды, требующиеся для совместной — возможно удаленной — работы.
3.1 Удаленные ветки (remote tracking branches)
Новое понятие здесь — удаленные ветки. Удаленные ветки соответствуют какой-либо
ветке (чаще master) на удаленном сервере. Одна такая создается автоматически при
создании копии удаленного репозитария; все команды, связанные с удаленной
работой, будут по умолчанию использовать именно эту удаленную ветку (обычно
называется «origin»).
Рассмотрим эти команды.
3.2 git clone — создание копии (удаленного) репозитария
Для начала работы с центральным репозитарием, следует создать копию
оригинального проекта со всей его историей локально:
git clone /home/username/project myrepo — клонируем репозитарий с той же машины
в директорию myrepo.
git clone ssh://user@somehost:port/
user/repository — клонируем репозитарий,
используя безопасный протокол ssh (для чего требуется завести у себя на машине
эккаунт ssh).
git clone git://user@somehost:port/
user/repository/project.git/ — у git имеется
и собственный протокол.
3.3 git fetch и git pull — забираем изменения из центрального репозитария (из удаленной ветки)
Для синхронизации текущей ветки с репозитарием используются команды git fetch и
git pull.
git fetch — забрать изменения удаленной ветки из репозитария по умолчания,
основной ветки; той, которая была использована при клонировании
репозитария. Изменения обновят удаленную ветку (remote tracking branch), после
чего надо будет провести слияние с локальной ветку командой git merge.
git fetch /home/username/project — забрать изменения из определенного
репозитария.
Возможно также использовать синонимы для адресов, создаваемые командой git remote:
git remote add username-project /home/username/project
git fetch username-project — забрать изменения по адресу, определяемому
синонимом.
Естественно, что после оценки изменений, например, командой git diff, из надо
создать коммит слияния с основной:
git merge username-project/master
Команда git pull сразу забирает изменения и проводит слияние с активной веткой:
git pull — забрать из репозитария, для которого были созданы удаленные ветки по
умолчанию.
git pull username-project — забрать изменения из определенного репозитария.
Как правило, используется сразу команда git pull.
3.4 git push — вносим изменения в удаленный репозитарий (удаленную ветку)
После проведения работы в экспериментальной ветке, слияния с основной,
необходимо обновить удаленный репозитарий (удаленную ветку). Для этого
используется команда git push:
git push — отправить свои изменения в удаленную ветку, созданную при
клонировании по умолчанию.
git push ssh://yourserver.com/
you/proj.git master:experimental — отправить изменения
из ветки master в ветку experimental удаленного репозитария.
git push origin :experimental — в удаленном репозитарии origin удалить ветку experimental.
git push origin master:master — в удаленную ветку master репозитария origin (синоним
репозитария по умолчанию) ветки локальной ветки master.
4 git-о-день
В этом разделе будут показаны и разобраны подробно несколько обычных и чуть
меньше необычных для работы с git ситуаций.
4.1 Обычный workflow при работе с локальным репозитарием
Git обладает необычайной легкостью в использовании не только как распределенная
система контроля версий, но и в работе с локальными проектами. Давайте разберем
обычный цикл — начиная с создания репозитария — работы разработчика git над
собственным персональным проектом:
Почему именно так? Зачем отказываться от линейной модели? Хотя бы даже потому,
что у программиста появляется дополнительная гибкость: он может переключаться
между задачами (ветками); под рукой всегда остается «чистовик» — ветка
master; коммиты становятся мельче и точнее.
4.2 Workflow при работе с удаленным репозитарием
Предположим, что вы и несколько ваших напарников создали общественный
репозитарий, чтобы заняться неким общим проектом. Как выглядит самая
распространенная для git модель общей работы?
you/proj.git
… возможно, прошло некоторое время.
Итак, первым делом создаем (1) создаем копию удаленного репозитария (по
умолчанию команды вроде git pull и git push будут работать с ним). «Вытягиваем»
последние обновления (2); смотрим, что же изменилось(3); создаем новую ветвь и
переключаемся в нее (4); индексируем все изменения и одновременно создаем из них
коммит (5); переключаемся в главную ветвь (6), обновляем ее (7); проводим
слияние с веткой bad-feature(8) и, обнаружив и разрешив конфликт, делаем коммит
слияния (9).
После совершения коммита отслеживаем изменения(10), запускаем, например,
юнит-тесты и с ужасом обнаруживаем, что после слияния проект валится на большей
части тестов.
В принципе, тесты можно было прогнать и до коммита, в момент
слияния (между пунктами 8 и 9); тогда бы хватило «мягкого» резета.
Таким образом, приходится совершить «жесткий» (11) сброс произошедшего слияния,
ветки вернулись в исходное до состояние. После чего переключаемся в неудачную
ветку (12), вносим необходимые изменения и переименовываем ветку (13). Совершаем
коммит (14); переходим в главную ветку(15), опять ее обновляем (16). На этот раз
бесконфликтно делаем слияние (17), закидываем изменения в удаленный репозитарий
(18) и удаляем ненужную теперь ветку (19). Закрываем ноутбук, одеваемся и идем
домой под утро.
5 Заключение
В топике не рассмотрено несколько важных вопросов, вроде администрирования
общественного репозитария, интеграции с текстовыми редакторами или IDE,
использования SSH под Линукс и Windows; приветствуются замечания, и особенно
дополнения в раздел «git-о-день».
UPD: замечание по работе с удаленным репозитарием. При работе с git с точки зрения администрирования, создания общественных репозитариев, управления доступом, использования шифрованных соединений и так далее могут возникнуть определенные вопросы; причем в этой заметке они не освещаются никак. Например, выше описана работа с уже готовым удаленным репозитарием; его развертывание никак не освещено.
Это все я сейчас собираю в отдельный топик, которую и выкину сюда через неделю-полторы.