Git: основы работы с инструментом(текстовая версия)
Программы разрабатывают группы людей. Конечно, есть энтузиасты, которые делают это в одиночку, но даже им приходится в какой-то момент задуматься, а как хранить кодовую базу своего решения? Можно было бы просто сохранять на своём локальном компьютере все данные, никак их не упорядочивая и в случае, если разработчиков несколько, передавать по сети эти файлики, чтобы объединять изменения от всех участников. Это привело бы к ручному труду, вероятным потерям и сложностям отката кода, если в нём написали ошибочные части. Для того, чтобы помочь в этих непростых ситуациях, придумалисистемы хранения кода. В рамках этого текста мы рассмотрим одну из таких систем под названием Git.
На сегодня его можно назвать стандартом индустрии. Мало кто в IT среде не слышал о таких продуктах, как GitHub, GitLab или Bitbucket. Все эти системы являются надстройками с интерфейсом над основной системой - Git. В чём её суть?
Система позволяет нам указать ей, что нужно запомнить содержимое файлов в директории с репозиторием, а после этого мы можем эти изменения отменить, если пожелаем или мы можем поделиться этими изменениями с другими людьми. В момент, когда мы планируем создавать новый проект, при помощи команды git init мы инициируем новый репозиторий в той директории, в которой будет хранится код нашего решения. Что произойдёт в этот момент? Будет создана скрытая директория .git, основная цель которой запоминать в каких файлах и какие изменения будут произведены. Сохранять состояние файлов она будет не самостоятельно, мы должны сами оповещать о том, что хотим запомнить их содержимое на тот момент времени, когда мы запускаем нужную для этого команду.
Коммиты
Тут стоит раскрыть механизм фиксации изменений. Если постараться всё упростить, то фиксация изменений проходит за четыре состояния файла в репозитории:
- он сохранён на файловой системе,
- он добавлен в отслеживаемое,
- отслеживаемое состояние зафиксировано в коммите,
- коммит отправлен в сетевой репозиторий.
Вот представь, у тебя есть файл, который ты только что создал в директории с локальным репозиторием. Гит о нём ещё ничего не знает, так как раньше этого файла не существовало. Но он знает, что он уже появился. Это можно отследить командой git status. Теперь мы можем сказать гиту, что он должен запомнить конкретно этот файл в его таком состоянии, выполняем команду git add и путь до файла, тем самым мы гарантируем, что когда в следующий раз выполним фиксацию - данные изменения будут записаны в коммите. Если мы выполним команду git status сейчас, то увидим такую картинку.
Теперь выполним фиксацию, то есть создадим коммит при помощи команды git commit -m, а в значении укажем краткое предложение, которое ёмко описывает что мы изменили. Выполняем git status и видим, что наши изменения теперь зафиксированы.
Допустим, что позже мы захотели изменить этот файл и добавить ещё один новый, тогда мы изменяем сохраняем файлы на диске. Выполняем команду git status, видим, что разные файлы у нас находятся в разных состояниях, относительно последней локальной фиксации. Добавляем в отслеживаемые оба файла и выполняем команду git status. Видим схожую картинку, как было после отслеживания первого файла. Заметь, что в первом случае я создал файл с нуля, а во втором сделал изменения в том файле, о котором гит уже знает, поэтому статусы у этих файлов разные. Ну и наконец зафиксируем все изменения командой git commit.
Как отменить коммиты?
Здесь стоит сказать, что зафиксированные или закоммиченные изменения можно откатить обратно, причём, до разных уровней. Для начала узнаем новую команду - git log.
Она позволяет нам посмотреть историю коммитов в нашем репозитории. Сейчас мы видим, что у нас есть два коммита, которые я делал в прошлый раз. Чтобы отменять любое их количество, у нас есть команда git reset и три основных способа это сделать:
- git reset --soft HEAD~1 отменяет последний коммит, но не вынимает файлы из отслеживаемых и оставляет все изменения файлов на файловой системе.
- git reset HEAD~1 отменяет последний коммит, вынимает файлы из отслеживаемых, но оставляет все изменения файлов на файловой системе.
- git reset --hard HEAD~1 отменяет последний коммит, вынимает файлы из отслеживаемых и полностью восстанавливает состояние файлов до предыдущего коммита.
Все взаимодействия стоит проверить командами git log, git status и ls до и после их исполнения, чтобы понять как оно работает.
Что означает запись HEAD~1?
Когда мы создаём коммит, то git не просто фиксирует это состояние, он ставит указатель HEAD, запоминает, что должен нам показывать те файлы и то их содержимое, которое было известно на момент этого коммита. Это как раз указатель что именно этот коммит является последним, головой всех наших коммитов. Тильда и единица как бы говорит гиту, откати голову на один коммит назад, если бы вместо единицы было бы написано три, то он бы откатил голову на три коммита. Способов работы с указателями много, их я перечислять не будут, просто чтобы не забивать тебе этим голову, достаточно знать хотя бы этот, чтобы иметь минимальное представление о том, как гит устроен, но если ты захочешь сам погрузиться в этом всё - единственно верный способ это читать официальную документацию. Да, там нудно и скучно, но зато фундаментально и точно корректно.
А мы сейчас пытаемся уловить суть: в какой-то момент, когда мы сами захотим, мы говорим гиту, что теперь он следит за состоянием и содержанием всех файлов в выбранной нами директории, после чего мы можем сообщить ему, что он должен запомнить, то есть зафиксировать то, как выглядит вся директория сейчас. В случае, если мы сделали ошибки и хотим вернуть всё обратно, то мы можем просто сказать гиту, что хотим вернуться на ту версию нашей директории, которую выберем сами из зафиксированных, и он вернёт её к этому виду.
Совместная работа
И вы спросите меня, как делиться этими директориями с другими? В нашем локальном репозитории мы должны сказать, что он связан с другим сетевым репозиторием, для того, чтобы иметь возможность выкачивать новые изменения оттуда к себе и отправлять свои изменения туда. Вот для этого как раз и существуют те самые Github’ы c Gitlab’ами и прочими BitBucket’ами. Они могут быть как частные, и использоваться только внутри той компании, где ты работаешь, так и публичные, как например, гитхаб доступен нам по ссылке GitHub.com. Мы можем создать там свой сетевой репозиторий и выкладывать свой код из локального копии репозитория туда. Тогда должен возникнуть вопрос: как попадают в сетевой репозиторий?
Вот мы пишем код, сохраняем его в файликах, фиксируем эти изменения в своей локальной копии репозитория. И на этот момент они есть только в ней, чтобы они отправились в сетевой репозиторий, мы должны сначала сказать нашему локальному репозиторию, что он связан с сетевым, при помощи команды git remote add <ссылка не репозиторий>. И только после этого мы можем выполнить отдельную команду git push, которая отправит наши изменения в сеть. И допустим, мы хотим поделиться этим кодом с нашем другом. Мы кидаем ему ссылку на наш сетевой репозиторий, а он у себя запускает команду git clone, которая позволяет ему создать копию текущего состояния сетевого репозитория у себя на компьютере и создать его локальную копию репозитория. Почему его? Потому что, если после того, как он сделал клонирование, ты сделаешь изменения в своей локальной копии - у него они не появятся. Они не появятся у него и после того, как ты отправишь свои изменения командой push в сетевой репозиторий. У него они появятся только после того, как он выполнит команду git pull, то есть вытянет текущее состояние сетевого репозитория в свою локальную копию.
В каждой копии, локальной или сетевой, не важно, всегда может быть собственное состояние всего содержимого репозитория. И чтобы отправлять свои изменения в сетевой репозиторий, нужно выполнять команду push и тогда она отправит все зафиксированные изменения, а чтобы вытянуть чужие изменения из сетевого репозитория к себе, нужно делать pull.
Отлично, теперь чуть усложним схему. Допустим, вы с другом работаете над одной программой вместе, он в своём файле, а ты в своём, почему это важно поймёшь чуть позже. Ты сделал изменения, отправил их в сетевой репозиторий, друг их стянул, начал работать над своей частью, а ты в этот момент нашёл ошибку у себя и решил её исправить. Пока ты исправлял, твой друг успел сделать свою часть, отправил её в сетевой репозиторий. Получается, что в хронологии изменений появилась новая запись, о которой твоему локальному репозиторию неизвестно. И теперь ты не сможешь отправить свои изменения до тех пор, пока не заберёшь изменения из сетевой части. Но ты не сможешь только отправлять, фиксировать состояние ты всё ещё можешь. Просто, перед тем, как делать push, тебе придётся сделать pull, в этот момент git сам заберёт все изменения из сети, отсортирует их по времени создания фиксаций и разрешит сделать push.
Что будет если мы поработаем с одним и тем же файлов или даже с одной и той же строкой? На самом деле, тут всё достаточно просто. Наш репозиторий уже находится в сети, мы продолжаем над ним работать, а между делом, в том же самом файле, наш друг уже что-то сделал и выложил в сетевой репозиторий. Мы честно приготовили свою часть и пытаемся отправить эти изменения, но гит увидит, что состояние этого файла изменилось с момента, когда мы последний раз забирали изменения, о чём он нам сообщит, сказав, что у него возник конфликт, он не знает какое из изменений считать более актуальным. И здесь мы можем помочь ему, выбрав один из трёх вариантов: сказать, что изменения в сетевом репозитории более правильные, а наши можно удалить, либо можно указать, что наши изменения более правильные, а в сети лежит что-то неактуальное. Либо третьим вариантом мы можем указать, что оба изменения нужны и требуется сохранить оба. В терминологии гита это называется merge conflicts, которые мы ему помогает решить, то есть сделать resolve. Во всех трёх случаях гит перестраивает дерево коммитов так, чтобы все изменения и наши и из сети могли сохраниться в истории коммитов, но при этом состояние файлов сохранилось в том виде, которое мы указали последним.
Как отменить коммит, который ты уже отправил в репозиторий? На самом деле, у нас есть несколько способов для этого, но правильный только один - использовать комманду git revert. Всё, что она сделает это самостоятельно отменит те изменения, которые были в коммите, зафиксирует эту отмену в новом коммите и после этого мы этот новый коммит можем отправить в сетевой репозиторий. Фактически, это не откат, это просто создание нового коммита, в котором обратно меняются файлы на предыдущее состояние. Но тот коммит, который мы отправили изначально с ошибкой, уже навсегда останется в истории коммитов.
Почему этот вариант правильный? Потому что гуру гита точно знают о том, что можно с очень дикой болью удалить этот коммит из истории, например, через git reset —hard, о котором я уже говорил выше. Вот только для того, чтобы это сработало нужно этот коммит удалить и у себя и в сетевом репозитории и, если его успели скачать другие, то и у них тоже. Иначе, гит не сможет понять какое состояние репозитория верное, откуда внезапно взялся коммит, которого больше нет нигде и тому, кто обладает этой деффектной копией, придётся клонировать его заново.
Вся совместная работа сводится к правильному управлению процессом слияния или merge - одним из основополагающих процессов в гите. На самом деле, этот процесс происходит каждый раз, когда мы делаем push или pull изменений. И чаще всего гит самостоятельно разбирается что можно применить, собственно, то, что новое, то и принимает, но в случае работы с одним файлом он не может гарантировать что лучше, потому что тут может не сработать правило - новое лучше и чтобы случайно не убрать то, что было нужно, он отдаёт этот процесс на откуп тому пользователю, который пытается слить изменения воедино. Стандартная стратегия называется recursive. Есть и другие, например, есть стратегия под названием octopus, эта стратегия применяется при попытки слияния более двух HEAD… Чего?!
Ветки
Да, тут такое дело, я не рассказал о ещё одной фундаментальной черте гита - ветки. Всё, что мы делали до этого: коммитили, откатывали, пушили, пуллили - всё это делали в так называемой ветке. Это набор коммитов, которые живут изолировано в своём пространстве до тех пор, пока мы не сольём их с ещё одной веткой. Сам процесс слияния чаще упоминается именно в контексте слияния веток, а не разрешения конфликтов двух коммитов в одной ветке. Всё равно не понятно что такое ветка? Ну смотри, ты хочешь взять всё, что есть в репозитории и поработать над большим количеством файлов. И твой коллега тоже хочет поработать над ними, но в рамках другой задачи. И, если мы ничего не знаем про ветки, то как будет выглядеть концепция? Каждый коммитит, пушит в репозиторий, но каждый раз, когда оба поработают над одним файлом - придётся делать разрешение конфликта при слиянии, что будет отнимать бесконечное количество времени. Поэтому, в правильной картине мира гита, параллельная работа двух и более людей должна производится в собственных ветках. То есть, они берут за основу состояние основной ветки, той, в которую мы создавали свои первые коммиты, при помощи специальной команды создают свою изолированную копию всех файлов в репозитории, то есть, ветку и работают в ней независимо от других. При этом, каждый раз, когда они пушат эти изменения в репозиторий, то у остальных участников проекта есть возможность переключиться на чужую ветку и тоже что-то начать в ней делать. От веток можно делать другие ветки или наоборот, можно сливать две ветки в одну. Ну и самое важное, что при переключении между ветками, для тебя, как для конечного пользователя, структура каталогов и файлов внутри репозитория выглядит так, будто состояние ветки это самое основное что у тебя есть. То есть, ты не видишь где-то рядом ещё одну структуру, а в своём каталоге свою, а наоборот, тебе показывают только тот набор и файлов и их состояние, на которые ты переключился.
Допустим, мы хотим создать свою ветку на основе той, в которой работали изначально. Во-первых, запоминаем команду git branch, которая позволяет нам увидеть, какие локальные ветки у нас есть и на какой мы находимся сейчас. Вот у меня сейчас одна ветка с названием main, в которой мы и работали всё это время. Для того, чтобы создать новую ветку, мне к команде git branch нужно через пробел дописать имя ветки, которую я хочу создать, например test. В ответ, гит говорит нам об успешном создании. Чтобы переключиться на новую ветку нам нужно написать git checkhout <имя ветки>. Теперь сделаем пару коммитов и отправим всё это в сетевой репозиторий. С другой стороны, наш второй разработчик тоже создал свою собственную ветку, сделал несколько изменений и отправил свою ветку в репозиторий. Мы видим, что эти два состояния не конфликтуют друг с другом и совершенно спокойно хранятся в изолированном виде. Более того, локальные репозитории двух этих разработчиков пока не знают даже о существовании чужих веток.
Потому что всё, что находится в удалённом репозитории, к себе нужно стягивать, то есть делать pull, но это не единственный способ узнать об изменении информации, есть ещё команда git fetch. Основное их отличие в том, что fetch вытягивает всю информацию, которую мы затребовали и сохраняет её в своём локальном скрытом каталоге, но не переключает наш указатель HEAD на то, что пришло более новое. А git pull делает и то, что делает fetch и сразу же пытается переключить указатель на более новое состояние той ветки, в которой мы работаем, при этом, естественно опять запускается механизм merge. То есть, очень грубо говоря, команда pull это просто короткий способ запустить fetch и merge друг за другом.
Почему я сказал, что вытягиваться будет та информация, которую мы затребовали? Потому что мы можем попросить вытащить состояние всего репозитория, а можем попросить вытащить конкретную ветку, чтобы не обновлять весь репозиторий сразу. И это важно, так как часто репозитории содержат большое количество файлов и вытягивать все ветки других разработчиков тебе просто не нужно, это лишь замедлит работу, а эти ветки ты никогда не будешь использовать сам. Но вот если будешь, то тебе необходимо их вытаскивать. И тогда, перед тобой встаёт выбор, выполнить просто команду git pull или git fetch, которые вытаскивают всё или через пробел указать имя ветки, чтобы они вытащили только нужное тебе.
Ветки можно не только создавать, но и удалять. Это делают в двух случаях - мы закончили работу над кодом и этот код попал в основную ветку. Очевидно, что ветка для этой фичи больше не нужна, держать её не имеет никакого смысла, поэтому убирают, чтобы не приходилось постоянно выкачивать излишки, которые и так уже есть в основной ветке. Второй случай удаления ветки - когда понимают, что над фичей больше не собираются работать, так как она больше не нужна. Такое тоже случается в процессе работы: приходит понимание, что эти правки уже есть в коде и они не нужны или создание нового функционала занимает слишком много времени, которое не согласовал бизнес, ну или код вообще вредоносный и делает только хуже.
Теги
Что там с тэгами, это ещё что? А это ещё один механизм, который позволяет пометить какой-то определённый коммит ключевыми словами. Мы уже видели команду без которой тэги не имеют смысла - команда называется checkout. Она позволяет переключаться на другие ветки, на определённые коммиты в этих ветках и даже на тэги. И так иногда случается, разработчикам нужно не просто переключиться на ветку, но и переключиться на конкретный коммит в этой ветке, например, потому что они именно от этого коммита хотят сделать новую ветки или потому что они хотят сделать сборку именно этого состояния общей кодовой базы. Все коммиты имеют свой хэш, это очень длинная строчка с буквами и цифрами, которая является уникальной для каждого коммита в этом репозитории. И так как мы с вами не машины, и запоминать эту длинную строку нам совсем неудобно, то были придуманны тэги. То есть, ты просто своим ёмким ключевым словом помечаешь коммит при помощи команды git tag, отправляешь его в общий репозиторий командой git push --tags, а после этого, другой разработчик может склонировать репозиторий и сделать git checkout на это вот ключевое слово и автоматически попадёт на нужный коммит. Ну и релизы помечают тэгами ровно для этого же, чтобы было понятно, что вот в этом состоянии был код, когда создавали новый дистрибутив.
Workflow
Раз уж мы столкнулись с ветками, то нельзя промолчать о процессе работы с ними. Начнём с того, что существует несколько так называемых воркфлоу, в рамках которых определяется какие ветки считаются основными, когда создаются остальные ветки и главное, в какой момент происходит процесс слияния веток друг с другом. Первый и, пожалуй, сам известный - gitflow. Смысл его в том, что у нас есть одна основная ветка, по-умолчанию её называют main. В этой ветке должен находится только тот код, который гарантированно зарелизен, то есть этот код уже оттестирован в других ветках, выпущен как собранный дистрибутив и является слепком этого самого релиза. От этой ветки создаётся ветка develop - это тот бранч, который используют для создания основных изменений и тестирования кода перед тем, как он попадёт в релиз, то есть в ветку main. Но так как над одним кодом могут работать несколько людей, то для каждой своей фичи, то есть для каждой задачи по доработке кода они создают отдельную ветку. Если это какое-то добавление нового функционала или улучшение существующего - ветки называют feature/, если в коде были обнаружены ошибки, то есть баги, то ветки называют bugfix/. Каждую из этих веток разработчик отдельно “обслуживает”, дополняет кодом по своей задаче и когда понимает, что задача выполнена и весь код написан - вливает её в ветку develop. В этот момент производится контрольная компиляция кода и проверка, что все тесты успешно проходят. После того, как всё, что было запланировано в релизе, оказалось выполнено - ветку develop вливают без удаления в ветку main, а на полученный коммит навешивают тэг с номером версии релиза. Я умолчал про ещё один тип веток и тип задач - hotfix. В русском языке их часто называют костыли, потому что иногда так случается, что выпущенная версия релиза внезапно упала на проде, но чтобы понять в чём конкретно ошибка и как её поправить, нужно потратить много времени, которого у прода, как обычно нет, им нужно решить проблему уже сейчас, чтобы не страдали клиенты. Тогда от ветки main создаётся ветка hotfix, в которой создают тот самый костыль, он должен как-то временно позволить пользоваться продуктом, чтобы как минимум не страдал остальной функционал системы. Его вливают в ветку main и сразу выпускают релиз с ним, чтобы отправить на прод, но ещё его же тут же отправляют в ветку develop, чтобы в кодовой базе разработчиков этот код тоже появился и его доработали до полноценно-рабочего состояния и не забыли о проблеме. Ура, самый фундаментальный workflow мы разобрали, теперь пойдём смотреть на то, что придумали другие, там есть варианты проще.
GtiHubFlow, он отличается тем, что выглядит намного проще предыдущего flow. Смысл в том, что у нас есть одна основная ветка, а все остальные изменения и доработки мы делаем в своих, короткоживущих ветках. Короткоживущая означает, что ветка создана только для выполнения текущей задачи и будет уничтожена после того, как пройдёт процесс слияния. А процесс слияния происходит в тот момент, когда задача выполнена. И всё, это весь flow.
Есть ещё один знаменитый процесс работы, называется GitLabFlow, как не трудно догадаться, это реализация workflow от разработчиков GitLab. Основное отличие от предыдущих в том, что у нас есть отдельная ветка так называемого staging, то есть установка на тестовое окружение, есть ветка для установки на production окружение. Если есть ещё какие-то окружения - у них есть свои ветки. Далее, разработчики все вместе рабоатют в одной ветка staging, производят изменения и все их доработки сразу попадают на staging окружение. Когда нужный набор доработок получен и релиз “сформирован”, ветку без удаления сливают с веткой следующего окружения. Если это прод, то в прод, если препрод, то в препрод и так далее. То есть, никаких короткоживущих веток у нас нет, каждая ветка под отдельное окружение, а все разработчики работают в общем пространстве и решают свои конфликты как только они появляются.
Каким из этих путей пойти - вопрос достаточно философский, каждый из них равнозначно может подойти или не подойти под конкретно твой проект, тут всё максимально ситуативно и нужно отталкиваться от процесса в компании, желаний команды и прочих мелочей. Процесс может покажется тебе слишком сложным, но если ты хотя бы раз его пройдёшь самостоятельно от начала и до конца, то эта сложность моментально улетучится.
Интерфейсы
На текущий момент времени есть три основных мастодонта на рынке, которые почти полностью покрыли потребность в сетевом хранении репозиториев: GitHub, Bitbucket и Gitlab. Все три обладают схожим базовым функционалом, и хоть отличаются некоторыми возможностями, но по своей сути едины - предоставляют возможность посмотреть содержимое репозитория, получить ссылку на клонирование репозитория, создать Request на слияние веток, посмотреть ветки и историю коммитов в них и раздать права на изменение репозиториев. Последнее, наверное, особо важное в рамках использования этих инструментов в промышленной разработке, так как компании часто хотят ограничить пользователей от бесконтрольного вмешательства в чужие репозитории, поэтому, так называемые, ролевые модели повсеместно используются при каждом удобном случае. Так же, стоит упомянуть, что во всех интерфейсах, которые поддерживают Merge и Pull Requests используется особая процедура, которая называется Code Review. Кратко, это процесс, в котором участвуешь ты, как создатель изменений, то есть ты создаёшь сам этот request, а так же другие разработчики, обычно, более опытные участники команды, которые должны посмотреть на твои изменения своими глазами и одобрить их, ну или наоборот, указать, что в каком-то конкретном месте нужна доработка. И вот пока они не одобрят внесение этих изменений, то и кнопка вливания изменений не должна стать активной. На самом деле, на эту же кнопку могут навешивать отдельные дополнительные автоматические проверки, например, должна пройти сборка этого кода в той системе, в которой мы его собираем в рамках нашей компании. После того, как сборка пройдёт успешно, у коммита появляется признак успешности, что тоже является некоторым гарантом работоспособности нашего кода. Но это тема для самостоятельного материала.
Ну и раз мы проговорили про удобство работы с сетевым репозиторием, то тут же проговорим про локальные удобства. Большинство из тех команд, которые я сегодня исполнял в консоли, можно буквально натыкивать в интерфейсах любых IDE. Тут тоже нет особых открытий, основные продукты, которыми пользуется подавляющее большинство это VSCode, как у меня, или IDEA от JetBrains. Опять же, у каждого есть свои особенности, но в сути своей они схожи: просто предоставляют возможность работы с текстовыми файлами, а поверх них используют подключаемые плагины для улучшения этой работы: всякие там линтеры, компиляторы, подсветки синтаксиса и всё вот такое вот, чтобы работать было максимально лениво.
Резюме
Напоследок, хотелось бы сказать, что я не перечислил все команды, которые могут быть использованы в этом инструменте. Есть, например, команда, которая позволяет скопировать в свою ветку один коммит и с другой, называется Cherry pick, с аналогией, что ты со всего дерева к себе забираешь только одну “вишенку”. Есть отдельная команда git merge, которая позволяет запустить автоматическую процедуру слияния двух и более веток в одну с автоматическим решением проблем, там, где это возможно. И у этой команды есть множество стратегий, которые позволяют проводить эту процедура по-разному. Вообще, при вливании другой ветки в свою, например, нового состояния основной ветки в свою фичовую, у тебя есть возможность не только влить изменения через merge commit, но и сделать так называемый rebase, то есть указать гиту, что мы меняем первоначальную точку создания ветки на то состояние, которое в основной ветке сейчас. В том же битбакете тэги можно навешивать напрямую в интерфейсе, только для локального использования их придётся вытягивать командой git pull. И таких мелочей наберётся ещё на парочку уроков, но мы не будем погружаться в эту часть, потому что всё это уже достаточно редко используется, в случаях, когда инструмент стали использовать не совсем в стандартном workflow или всё пошло “не по сценарию”. Поэтому все остальные команды и тонкости использования я оставлю для вас, для вашего самостоятельного изучения в тот момент, когда такие потребности появятся. А пока, давайте резюмируем всё, что мы получили в этом уроке.
Git это система управления версиями содержимого наших файлов. Она позволяет фиксировать эти изменения так, чтобы мы могли в любой момент вернуться к нему или переключиться на него. Мы так же можем делиться своими наработками в сетевых сервисах хранения git репозиториев и копировать чужие репозитории к себе, чтобы поработать в них. Вся работа ведётся по определённым правилам, которые диктуются выбранным workflow. Чаще всего, нам необходимо создавать изолированное пространство, так называемые ветки, в рамках которых мы делаем изменения. Нужно это так же и для того, чтобы не получать постоянно конфликты с изменениями от других разработчиков. В случае готовности, мы можем сливать состояние своей ветки с состояниями других веток, таким образом мы добавляем свои изменения в основную кодовую базу продукта, который делает наша команда. В таком случае нередко нам приходится таки решать конфликты слияния, в рамках этого решения мы вольны сами решать какие именно изменения нужно сохранить: свои, чужие или оба. Мы так же можем получать состояние удалённого репозитория или даже полное содержимое этих изменений, в случае, если мы хотим с этими изменениями поработать. Надеюсь, теперь ты чуточку лучше знаешь этот инструмент. Увидимся уже в следующем уроке на этой же площадке через три две одну.
devops
notcourse
git