GitHub: работа с ветками и коммитами
В предыдущих статьях мы рассказывали, что такое GitHub, как его настроить и как опубликовать свой проект. Но это лишь малая часть его инструментов. Одним из ключевых моментов для GitHub является работа с ветками — разбираемся с ними в этой статье.
Ветка (branch) — это история коммитов. Давайте сначала разберемся, что это такое.
Коммит (commit) — это информация об измененных файлах. Коммит состоит из автора коммита, измененных файлов, HEAD и времени. Для примеров мы будем использовать репозиторий и сделаем первый коммит, который отправим на сервер. Он нужен для того, чтобы разграничивать задачки. Так будет понятно, какой код в истории относится к той или иной задаче, чтобы потом мы могли быстро понять суть.
Например, у нас задача — сделать блок формы. Для этого мы сделаем нужные изменения в файле index.html & style.css, и даже через месяц сможем при помощи истории изменений просмотреть измененные куски кода именно для этого блока.
При помощи команды git log в консоли мы можем отслеживать историю коммитов в ветке.

На самом GitHub мы можем увидеть последний коммит в файле и последний коммит в ветке. Всю историю мы можем просмотреть, кликнув по кнопке n commits, где n — количество запущенных на сервер коммитов. У нас в ветке пока что один коммит, поэтому на ссылке надпись 1 commit.

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

Если вы кликните по сообщению в коммите, в нашем случае это add first commit, то попадёте в список всех изменённых файлов.

Теперь подробнее разберем, как создавать коммит. Для начала нам нужно будет поменять файлы или добавить новые, чтобы было что коммитить, так как коммит — это история изменений. Как правило, в коммит включают изменения по одной задаче.
В нашем примере мы изменим содержание страницы index.html и добавим стили в style.css.

Изменения, не включенные в коммит, мы можем просмотреть при помощи команды git status.

Чтобы добавить файлы в коммит, мы будем использовать git add. Здесь мы можем указать нужные нам файлы для коммита, например, index.html. Если после этого мы сделаем git status, то эти файлики подсветятся зелёным — это означает, что мы можем добавить их к коммиту.

Но не всегда удобно вручную вбивать все изменённые файлы. В GitHub мы можем воспользоваться командой git add . — точка означает, что в коммит добавятся все изменённые файлы.

Теперь мы можем создать наш коммит при помощи команды git commit -m ‘текст коммита’. В тексте обычно рассказывается в паре слов о том, что было сделано — например, «добавили стили для index.html». Название коммитов пишут на русском или английском языке — зависит от того, как вы договоритесь с командной. После того, как вы создадите коммит, он появится у вас в истории.

Если мы запушим наш результат на GitHub, то увидим наш коммит.

У нас в коммите в сообщении есть опечатка, мы можем поменять подпись к последнему коммиту при помощи команды git commit —amend.


После того, как мы поменяли наш коммит локально, запушим его на сервер при помощи ключа force. Обычный push не сработает, так как у нас уже есть коммит на сервере — здесь будьте аккуратны, ведь вы меняете историю не только локально, но и удалённо.

Теперь поговорим про ветки (branch). Ветка — это история изменений. Сейчас у в репозитории одна ветка main, в которой хранится стабильная версия. Как правило, новые задачи делаются в новых ветках, а потом вливаются в main после ревью кода.
Посмотрим, как выглядит наша ветка с двумя коммитами в графике.

Представим, что у нас есть задача — сделать форму на главной странице. Для этого создадим новую ветку git checkout -b form-index (ключ -b означает, что мы создаем новую ветку).
Ветки можно просматривать при помощи команды git branch.

История наших коммитов пока одинаковая — что у main, что у form-index. git checkout main без ключа -b означает, что мы переключаемся на уже существующую ветку.
Пробежимся git log и сравним наши ветки.

Тем не менее, если мы зайдем на GitHub, то обнаружим, что у нас там только одна ветка — main. Так происходит, потому что ветка form-index существует пока только на нашем компьютере, то есть локально.

Чтобы наша новая ветка появилась на сервере, нам нужно запушить наши изменения.


Если посмотрим на историю коммитов в form, то увидим, что она отличается от main на один коммит.

Мы можем создавать новые ветки не только из main, но и из других веток — так делают редко. Самое главное здесь понять, что если мы создали новую ветку из другой ветки, то мы наследуем историю коммитов ветки, из которой создали ветвление, но только в момент создания.
Давайте создадим ветку form-index-fix и посмотрим на историю коммитов в ней.

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

Если ветка потеряла свою актуальность, мы можем её удалить локально при помощи команды git branch -D название ветки. Здесь важно отметить, что вы не можете удалить ветку, если вы сейчас в ней — обязательно нужно переключить её.

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

Git имеет репутацию запутывающего инструмента. Пользователи натыкаются на терминологию и формулировки, которые вводят в заблуждение. Это более всего проявляется в «перезаписывающих» историю командах, таких как git cherry-pick или git rebase. По моему опыту, первопричина путаницы — интерпретация коммитов как различий, которые можно перетасовать. Однако коммиты — это не различия, а снимки! Я считаю, что Git станет понятным, если поднять занавес и посмотреть, как он хранит данные репозитория. Изучив модель хранения данных мы посмотрим, как новый взгляд помогает понять команды, такие как git cherry-pick и git rebase.
Если хочется углубиться по-настоящему, читайте главу о внутренней работе Git (Git internals) книги Pro Git. Я буду работать с репозиторием git/git версии v2.29.2. Просто повторяйте команды за мной, чтобы немного попрактиковаться.
Хеши — идентификаторы объектов
Самое важное, что нужно знать о Git-объектах, — это то, что Git ссылается на каждый из них по идентификатору объекта (OID для краткости), даёт объекту уникальное имя.
Чтобы найти OID, воспользуемся командой git rev-parse. Каждый объект, по сути, — простой текстовый файл, его содержимое можно проверить командой git cat-file -p.
Мы привыкли к тому, что OID даны в виде укороченной шестнадцатеричной строки. Строка рассчитана так, чтобы только один объект в репозитории имел совпадающий с ней OID. Если запросить объект слишком коротким OID, мы увидим список соответствующих подстроке OID.
Блобы — это содержимое файлов
На нижнем уровне объектной модели блобы — содержимое файла. Чтобы обнаружить OID файла текущей ревизии, запустите git rev-parse HEAD:<path>, а затем, чтобы вывести содержимое файла — git cat-file -p <oid>.
Если я отредактирую файл README.md на моём диске, то git status предупредит, что файл недавно изменился, и хэширует его содержимое. Когда содержимое файла не совпадает с текущим OID в HEAD:README.md, git status сообщает о файле как о «модифицированном на диске». Таким образом видно, совпадает ли содержимое файла в текущей рабочей директории с ожидаемым содержимым в HEAD.
Деревья — это списки каталогов
Обратите внимание, что блобы хранят содержание файла, но не его имя. Имена берутся из представления каталогов Git — деревьев. Дерево — это упорядоченный список путей в паре с типами объектов, режимами файлов и OID для объекта по этому пути. Подкаталоги также представлены в виде деревьев, поэтому деревья могут указывать на другие деревья!

Воспользуемся диаграммами, чтобы визуализировать связи объектов между собой. Красные квадраты — наши блобы, а треугольники — деревья.
Деревья дают названия каждому подпункту и также содержат такую информацию, как разрешения на файлы в Unix, тип объекта (blob или tree) и OID каждой записи. Мы вырезаем выходные данные из 15 верхних записей, но можем использовать grep, чтобы обнаружить, что в этом дереве есть запись README.md, которая указывает на предыдущий OID блоба.
При помощи путей деревья могут указывать на блобы и другие деревья. Имейте в виду, что эти отношения идут в паре с именами путей, но мы не всегда показываем эти имена на диаграммах.
Само дерево не знает, где внутри репозитория оно находится, то есть указывать на дерево — роль объектов. Дерево, на которое ссылается <ref>^
Коммиты — это снапшоты
Коммит — это снимок во времени. Каждый содержит указатель на своё корневое дерево, представляющее состояние рабочего каталога на момент снимка.
В коммите есть список родительских коммитов, соответствующих предыдущим снимкам. Коммит без родителей — это корневой коммит, а коммит с несколькими родителями — это коммит слияния.
Коммиты также содержат метаданные, которые описывают снимки, например автора и коммиттера (включая имя, адрес электронной почты и дату) и сообщение о коммите. Сообщение о коммите для автора коммита — это возможность описать цель коммита по отношению к родителям.

Например, коммит в v2.29.2 в Git-репозитории описывает этот релиз, также он авторизован, а его автор — член команды разработки Git.
Заглянув немного дальше в историю при помощи git log, мы увидим более подробное сообщение о коммите, оно рассказывает об изменении между этим коммитом и его родителем.
Круги на диаграммах будут представлять коммиты:
Квадраты — это блобы. Они представляют содержимое файла.
Треугольники — это деревья. Они представляют каталоги.
Круги — это коммиты. Снапшоты во времени.
Ветви — это указатели
В Git мы перемещаемся по истории и вносим изменения, в основном не обращаясь к OID. Это связано с тем, что ветви дают указатели на интересующие нас коммиты. Ветка с именем main — на самом деле ссылка в Git, она называется refs/heads/main. Файлы ссылок буквально содержат шестнадцатеричные строки, которые ссылаются на OID коммита. В процессе работы эти ссылки изменяются, указывая на другие коммиты.
Это означает, что ветки существенно отличаются от Git-объектов. Коммиты, деревья и блобы неизменяемы (иммутабельны), это означает, что вы не можете изменить их содержимое. Изменив его, вы получите другой хэш и, таким образом, новый OID со ссылкой на новый объект!
Ветки именуются по смыслу, например, trunk [ствол] или my-special-object. Ветки используются, чтобы отслеживать работу и делиться её результатами. Специальная ссылка HEAD указывает на текущую ветку. Когда коммит добавляется в HEAD, HEAD автоматически обновляется до нового коммита ветки. Создать новую ветку и обновить HEAD можно при помощи флага git -c:
Обратите внимание: когда создавалась my-branch, также был создан файл (.git/refs/heads/my-branch) с текущим OID коммита, а файл .git/HEAD был обновлён так, чтобы указывать на эту ветку. Теперь, если мы обновим HEAD, создав новые коммиты, ветка my-branch обновится так, что станет указывать на этот новый коммит!
Общая картина
Посмотрим на всю картину. Ветви указывают на коммиты, коммиты — на другие коммиты и их корневые деревья, деревья указывают на блобы и другие деревья, а блобы не указывают ни на что. Вот диаграмма со всеми объектами сразу:

Время на диаграмме отсчитывается слева направо. Стрелки между коммитом и его родителями идут справа налево. У каждого коммита одно корневое дерево. HEAD указывает здесь на ветку main, а main указывает на самый недавний коммит.
Корневое дерево у этого коммита раскинулось полностью под ним, у остальных деревьев есть указывающие на эти объекты стрелки, потому что одни и те же объекты доступны из нескольких корневых деревьев! Эти деревья ссылаются на объекты по их OID (их содержимое), поэтому снимкам не нужно несколько копий одних и тех же данных. Таким образом, объектная модель Git образует дерево хешей.
Рассматривая объектную модель таким образом, мы видим, почему коммиты — это снимки: они непосредственно ссылаются на полное представление рабочего каталога коммита!
Вычисление различий
Несмотря на то, что коммиты — это снимки, мы часто смотрим на коммит в его историческом представлении или видим его на GitHub как diff. На самом же деле сообщение о коммите часто ссылается на различие. генерируемое динамически из данных снимка путём сравнения корневых деревьев коммита и его родителя. Git может сравнить не только соседние снимки, но и два любых снимка вообще.
Чтобы сравнить два коммита, сначала рассмотрите их корневые деревья, которые почти всегда отличаются друг от друга. Затем в поддеревьях выполните поиск в глубину, следуя по парам, когда пути для текущего дерева имеют разные OID.
В примере ниже корневые деревья имеют разные значения для docs, поэтому мы рекурсивно обходим их. Эти деревья имеют разные значения для M.md, таким образом, два блоба сравниваются построчно и отображается их различие. Внутри docs N.md по-прежнему тот же самый, так что пропускаем их и возвращаемся к корневому дереву. После этого корневое дерево видит, что каталоги things имеют одинаковые OID, так же как и записи README.md.

На диаграмме выше мы заметили, что дерево things не посещается никогда, а значит, не посещается ни один из его достижимых объектов. Таким образом, стоимость вычисления различий зависит от количества путей с разным содержимым.
Теперь, когда понятно, что коммиты — это снимки, можно динамически вычислять разницу между любыми двумя коммитами. Почему тогда этот факт не общеизвестен? Почему новые пользователи натыкаются на идею о том, что коммит — это различие?
Одна из моих любимых аналогий — дуализм коммитов как дуализм частиц, при котором иногда коммиты рассматриваются как снимки, а иногда — как различия. Суть дела в другом виде данных, которые не являются Git-объектами — в патчах.
Подождите, а что такое патч?
Патч — это текстовый документ, где описывается, как изменить существующую кодовую базу. Патчи — это способ самых разрозненных команд делиться кодом без коммитов в Git. Видно, как патчи перетасовываются в списке рассылки Git.
Патч содержит описание изменения и причину ценности этого изменения, сопровождаемые выводом diff. Идея такова: некий разработчик может рассматривать рассуждение как оправдание применения патча, отличающегося от копии кода нашего разработчика.
Git может преобразовать коммит в патч командой git format-patch. Затем патч может быть применён к Git-репозиторию командой git apply. В первые дни существования открытого исходного кода такой способ обмена доминировал, но большинство проектов перешли на обмен коммитами непосредственно через пул-реквесты.
Самая большая проблема с тем, чтобы делиться исправлениями, в том, что патч теряет родительскую информацию, а новый коммит имеет родителя, который одинаков с вашим HEAD. Более того, вы получаете другой коммит, даже если работаете с тем же родителем, что и раньше, из-за времени коммита, но при этом коммиттер меняется! Вот основная причина, по которой в объекте коммита Git есть разделение на «автора», и «коммиттера».
Самая большая проблема в работе с патчами заключается в том, что патч трудно применить, когда ваш рабочий каталог не совпадает с предыдущим коммитом отправителя. Потеря истории коммитов затрудняет разрешение конфликтов.
Идея перемещения патчей с места на место перешла в несколько команд Git как «перемещение коммитов». На самом же деле различие коммитов воспроизводится, создавая новые коммиты.
Если коммиты — это не различия, что делает git cherry-pick?
Команда git cherry-pick создаёт новый коммит с идентичным отличием от <oid>, родитель которого — текущий коммит. Git в сущности выполняет такие шаги:
Вычисляет разницу между <oid> коммита и его родителя.
Применяет различие к текущему HEAD.
Создаёт новый коммит, корневое дерево которого соответствует новому рабочему каталогу, а родитель созданного коммита — HEAD.
Перемещает ссылку HEAD в этот новый коммит.
После создания нового коммита вывод git log -1 -p HEAD должен совпадать с выводом git log -1 -p <oid>.
Важно понимать, что мы не «перемещали» коммит так, чтобы он был поверх нашего текущего HEAD, мы создали новый коммит, и его вывод diff совпадает со старым коммитом.
А что делает git rebase?
Команда git rebase — это способ переместить коммиты так, чтобы получить новую историю. В простой форме это на самом деле серия команд git cherry-pick, которая воспроизводит различия поверх другого, отличного коммита.
Самое главное: git rebase <target> обнаружит список коммитов, доступных из HEAD, но недоступных из <target>. С помощью команды git log —online <target>. HEAD вы можете отобразить их самостоятельно.
Затем команда rebase просто переходит в местоположению <target> и выполняет команды git cherry-pick в этом диапазоне коммитов, начиная со старых. В конце мы получили новый набор коммитов с разными OID, но схожих с первоначальным диапазоном.
Для примера рассмотрим последовательность из трёх коммитов в текущей ветке HEAD с момента разветвления target. При запуске git rebase target, чтобы определить список коммитов A, B, и C, вычисляется общая база P. Затем поверх target они выбираются cherry-pick, чтобы создать новые коммиты A’, B’ и C’.

Коммиты A’, B’ и C’ — это совершенно новые коммиты с общим доступом к большому количеству информации через A, B и C, но они представляют собой отдельные новые объекты. На самом деле старые коммиты существуют в вашем репозитории до тех пор, пока не начнётся сбор мусора.
С помощью команды git range-diff мы даже можем посмотреть на различие двух диапазонов коммитов! Я использую несколько примеров коммитов в репозитории Git, чтобы сделать rebase на тег v2.29.2, а затем слегка изменю описание коммита.
Обратите внимание: результирующий range-diff утверждает, что коммиты 17e7dbbcbc и 2aa8919906 «равны», а это означает, что они будут генерировать один и тот же патч. Вторая пара коммитов различается: показано, что сообщение коммита изменилось, есть правка в README.md, которой не было в исходном коммите.
Если пройти вдоль дерева, вы увидите, что история коммитов всё ещё существует у обоих наборов коммитов. Новые коммиты имеют тег v2.29.2 — в истории это третий коммит, тогда как старые имеют тег v2.28.0 — болеее ранний, а в истории он также третий.
Если коммиты – не отличия, тогда как Git отслеживает переименования?
Внимательно посмотрев на объектную модель, вы заметите, что Git никогда не отслеживает изменения между коммитами в сохранённых объектных данных. Можно задаться вопросом: «Откуда Git знает, что произошло переименование?»
Git не отслеживает переименования. В нём нет структуры данных, которая хранила бы запись о том, что между коммитом и его родителем имело место переименование.
Вместо этого Git пытается обнаружить переименования во время динамического вычисления различий. Есть два этапа обнаружения переименований: именно переименования и редактирования.
После первого вычисления различий Git исследует внутренние различия, чтобы обнаружить, какие пути добавлены или удалены. Естественно, что перемещение файла из одного места в другое будет выглядеть как удаление из одного места и добавление в другое. Git попытается сопоставить эти действия, чтобы создать набор предполагаемых переименований.
На первом этапе этого алгоритма сопоставления рассматриваются OID добавленных и удалённых путей и проверяется их точное соответствие. Такие точные совпадения соединяются в пары.
Вторая стадия — дорогая часть вычислений: как обнаружить файлы, которые были переименованы и отредактированы? Посмотреть каждый добавленный файл и сравните этот файл с каждым удалённым, чтобы вычислить показатель схожести в процентах к общему количеству строк. По умолчанию что-либо, что превышает 50 % общих строк, засчитывается как потенциальное редактирование с переименованием. Алгоритм сравнивает эти пары до момента, пока не найдёт максимальное совпадение.
Вы заметили проблему? Этот алгоритм прогоняет A * D различий, где A — количество добавлений и D — количество удалений, то есть у него квадратичная сложность! Чтобы избежать слишком долгих вычислений по переименованию, Git пропустит часть с обнаружением редактирований с переименованием, если A + D больше внутреннего лимита. Ограничение можно изменить настройкой опции diff.renameLimit в конфигурации. Вы также можете полностью отказаться от алгоритма, просто отключив diff.renames.
Я воспользовался знаниями о процессе обнаружения переименований в своих собственных проектах. Например, форкнул VFS for Git, создал проект Scalar и хотел повторно использовать большое количество кода, но при этом существенно изменить структуру файла. Хотелось иметь возможность следить за историей версий в VFS for Git, поэтому рефакторинг состоял из двух этапов:
Эти два шага позволили мне быстро выполнить git log —follow — <path>, чтобы посмотреть историю переименовывания.
Я сократил вывод: два этих последних коммита на самом деле не имеют пути, соответствующего Scalar/CommandLine/ScalarVerb.cs, вместо этого отслеживая предыдущий путь GVSF/GVFS/CommandLine/GVFSVerb.cs, потому что Git распознал точное переименование содержимого из коммита fb3a2a36 [RENAME] Rename all files.
Не обманывайтесь больше
Теперь вы знаете, что коммиты — это снапшоты, а не различия! Понимание этого поможет вам ориентироваться в работе с Git.
И теперь мы вооружены глубокими знаниями объектной модели Git. Не важно, какая у вас специализация, frontend, backend, или вовсе fullstack — вы можете использовать эти знания, чтобы развить свои навыки работы с командами Git’а или принять решение о рабочих процессах в вашей команде. А к нам можете приходить за более фундаментальными знаниями, чтобы иметь возможность повысить свою ценность как специалиста или вовсе сменить сферу.
Введение в Git. Что это такое и как использовать?
Git — это распределенная система контроля версий с открытым исходным кодом. Описание довольно сложное, давайте разберем его по частям:
- Система контроля: Git отслеживает и хранит ваш контент. Чаще всего от используется для программного кода.
- Система контроля версий: код, который хранится в Git может изменяться и добавляться. Часто над одним проектом параллельно работают несколько программистов. Система контроля версий сохраняет историю изменений и позволяет удобно с ней работать. Кроме того в Git есть такие удобные вещи как ветки и слияния.
- Распределенная система контроля версий: в Git есть удаленный репозиторий, который располагается на сервере, и локальный репозиторий на машине каждого разработчика. Это значит, что код не только хранится на центральном сервере. На каждом компьютере есть его полная копия.
Зачем вообще нужны системы контроля версий?
В реальном мире над проектами обычно параллельно трудятся сразу несколько разработчиков. Так как они имеют дело с одним и тем же кодом, при его изменении возможны конфликты. Git позволяет решать эту проблему.
Кроме того, часто изменяются требования к продукту. С системой контроля версий легко отменить внесенные изменения и вернуться к более старой версии.
И наконец, иногда требуется объединить в одну кодовую базу несколько параллельных проектов. В этом очень помогает концепция веток в Git.
Начинаем использовать Git
Установка
Здесь вы найдете детальную инструкцию по установке Git на любую операционную систему.
Проверьте установку, запустив в терминале команду
Создание локального репозитория
Создайте отдельную папку для вашего проекта. Давайте для примера назовем ее simple-git-demo .
Зайдите в нее и добавьте локальный git-репозиторий с помощью следующих команд:
Немного кода
Создайте новый файл demo.txt в папке проекта и запишите в него что-нибудь:
Вместо реального кода мы будет работать с обычным текстом. Это поможет сосредоточиться на концепциях Git, не отвлекаясь на специфические особенности языков программирования.
Работа с кодом и сохранение изменений
Добавление порции кода в локальный репозиторий называется коммитом, или фиксацией. До коммита код находится в «рабочей» или «промежуточной» области (staging area). Здесь можно отслеживать все файлы, которые должны быть зафиксированы.
Файлы, которые не добавлены в промежуточную область, не могут быть зафиксированы.
Добавление в рабочую область (staging)
Для добавления файла в промежуточную область используется следующая команда:
Можно добавить сразу несколько:
Чтобы добавить все файлы внутри директории проекта, используйте:
Обращайтесь с этой командой осторожно, так как она действительно добавляет ВСЕ файлы и папки в промежуточную область.
Фиксация изменений (commiting)
Чтобы сделать коммит, нужно выполнить команду:
«Initial Commit» — это сообщение фиксации. Используйте понятные и отражающие суть изменений сообщения.
Git status и git log
Теперь изменим demo.txt :
Статус
git status показывает, какие файлы были изменены и какие файлы находятся в промежуточной области. Команда выводит и другую информацию, которую мы пока можем проигнорировать.
Мы увидим, что demo.txt изменен, но еще не находится в рабочей области. Давайте добавим его:
и зафиксируем изменения:
Команда git log напечатает все сделанные коммиты вместе с их автором, датой и сообщением.
Ветки
До сих пор мы не создали ни одной ветки в Git. По умолчанию все коммиты попадают в ветку master.
Что такое ветка?
Ветка — это просто указатель на последний коммит в репозитории. В данный момент наша ветка master указывает на второй коммит с сообщением «demo.txt file is modified» .
Зачем нужно создавать несколько веток?
Разные ветки позволяют параллельно разрабатывать разную функциональность.
Изначально commit 1 и commit 2 выполнялись в ветке master. После второй фиксации создается новая ветка под названием test, и commit 3 и commit 4 добавляются в нее.
В то же время в ветку master тоже добавляются commit 3 и commit 4. То есть в разных ветках параллельно создаются коммиты. Сейчас тестовая ветка не связана с главной, но их можно объединить с помощью git merge . Этот вопрос будет рассмотрен позднее, а пока повторим схему с картинки.
Создайте новую ветку в локальном репозитории
Ветка создана, но мы все еще находимся в контексте ветки master. Чтобы переключиться на тестовую, нужно использовать команду
Вот теперь мы находимся на ветке test .
Увидеть полный список все веток локального репозитория поможет команда
Сделайте коммиты в новой ветке
Добавьте изменения в рабочую область и зафиксируйте их:
После этого коммита тестовая ветка опережает главную: она включает две ранее сделанные фиксации и одну новую.
Вы можете проверить историю коммитов в тестовой ветке, используя:
Слияние
Предположим, мы закончили какой-то этап разработки в тестовой ветке и теперь хотим вернуть весь код в главную, то есть объединить их (смержить).
Сначала вернитесь в ветку master:
Затем выполните команду merge :
Слияние должно быть успешным, так как в этом примере нет конфликтов кода. Но в реальных проектах они иногда возникают. Умение разрешать конфликты слияния приходит с опытом.
Запустите git log и вы увидите, что в мастер-ветке теперь также 3 коммита.
Удаленный Репозиторий
До сих пор мы работали только в локальном репозитории. Обычно так и происходит: разработчик пишет код на своем компьютере. Но затем он должен отправить свои изменения в удаленный репозиторий, чтобы их могли увидеть другие разработчики.
GitHub
Для создания удаленного репозитория мы будем использовать GitHub. Прежде всего вам нужно создать аккаунт.
После регистрации нажмите на кнопку Начать проект, чтобы создать новый репозиторий. Дайте ему имя git-blog-demo и нажмите кнопку Создать репозиторий.
На изображении выделен URL вашего репозитория, который вы должны увидеть на странице.
Чтобы указать вашему локальному репозиторию на удаленный, используйте следующую команду (вместе [repository url] введите адрес своего репозитория без квадратных скобок):
Git push
Теперь отправим весь код из локального репозитория в удаленный:
Он будет помещен из ветки master локального репозитория в ветку master удаленного репозитория.
Дополнительные команды
Git pull
Используется для извлечения последних изменений из удаленного репозитория в локальный. Удаленный код может обновляться другими разработчиками, поэтому необходимо поддерживать локальную версию в актуальном состоянияя:
Git clone
Используется для клонирования существующего удаленного репозитория на ваш компьютер.
Поздравления
Теперь вы знаете основы использования Git и можете переходить к более продвинутым концепциям!