Проще говоря, удаленное хранилище — это не ваше собственное. Это может быть центральный сервер, персональный компьютер другого разработчика или даже ваша файловая система. Пока вы можете получить к нему доступ по какому-то сетевому протоколу, Git позволяет невероятно легко делиться информацией с другими репозиториями.
Основная роль удаленных репозиториев — представлять других разработчиков в своем собственном репозитории. Филиалы, с другой стороны, должны заниматься только разработкой проекта. Иными словами, не пытайтесь дать каждому разработчику свою собственную ветку для работы — дайте каждому полное хранилище и резервные ветви для разработки функций.
Эта глава начинается с описания механики удаленных устройств, а затем представлены два наиболее распространенных рабочих процесса совместной работы на основе Git: централизованный рабочий процесс и рабочий процесс интегратора.
Манипулирование пультами
Подобно git branch
, команда git remote
используется для управления соединениями с другими репозиториями. Remotes — это не что иное, как закладки для других репозиториев — вместо того, чтобы вводить полный путь, они позволяют вам ссылаться на него с удобным для пользователя именем. Мы узнаем, как мы можем использовать эти закладки в Git Below.
Листинг Remotes
Вы можете просмотреть существующие пульты, вызвав команду git remote
без аргументов:
1
|
git remote
|
Если у вас нет пультов, эта команда не выводит никакой информации. Если вы использовали git clone
для получения своего хранилища, вы увидите удаленный источник. Git автоматически добавляет это соединение, предполагая, что вы, вероятно, захотите взаимодействовать с ним в будущем.
Вы можете запросить немного больше информации о ваших пультах с флагом -v
:
1
|
git remote –v
|
Это отображает полный путь к хранилищу. Указание удаленных путей обсуждается в следующем разделе.
Создание Remotes
Команда git remote add
создает новое соединение с удаленным репозиторием.
1
|
git remote add <name> <path-to-repo>
|
После выполнения этой команды вы можете обратиться к репозиторию Git в <path-to-repo>
используя <name>
. Опять же, это просто удобная закладка для длинного имени пути — она не создает прямой ссылки на чей-либо репозиторий.
Git принимает множество сетевых протоколов для указания местоположения удаленного репозитория, включая file://
, ssh://
, http://
и его собственный протокол git://
. Например:
1
|
git remote add some-user ssh://[email protected]/some-user/some-repo.git
|
После выполнения этой команды вы можете получить доступ к хранилищу по адресу github.com/some-user/some-repo.git
используя только some-user
. Поскольку мы использовали ssh://
в качестве протокола, вам, вероятно, будет предложено ввести пароль SSH, прежде чем вы сможете что-либо делать с учетной записью. Это делает SSH хорошим выбором для предоставления доступа на запись разработчикам, тогда как HTTP-пути обычно используются для предоставления доступа только для чтения. Как мы скоро обнаружим, это разработано как функция безопасности для распределенных сред.
Удаление Remotes
Наконец, вы можете удалить удаленное соединение с помощью следующей команды:
1
|
git remote rm <remote-name>
|
Удаленные филиалы
Коммиты могут быть атомной единицей управления версиями на основе Git, но ветки являются средой, в которой взаимодействуют удаленные репозитории. Удаленные ветки действуют так же, как локальные ветки, которые мы уже рассмотрели, за исключением того, что они представляют ветку в чьем-либо хранилище.
После того, как вы загрузили удаленную ветку, вы можете проверять, объединять и расширять ее, как и любую другую ветку. Это дает очень короткую кривую обучения, если вы понимаете, как использовать ветки локально.
Извлечение удаленных веток
Загрузка веток из другого хранилища называется извлечением . Чтобы получить удаленную ветку, вы можете указать репозиторий и ветку, которую вы ищете:
1
|
git fetch <remote> <branch>
|
Или, если вы хотите загрузить каждую ветку в <remote>
, просто опустите имя ветки. После загрузки вы можете увидеть загруженные ветки, передав опцию -r
в git branch
:
1
|
git branch –r
|
Это дает вам список веток, который выглядит примерно так:
1
2
3
|
origin/master
origin/some-feature
origin/another-feature
|
Удаленные ветви всегда имеют префикс удаленного имени ( origin/
), чтобы отличать их от локальных ветвей.
Помните, Git использует удаленные репозитории в качестве закладок, а не соединения в реальном времени с другими репозиториями. Удаленные ветки являются копиями локальных веток другого хранилища. Вне фактической выборки репозитории являются полностью изолированными средами разработки. Это также означает, что Git никогда не будет автоматически выбирать ветки для доступа к обновленной информации — вы должны сделать это вручную.
Но это хорошо, так как это означает, что вам не нужно постоянно беспокоиться о том, что все остальные вносят в вашу работу. Это возможно только из-за нелинейного рабочего процесса, включенного в ветвях Git.
Проверка удаленных ветвей
В любом случае, удаленные ветви ведут себя как ветви только для чтения. Вы можете безопасно просматривать их историю и просматривать их коммиты с помощью git checkout
, но вы не можете продолжить их разработку, прежде чем интегрировать их в свой локальный репозиторий. Это имеет смысл, если учесть тот факт, что удаленные ветви являются копиями коммитов других пользователей.
Синтаксис ..
очень полезен для фильтрации журнала. Например, следующая команда отображает любые новые обновления от origin/master
, которых нет в вашей локальной ветке master
. Обычно рекомендуется выполнить это до объединения изменений, чтобы вы точно знали, что интегрируете:
1
|
git log master..origin/master
|
Если это выводит какие-либо коммиты, это означает, что вы находитесь за официальным проектом, и вам, вероятно, следует обновить свой репозиторий. Это описано в следующем разделе.
Можно извлекать удаленные ветви, но это переведет вас в отключенное состояние HEAD
. Это безопасно для просмотра изменений других пользователей перед их интеграцией, но любые добавленные вами изменения будут потеряны, если вы не создадите новую подсказку локальной ветки для ссылки на них.
Слияние / перебазирование
Конечно, весь смысл извлечения заключается в интеграции полученных удаленных веток в ваш локальный проект. Допустим, вы являетесь участником проекта с открытым исходным кодом, и вы работали над функцией под названием some-feature
. По мере продвижения «официального» проекта (обычно указываемого по origin
) вы можете захотеть включить его новые коммиты в ваш репозиторий. Это гарантирует, что ваша функция по-прежнему работает с новейшими разработками.
К счастью, вы можете использовать точно такую же команду git merge
чтобы включить изменения из origin/master
в вашу ветку возможностей:
1
2
3
|
git checkout some-feature
git fetch origin
git merge origin/master
|
Поскольку ваша история разошлась, это приводит к трехстороннему слиянию, после которого ваша ветвь с some-feature
получает доступ к самой последней версии официального проекта.
Однако частое слияние с origin/master
просто для получения обновлений в конечном итоге приводит к истории, изобилующей бессмысленными коммитами слияния. В зависимости от того, насколько тщательно ваша функция должна отслеживать остальную часть кода, перебазировка может стать лучшим способом интеграции изменений:
1
2
3
|
git checkout some-feature
git fetch origin
git rebase origin/master
|
Как и при локальном перебазировании, это создает совершенно линейную историю, свободную от лишних коммитов слияния:
Перебазирование / слияние удаленных веток имеет те же компромиссы, что и обсуждаемые в главе о локальных ветвях.
тянущий
Поскольку последовательность выборки / слияния является таким распространенным явлением в распределенной разработке, Git предоставляет команду pull
в качестве удобного ярлыка:
1
|
git pull origin/master
|
Это выбирает основную ветвь источника, а затем объединяет ее с текущей веткой за один шаг. Вы также можете передать опцию --rebase
чтобы использовать git rebase
вместо git merge
.
Нажимать
Чтобы дополнить команду git fetch
, Git также предоставляет команду push
. Выдавливание — это почти противоположность извлечения, при этом извлечение ветвей импорта приводит к выталкиванию веток экспорта в другой репозиторий.
1
|
git push <remote> <branch>
|
Приведенная выше команда отправляет локальный <branch>
в указанный удаленный репозиторий. За исключением того, что вместо удаленной ветви git push
создает локальную ветку. Например, выполнение git push mary my-feature
в вашем локальном репозитории будет выглядеть следующим образом с точки зрения Мэри (ваш репозиторий не будет затронут push).
Обратите внимание, что my-feature
— это локальная ветвь в репозитории Mary, тогда как это была бы удаленная ветвь, если бы она сама ее получила.
Это делает толкание опасной операцией. Представьте, что вы разрабатываете в своем собственном локальном репозитории, когда внезапно из ниоткуда появляется новый локальный филиал. Но предполагается, что репозитории являются полностью изолированными средами разработки, так почему же вообще должен существовать git push
? Как мы вскоре обнаружим, push является необходимым инструментом для поддержки общедоступных Git-репозиториев.
Удаленные рабочие процессы
Теперь, когда у нас есть общее представление о том, как Git взаимодействует с другими репозиториями, мы можем обсудить реальные рабочие процессы, которые поддерживаются этими командами. Две наиболее распространенные модели сотрудничества: централизованный рабочий процесс и рабочий процесс интегратора. Пользователям SVN и CVS должно быть вполне комфортно с духом централизованной разработки Git, но использование Git означает, что вы также сможете использовать его высокоэффективные возможности слияния. Рабочий процесс интегратора является типичной распределенной моделью совместной работы и невозможен в чисто централизованных системах.
Читая эти рабочие процессы, помните, что Git рассматривает все репозитории как равные. В соответствии с Git не существует «основного» репозитория, как в случае с SVN или CVS. «Официальная» кодовая база — это просто соглашение проекта — единственная причина, по которой это официальный репозиторий, заключается в том, что именно там находятся удаленные точки origin
каждого.
Общественные (голые) хранилища
Каждая модель сотрудничества включает по крайней мере один общедоступный репозиторий, который служит отправной точкой для нескольких разработчиков. Публичные репозитории имеют уникальное ограничение: они не должны иметь рабочий каталог. Это не позволяет разработчикам случайно перезаписывать работу друг друга с помощью git push
. Вы можете создать пустой репозиторий, передав опцию --bare
в git init
:
1
|
git init —bare <path>
|
Общедоступные репозитории должны функционировать только как хранилища, а не как среда разработки. Это достигается путем добавления расширения .git
к пути к файлу хранилища, поскольку внутренняя база данных хранилища находится в корне проекта, а не в подкаталоге .git
. Итак, полный пример может выглядеть так:
1
|
git init —bare some-repo.git
|
Помимо отсутствия рабочего каталога, в пустом хранилище нет ничего особенного. Вы можете добавить удаленные соединения, нажать на него и извлечь из него обычным способом.
Централизованный рабочий процесс
Централизованный рабочий процесс лучше всего подходит для небольших групп, где у каждого разработчика есть доступ на запись в репозиторий. Это позволяет сотрудничать, используя единый центральный репозиторий, очень похожий на рабочий процесс SVN или CVS. В этой модели все изменения должны передаваться через центральный репозиторий, который обычно хранится на сервере для обеспечения совместной работы через Интернет.
Разработчики индивидуально работают в своем локальном репозитории, который полностью изолирован от всех остальных. Как только они завершили функцию и готовы поделиться своим кодом, они очищают его, интегрируют в свой локальный master
и помещают в центральный репозиторий (например, origin
). Это также означает, что каждому разработчику необходим SSH-доступ к центральному хранилищу.
Затем все остальные могут получить новые коммиты и включить их в свои локальные проекты. Опять же, это может быть сделано слиянием или перебазированием, в зависимости от соглашений вашей команды.
Это основной процесс, стоящий за централизованными рабочими процессами, но он сталкивается с трудностями, когда несколько пользователей пытаются одновременно обновить центральное хранилище. Представьте себе сценарий, в котором два разработчика завершили функцию, объединили ее с локальным master
и попытались опубликовать ее одновременно (или близко к ней).
Тот, кто первым доберется до сервера, может выполнить свои коммиты как обычно, но затем второй разработчик застрянет с расходящейся историей, и Git не сможет выполнить ускоренное слияние. Например, если разработчик по имени Джон отправит свои изменения прямо перед Мэри, мы увидим конфликт в репозитории Мэри:
Единственный способ сделать так, чтобы мастер источника (обновленный Джоном) совпадал с master
Мэри, — это перезаписать коммит Джона. Очевидно, это было бы очень плохо, поэтому Git прерывает push и выводит сообщение об ошибке:
1
2
|
!
error: failed to push some refs to ‘some-repo.git’
|
Чтобы исправить эту ситуацию, Мария должна синхронизироваться с центральным хранилищем. Тогда она сможет продвигать свои изменения обычным способом.
1
2
3
|
git fetch origin master
git rebase origin/master
git push origin master
|
Помимо этого, централизованный рабочий процесс является относительно простым. Каждый разработчик находится в своем локальном хранилище, периодически вытягивая / подталкивая к центральному хранилищу, чтобы поддерживать все в актуальном состоянии. Это удобный рабочий процесс для настройки, поскольку требуется только один сервер, и он использует существующие функции SSH.
Рабочий процесс интегратора
Рабочий процесс интегратора представляет собой распределенную модель разработки, в которой все пользователи поддерживают свой собственный общедоступный репозиторий, в дополнение к своему частному. Он существует как решение проблем безопасности и масштабируемости, присущих централизованному рабочему процессу.
Основным недостатком централизованного рабочего процесса является то, что каждому разработчику требуется принудительный доступ ко всему проекту. Это хорошо, если вы работаете с небольшой группой доверенных разработчиков, но представьте себе сценарий, в котором вы работаете над проектом программного обеспечения с открытым исходным кодом, и незнакомец обнаружил ошибку, исправил ее и хочет включить обновление в программу. основной проект. Вы, вероятно, не хотите предоставлять ему или ей push-доступ к центральному хранилищу, так как он или она может начать выдавать все виды случайных коммитов, и вы фактически потеряете контроль над проектом.
Но вы можете сказать, чтобы участник внес изменения в свой публичный репозиторий. Затем вы можете вставить его исправление в свой личный репозиторий, чтобы убедиться, что в нем нет необъявленного кода. Если вы одобряете его вклады, все, что вам нужно сделать, — это объединить их в локальный филиал и, как обычно, отправить его в основной репозиторий. Вы стали интегратором , в дополнение к обычному разработчику:
В этом рабочем процессе каждому разработчику требуется только принудительный доступ к своему общедоступному репозиторию. Участник использует SSH для отправки в свой общедоступный репозиторий, но интегратор может извлекать изменения через HTTP (протокол только для чтения). Это обеспечивает более безопасную среду для всех, даже когда вы добавляете больше соавторов:
Обратите внимание, что команда все еще должна договориться об одном «официальном» репозитории, из которого можно извлечь, иначе изменения будут применены не по порядку, и все будут очень быстро не синхронизированы. На приведенной выше схеме «Ваш публичный репо» является официальным проектом.
Как интегратор, вы должны отслеживать больше удаленных устройств, чем в централизованном рабочем процессе, но это дает вам свободу и безопасность для внесения изменений от любого разработчика без угрозы стабильности проекта.
Кроме того, рабочий процесс интегратора не имеет единой точки доступа, которая могла бы стать дроссельной катушкой для совместной работы. В централизованных рабочих процессах все должны быть полностью обновлены перед публикацией изменений, но это не относится к распределенным рабочим процессам. Опять же, это прямой результат нелинейного стиля разработки, реализованного в ветке Git.
Это огромные преимущества для крупных проектов с открытым исходным кодом. Организация сотен разработчиков для работы над одним проектом была бы невозможна без безопасности и масштабируемости распределенного сотрудничества.
Вывод
Поддержка этих централизованных и распределенных моделей сотрудничества — это все, что Git должен был когда-либо делать. Рабочий каталог, сцена, коммиты, ветки и удаленные устройства были специально разработаны для включения этих рабочих процессов, и практически все в Git вращается вокруг этих компонентов.
В соответствии с философией UNIX, Git был разработан как набор взаимодействующих инструментов, а не как единственная монолитная программа. Продолжая изучать многочисленные возможности Git, вы обнаружите, что очень легко адаптировать отдельные команды к совершенно новым рабочим процессам.
Теперь я оставляю вам право применять эти концепции в реальных проектах, но когда вы начнете включать Git в свой ежедневный рабочий процесс, помните, что это не серебряная пуля для управления проектами. Это всего лишь инструмент для отслеживания ваших файлов, и никакие глубокие знания Git не могут компенсировать случайный набор соглашений в группе разработчиков.
Этот урок представляет собой главу от Git Succinctly , бесплатной электронной книги от команды Syncfusion .