Рассмотрите простой пример рабочего процесса, который может быть полезен в вашем проекте.
Предположим, вы работаете над проектом и уже имеете несколько коммитов.
Вы решаете, что теперь вы будете заниматься задачей №53 из вашей системы проектирования. Вы создаете новую ветку issue-53 и Visual Studio Code сразу переключает вас на нее.
Вы работаете над новой функциональностью и фиксируете изменения. Это приводит к тому, что ветка issue-53 движется вперед, так как вы переключились на нее ранее (HEAD указывает на нее).
Тут вы получаете сообщение об обнаружении критической ошибки, которую нужно немедленно устранить.
Благодаря Git вам не придется пытаться реализовать исправление вместе с изменениями, которые вы сделали в ходе разработки issue-53. Вам даже не придется прилагать усилий, чтобы откатить все эти изменения для начала работы над исправлением. Все, что вам нужно, это переключиться на ветку main.
Имейте в виду, что если рабочий каталог или индекс содержат незафиксированные изменения, конфликтующие с веткой, на которую вы хотите переключиться, то Git не позволит переключить ветки. Лучше всего переключаться из чистого рабочего состояния проекта: все измененные файлы добавить в индекс и сделать коммит. Есть способы обойти это (припрятать изменения (stash) или добавить их в последний коммит (amend))
Теперь предположим, что вы зафиксировали все свои изменения и можете переключиться на ветку main. История вашего репозитория будет выглядеть следующим образом.
С этого момента ваш рабочий каталог имеет точно такой же вид, какой был перед началом работы над задачей №53. Теперь вы можете сосредоточиться на работе над исправлением.
Важно запомнить: когда вы переключаете ветки, Git возвращает состояние рабочего каталога к тому виду, какой он имел в момент последней фиксации изменений в эту ветку. Он добавляет, удаляет и изменяет файлы автоматически, чтобы состояние рабочего каталога соответствовало тому, когда были зафиксированы последние изменения.
Теперь вы можете перейти к написанию исправления. Создайте новую ветку bug-135 и исправьте в ней критическую ошибку.
Вы можете прогнать тесты, чтобы убедиться, что ваше исправление делает именно то, что нужно. И если это так, выполнить слияние с основной веткой для включения в продукт.
Чтобы ветку bug-135 влить в основную ветку main:
В результате история коммитов будет выглядеть у вас следующим образом.
Операция, которую сейчас выполнил Git, называется «перемотка вперед» (Fast-forward). Из-за того, что коммит, на который указывала ветка, которую вы влили, был прямым потомком того коммита, на котором вы находились, Git просто переместил указатель ветки вперед.
Другими словами, если в коммит вливается тот коммит, до которого можно добраться, двигаясь по истории прямо, Git упрощает слияние, просто перенося указатель метки вперед (так как нет разветвления в работе). Это называется перемотка вперед (fast-forward).
Теперь ваши изменения находятся в снимке коммита, на который указывает ветка main, и исправления конфигурации можно внедрять.
После внедрения вашего критического исправления вы готовы вернуться к работе над тем, что были вынуждены отложить. Но сначала нужно удалить ветку bug-135, потому что она больше не нужна, ведь ветка main указывает на то же самое место.
После этого ваша история будет выглядеть следующим образом:
Теперь вы можете переключить ветку, вернуться к работе над своей задачей № 53 и продолжить работу над ней, сделав еще один коммит.
Обратите внимание на то, что все изменения из ветки bug-135 не включены в вашу ветку issue-53. Если их нужно включить, вы можете влить ветку main в вашу ветку issue-53. Либо вы можете отложить слияние этих изменений до завершения работы, а затем переключиться на ветку main и влить ветку issue-53 в main.
Предположим, вы решили, что работа по задаче №53 закончена, и ее можно влить в ветку main. Для этого, как вы делали это с веткой bug-135 ранее, нужно переключиться на ветку, в которую вы хотите включить изменения (main), и выполнить команду в дополнительном меню репозитория. ( )
Результат этой операции будет отличаться от результата слияния ветки bug-135. Рассмотрите ситуацию подробнее.
В данном случае процесс разработки ответвился в более ранней точке. Так как коммит, на котором вы находитесь, не является прямым потомком ветки, с которой вы выполняете слияние, Git придется немного потрудиться.
В этом случае Git выполняет простое трехстороннее слияние двух снимков сливаемых веток и общего для двух веток родительского снимка.
Вместо того чтобы просто передвинуть указатель ветки вперед, Git создает новый снимок-результат трехстороннего слияния, а затем автоматически делает коммит. Этот особый коммит называют коммитом слияния (merge commit), так как у него более одного предка.
На схеме это будет выглядеть следующим образом.
Стоит отметить, что Git сам определяет наилучшего общего предка, подходящего как база для слияния. Это отличает его от более старых инструментов, таких как CVS или Subversion (до версии 1.5), где разработчикам, выполнявшим слияние, приходилось самим находить лучшую базу. Это безумно упрощает слияние в Git по сравнению с указанными системами.
Теперь, когда работа влита, ветка issue-53 больше не нужна. Вы можете закрыть задачу №53 в системе проектирования и удалить ветку.
Иногда процесс слияния не проходит гладко. Если вы изменили одну и ту же часть одного и того же файла по-разному в двух объединяемых ветках, Git не сможет их чисто объединить. Если ваше исправление ошибки №53 потребовало изменить, например, ту же часть файла, (тот же реквизит и т.д.) что и bug-135, Visual Studio Code прекратит процесс слияния и сообщит вам о конфликте.
Во-первых, в разделе Система управления версиями (Source Control) она покажет файлы, в которых обнаружен конфликт. Они будут отмечены значком ! Конфликт: оба изменили (Conflict: Both Modifyed)
Во-вторых, в правом нижнем углу вы увидите сообщение.
Visual Studio Code будет ждать, пока вы разрешите все конфликты.
Чтобы разрешить конфликт, можно нажать Открыть журнал GIT в сообщении, и тогда вы увидите сам конфликтный файл в том виде, в котором он присутствует в рабочей области.
Здесь видно, что в обеих ветках была изменена одна и та же строка. Изменения, содержащиеся в текущей ветке main, выделены так:
<<<<<<< HEAD (текущее изменение)
...
=======
Изменения, содержащиеся во вливаемой ветке issue-53, выделены так:
=======
...
>>>>>>> issue-53 (входящее изменение)
Ваша задача заключается в том, чтобы оставить в файле один из этих вариантов. Вы можете сделать это вручную, удалив ненужные строки, или автоматически, нажав на один из предлагаемых вариантов.
Другой способ разрешения конфликтов заключается в том, чтобы использовать редактор слияния. Он удобен тогда, когда в файле содержится большое количество конфликтующих фрагментов и анализировать все это в «простом» виде неудобно.
Чтобы открыть файл в редакторе слияния, можно нажать кнопку Разрешить в редакторе слияния, которая появляется в правом нижнем углу окна редактора файла.
В редакторе слияния файл представлен в трех окнах. В одном окне находится входящий вариант файла, в другом — текущий. В нижнем окне показывается результат слияния, который получится, если выполнить слияние в текущих условиях.
Если этот результат вас не устраивает, вы можете разрешить каждый конфликт в отдельности (принять, например, входящие изменения) или принять все входящие изменения сразу, если знаете, что в ветке issue-53 содержится именно тот вариант файла, который вам нужен.
После того, как все конфликты будут разрешены, Visual Studio Code добавит все файлы в индекс, создаст стандартное сообщение коммита слияния и будет ждать ваших действий.
Вы можете дополнить сообщение коммита слияния подробностями того, как были разрешены конфликты, если считаете, что это поможет другим в будущем разобраться в данном слиянии, если это не очевидно. После этого нажмите Фиксация (Commit).
По материалам книги Pro Git (авторы Scott Chacon и Ben Straub, издательство Apress). Книга распространяется по лицензии Creative Commons Attribution Non Commercial Share Alike 3.0 license.