Skip to content

Latest commit

 

History

History
705 lines (476 loc) · 45.6 KB

lesson9.md

File metadata and controls

705 lines (476 loc) · 45.6 KB

Лекция 9. Git. История системы контроля версий. Локальный репозиторий. Базовые команды управления репозиторием.

Сегодня мы поговорим о системе контроля версий Git, одной из самых популярных и широко используемых систем для управления исходным кодом. В ходе лекции мы рассмотрим исторический контекст, который привел к созданию Git, основные этапы его развития, а также причины появления необходимости в системах контроля версий.

Система контроля версий, что это и зачем? Была ли у вас ситуация когда вы работаете над дипломом в университете или над каким то файлом для своего проекта и в какой-то момент у вас на компьютере уже несколько файлов с названиями вроде: финал.docx, финал_01.docx, финал_01_точно_финал.docx, финал_последний.docx, финал_последний_c_избражениями.docx. Так вот когда вы работаете с кодом файлов у вас может быть очень много и людей, которые вносят новые правки тоже может быть очень много. Для того что бы все это контролировать и нужна система контроля версий.

Необходимость в системах контроля версий

Прежде чем перейти к истории создания Git, важно понять, почему вообще возникла необходимость в системах контроля версий. С развитием программного обеспечения и увеличением числа разработчиков, работающих над одним проектом, стали очевидны следующие проблемы:

  1. Отслеживание изменений: Когда несколько разработчиков работают над одним и тем же файлом, необходимо отслеживать, кто и какие изменения внес. Без этого легко запутаться в версиях и потерять важные правки.
  2. Совместная работа: В больших проектах требуется синхронизация работы множества разработчиков, распределение задач и объединение результатов их работы.
  3. История изменений: Важно иметь возможность вернуться к предыдущим версиям кода, чтобы понять, что было изменено и когда, а также для восстановления прежней рабочей версии в случае возникновения ошибок.
  4. Резервное копирование: Хранение различных версий кода помогает защититься от потери данных и обеспечить возможность восстановления после сбоев.
  5. Разработка новых функций: Возможность создания изолированных веток для разработки новых функций или исправления ошибок позволяет работать над новыми задачами, не нарушая основной код.

Начало истории

История системы Git начинается в начале 2000-х годов. До появления Git существовали различные системы контроля версий, такие как RCS, CVS и SVN. Эти системы помогали разработчикам отслеживать изменения в коде, работать совместно и управлять различными версиями проектов. Однако каждая из них имела свои недостатки и ограничения. Мы не будем в них углубляться, скорее всего, в современном мире, вы никогда c ними и не пересечетесь

Создание проекта Linux

Важной вехой в истории Git стало создание проекта Linux. Линус Торвальдс, создатель ядра Linux, изначально использовал для управления версиями исходного кода систему BitKeeper. BitKeeper была коммерческой системой контроля версий, предоставлявшей бесплатные лицензии для открытых проектов, таких как Linux.

Однако в 2005 году произошел конфликт между сообществом разработчиков Linux и компанией, владеющей BitKeeper. Компания прекратила предоставление бесплатных лицензий, что создало необходимость в поиске новой системы контроля версий. Линус Торвальдс, осознав важность независимости от коммерческих решений, решил создать собственную систему контроля версий, которая бы соответствовала требованиям разработки ядра Linux.

Основные требования к новой системе

Перед началом разработки Линус Торвальдс выделил несколько ключевых требований к новой системе контроля версий:

  1. Скорость: Система должна быть быстрой и эффективной при работе с большими объемами данных.
  2. Распределенность: Возможность работы без центрального сервера, что позволяет каждому разработчику иметь свою копию репозитория.
  3. Простота: Простота в использовании и настройке.
  4. Защита данных: Надежное хранение и контроль версий, предотвращение потери данных.

Разработка Git

Проект разработки новой системы контроля версий, названный Git, был начат в апреле 2005 года. Линус Торвальдс в течение нескольких недель создал первоначальную версию Git, которая удовлетворяла всем вышеупомянутым требованиям. Впоследствии к разработке присоединились другие участники сообщества Linux, что позволило значительно улучшить и расширить функциональность системы.

Основные характеристики Git

Git обладает несколькими ключевыми особенностями, которые отличают его от других систем контроля версий:

  1. Система хранения данных: Git использует структуру данных, называемую Directed Acyclic Graph (DAG), для хранения коммитов и веток. Это позволяет эффективно отслеживать изменения и поддерживать целостность данных.
  2. Распределенность: Каждый разработчик имеет полную копию репозитория, что делает систему более устойчивой к сбоям и позволяет работать в автономном режиме.
  3. Работа с ветками: Git предоставляет мощные инструменты для создания и слияния веток, что упрощает работу над новыми функциями и исправлениями.
  4. Скорость: Высокая производительность при выполнении операций, таких как клонирование, коммит и слияние изменений.

Распространение и популяризация

После создания Git быстро завоевал популярность в сообществе разработчиков благодаря своим преимуществам. Многие крупные проекты, включая ядро Linux, начали использовать Git в качестве основной системы контроля версий. В 2008 году был запущен сервис GitHub, предоставляющий платформу для хостинга Git-репозиториев и совместной работы над проектами. Это значительно способствовало распространению Git среди разработчиков по всему миру.

Современное состояние Git

Сегодня Git является де-факто стандартом для управления исходным кодом в индустрии разработки программного обеспечения. Он используется миллионами разработчиков и компаниями по всему миру для управления проектами различного масштаба и сложности. Git продолжает активно развиваться и совершенствоваться, благодаря усилиям сообщества и корпоративных спонсоров.

К практическому применению!

Установка Git

Прежде чем начать работу с Git, его необходимо установить. Вы можете скачать Git с официального сайта. Установка на различных операционных системах может отличаться, поэтому следуйте инструкциям для вашей ОС.

Что такое репозиторий?

Репозиторий Git — это место, где хранятся все файлы и история их изменений для проекта. Репозиторий может быть локальным (на вашем компьютере) или удалённым (на сервере или в облачном хранилище). Вся структура изменений и версий проекта хранится в скрытой папке .git.

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

Инициализация репозитория

Первым шагом при работе с Git является инициализация нового репозитория. Это можно сделать в любой папке с помощью команды:

git init

Эта команда создаст скрытую папку .git, где будут храниться все данные репозитория.

Команды git будут доступны только после установки git на ваш компьютер.

При первом запуске очень вероятно, что система не запустится с первого раза, а сначала попросит предоставить ваше имя/имейл и возможно какие-либо другие данные, следуйте инструкции из консоли и после этого все запуститься

Типы состояний файлов в Git

Это очень важная картинка с которой нам нужно детально познакомиться.

С точки зрения локального репозитория файлы в нем могут находиться в 4 состояниях:

  1. untracked (не отслеживаемые) - Состояние файлов, в котором изменения в файлах не отслеживается гитом, а значит он не может сказать были ли в этом файле изменения или нет.
  2. unmodified (не измененные) - Состояние файлов, когда файл отслеживается, но в него не были внесены никакие изменения.
  3. modified (измененные) - Состояние файлов, когда они отслеживаются, и гит видит что файлы были изменены по сравнению с последней версией.
  4. staged (подготовленные) - Состояние файлов, когда они отслеживаются, они изменены, и они готовы к тому что бы зафиксировать последние изменения в файле как новая, последняя версия

Основные наши действия с репозиторием локально - это изменение статусов файлов. По этому их очень важно понять.

Создали мы пустой репозиторий и что с этим делать?

Создавать или модифицировать файлы! Все файлы в вашем репозитории уже будут находиться в одном из состояний описанных выше

Просмотр состояния репозитория

Для проверки состояния репозитория и отслеживания изменений используйте команду:

git status

Эта команда покажет, какие файлы были изменены, подготовлены или еще не отслеживаются.

По сути эта команда показывает все файлы в репозитории, которые находятся в любом отличном от unmodified состоянии.

Что делать при создании нового файла?

На самом деле когда вы создаете новый файл, он создается в состоянии untracked и пока вы явно не скажете гиту отслеживать этот файл, гит будет упорно его игнорировать.

Для добавления файла в систему контроля версий, используется команда

git add filename.txt

где filename.txt - это название файла.

Эта же команда очень часто используется для добавления к отслеживанию сразу всего что вообще найдется в этой папке, для такого случая можно использовать символ . и тогда гит добавит сразу все файлы которые найдет

git add .

Обратите внимание, если файл бы в состоянии untracked и мы применили к нему git add, то этот файл сразу перейдет в состояние staged.

Если файл находится в состоянии unmodified то, для того что-бы он перешел в состояние modified достаточно просто внести в него абсолютно любые изменения.

Что бы файл из состояния modified перешел в состояние staged. К модифицированным файлам необходимо применить всю туже команду.

git add filename
git add .

Для одного файла, или сразу для всех в папке соответственно.

Зачем были нужны все эти манипуляции или git commit

Для того что бы зафиксировать новые изменения и после иметь возможность вернуться к какой-либо версии кода, используется команда

git commit -m "commit_message"

Гит коммит, это команда, которая все файлы из состояния staged переводит в состояние unmodified

При этом полностью сохраняя всю историю изменений под уникальным номером, и с возможностью возвращаться к этой версии если нам будет необходимо

Команда commit требует указать какой-либо текст с описанием, что именно это за изменения. Их можно указать после флага -m ну либо гит попросит указать этот текст интерактивно.

Первый совершенный в репозитории коммит называется инициализационным, и на его основе выполняются различные действия, так рекомендую сразу аккуратно к нему относиться и не вносить мусор уже в первый коммит.

А что после коммита?

Все повторяется, изменяем существующие файлы, или добавляем новые, через команду git add переводим файлы в состояние staged, и при помощи команды git commit фиксировать изменения.

История изменений

Чтобы увидеть историю коммитов, используйте команду:

git log

Эта команда покажет список всех коммитов с комментариями, датами и авторами изменений, и их уникальными номерами.

Система ветвления

Когда мы делаем новый коммит, гит сохраняет историю изменений и кроме этого он запоминает какой коммит был предыдущим перед новым (Помните, у них у всех есть номера).

Этим свойством можно пользоваться, раз каждый коммит помнит кто был его родитель, значит мы всегда пройдя вверх по родителям, можем выйти на самый первый коммит. А это значит, что мы можем создавать разветвления и различные версии в нашем коде.

Зная это мы можем после одного коммита сделать несколько разных, и у всех из них будет один и тот же родитель. Таким образом мы получим несколько различных версий кода, который имеет только общего предка. Такой "набор" коммитов от изначального до какой-либо версии называется словом ветка и мы можем их контролировать. На самом деле ветка не содержит в себе "набор" ветка это всего лишь ссылка на конкретный коммит. А уже сам коммит хранит в себе информацию о его родителях, за счет чего и появляется возможность вычислить любого предка для самого первого initial commit-a

Создание веток

Зачем нам вообще нужны ветки? Ветки позволяют проводить работу изолировано от всего остального. Например, мы разрабатываем какую-то новую функциональность.

Самый правильный подход при выполнении любой разработки, создавать новую ветку под новую функциональность и выполнять коммит в любом месте, где изменения в коде уже работают и имеют хоть какой-то законченный вид. В реальности чаще всего любое новшество создается в новой ветке, и дальше все зависит от размера этого новшества, но обычно такие ветки содержат от 1 до 20 коммитов.

А к какой ветке относится initial commit и все остальные которые мы уже делали?

Отличный вопрос :)

На самом деле когда мы инициализировали гит, то он за нас автоматически создал для нас ветку. У такой ветки обычно может быть одно из двух названий или master или main.

На заре git все базовые ветки всегда назывались master, но так как в 10-х годах был скандал связанный с толерантностью, во многих местах пришлось переименовать все, где использовались слова master и slave, ведь они переводятся как господин и раб соответственно. Хотя все еще в огромном кол-ве мест вы можете увидеть именно эти слова

Создание новой ветки

Для создания новой ветки, используется команда git branch branch_name, где branch_name это название новой ветки

git branch new-feature

Как только вы это сделали, у вас ничего не поменялось, кроме того, что на текущий коммит была сделана еще одна ссылка. Но если вы сделаете еще один коммит, он все еще будет связан с веткой мастера, потому что для того что бы выполнять изменения в новой ветке, нужно не только ее создать, но и переключиться на новую ветку.

Чтобы переключиться на новую ветку, выполните:

git checkout new-feature

Так же существует сокращенная запись когда мы хотим создать и переключиться на новую ветку одновременно:

git chechout -b newone

где newone - это название новой ветки которую мы хотим создать и сразу в нее переключится

Слияние веток (merge)

После завершения работы над новой функцией или исправлением, необходимо слить ветку с основной, мы ради этого это все и затевали.

Переключитесь на основную ветку и выполните команду слияния:

git checkout main
git merge new-feature

Эта команда выполнит слияние указанной ветки с той веткой в которой вы в этот момент находитесь.

Что значит слияние, это значит что git найдет первый коммит который для двух веток является общим. После чего попытается "наложить" коммиты из вашей ветки, поверх основной и создать еще один коммит, под названием " merge-commit". Он создается при слиянии.

Перебазирование веток (rebase)

Очень полезная команда. Выполняет подстановку коммитов из другой ветки в текущую начиная с места разветвления.

Посмотрите на рисунок. Если в ваша текущая ветка отстает от другой ветки, вы всегда можете "подровнять" ветки путем вызова команды git rebase

git rebase master

Обратите внимание, в отличие от merge, действие выполняется в обратном порядке. Хотя технически всегда действие выполняется от указанной ветки к текущей.

Интерактивная игра

У гита существует еще огромное количество команд, мы не будем изучать их все. Но в качестве домашнего задания к этому занятию, я хочу что бы вы прошли вот ЭТУ игру.

Она знакомит нас с основными командами и понятиями гита.

В дальнейшем я предполагаю, что этот материал пройден, так что как минимум ознакомиться крайне рекомендую

Конфликты

Самая не приятная вещь при работе с гитом это конфликты. Предположим, что в одной ветке мы изменили какую-то функцию, а потом в другой ветке мы изменили ее же. И пытаемся слить обе ветки в третью. В таком случае у нас обязательно возникнет конфликт. Потому что гит не может понять какой именно вариант кода мы считаем правильным.

Git уведомит вас о конфликтных файлах, и вам нужно будет вручную их разрешить. После разрешения конфликтов, добавьте исправленные файлы и создайте коммит:

git add conflict-file.txt
git commit -m "Resolved merge conflict"

Просмотр различий

Чтобы увидеть различия между текущими изменениями и последним коммитом, используйте команду:

git diff

Эта команда покажет, какие строки были добавлены или удалены.

Удаление файлов

Чтобы удалить файл из репозитория и системы, используйте команду:

git rm example.txt

Для удаления файла только из индекса, оставив его в файловой системе, выполните:

git rm --cached example.txt

Игнорирование файлов (.gitignore)

Иногда необходимо игнорировать определенные файлы или директории (почти всегда). Для этого создайте файл .gitignore в репозитории и добавьте в него шаблоны для игнорируемых файлов. Например:

*.log
node_modules/
.DS_Store

Что такое HEAD?

HEAD – это указатель на текущую ветку и последний коммит в этой ветке. Проще говоря, HEAD показывает, где вы находитесь в дереве изменений вашего репозитория в данный момент.

Представьте HEAD как закладку в книге. Когда вы переключаетесь между ветками или коммитами, HEAD меняет своё положение, указывая на соответствующий коммит.

Как работает HEAD?

В Git HEAD обычно указывает на ветку, а ветка, в свою очередь, указывает на коммит. В файле .git/HEAD содержится ссылка на файл, представляющий текущую ветку. Если вы откроете этот файл, то увидите что-то вроде:

ref: refs/heads/main

Это означает, что HEAD указывает на ветку main. Когда вы делаете новый коммит, указатель HEAD автоматически перемещается на этот новый коммит.

Типы HEAD

В Git существует два состояния HEAD:

  • Указывает на ветку (обычное состояние):

В этом случае HEAD указывает на ветку, и любое действие, которое вы совершаете, будет относиться к этой ветке. Например, при коммите HEAD и указатель ветки будут двигаться вперёд.

  • Отсутствие привязки к ветке (detached HEAD):

Это состояние, когда HEAD указывает непосредственно на коммит, а не на ветку. Обычно это происходит, когда вы переключаетесь на конкретный коммит с помощью команды git checkout . В таком состоянии любые изменения и коммиты не будут привязаны к какой-либо ветке. Основные команды работы с HEAD Проверка текущего состояния HEAD:

git log --oneline --decorate

Эта команда покажет список коммитов и укажет, на каком из них находится HEAD.

Переключение между ветками:

git checkout <branch-name>

Эта команда переместит HEAD на указанную ветку.

Переключение на конкретный коммит (detached HEAD):

git checkout <commit-hash>

Это переместит HEAD на указанный коммит без привязки к ветке.

Создание новой ветки и переключение на неё:

git checkout -b <new-branch-name>

Эта команда создаст новую ветку и переместит HEAD на неё.

git reset

Что такое git reset?

git reset – это мощная команда в Git, которая позволяет перемещать указатель текущей ветки и опционально изменять состояние индекса (staging area) и рабочего каталога. Основная цель этой команды – отменить изменения или переместить HEAD на другой коммит.

Синтаксис команды git reset

git reset [<mode>] [<commit>]

Где <mode> – это один из трёх режимов работы команды, а <commit> – это ссылка на коммит, к которому вы хотите переместить HEAD.

Режимы работы git reset

  1. --soft:

    • Перемещает HEAD к указанному коммиту.
    • Индекс и рабочий каталог остаются неизменными.
    • Используется для отмены последних коммитов, сохраняя изменения для повторного коммита.
    git reset --soft <commit>
  2. --mixed (по умолчанию):

    • Перемещает HEAD к указанному коммиту.
    • Индекс сбрасывается до состояния указанного коммита.
    • Рабочий каталог остаётся неизменным.
    • Используется для отмены коммитов и удаления изменений из индекса, оставляя их в рабочем каталоге.
    git reset --mixed <commit>
  3. --hard:

    • Перемещает HEAD к указанному коммиту.
    • Индекс и рабочий каталог сбрасываются до состояния указанного коммита.
    • Используется для полной отмены коммитов и всех изменений в рабочем каталоге и индексе.
    git reset --hard <commit>

Примеры использования git reset

  1. Отмена последнего коммита, сохраняя изменения для повторного коммита:

    git reset --soft HEAD~1
    # HEAD перемещается на один коммит назад, изменения сохраняются в индексе
  2. Отмена последнего коммита и удаления изменений из индекса:

    git reset --mixed HEAD~1
    # HEAD перемещается на один коммит назад, изменения остаются в рабочем каталоге
  3. Полная отмена последнего коммита и всех изменений:

    git reset --hard HEAD~1
    # HEAD перемещается на один коммит назад, все изменения отменяются
  4. Перемещение HEAD на конкретный коммит:

    git reset --hard <commit-hash>
    # HEAD перемещается на указанный коммит, состояние репозитория возвращается к этому коммиту
  5. Отмена нескольких последних коммитов:

    git reset --hard HEAD~3
    # HEAD перемещается на три коммита назад, все изменения отменяются

Важные замечания при использовании git reset

  • Режим --hard: Будьте особенно осторожны при использовании этого режима, так как он удаляет все несохранённые изменения в рабочем каталоге и индексе, и их нельзя будет восстановить.
  • Резервное копирование: Перед выполнением git reset --hard рекомендуется создать резервную копию текущего состояния репозитория или создать новую ветку для сохранения изменений.

Альтернативы git reset

В некоторых случаях другие команды могут быть более подходящими для вашей задачи:

  • git revert: Используйте для отмены конкретных коммитов, создавая новые коммиты с противоположными изменениями. Это сохраняет историю изменений.

    git revert <commit>
  • git checkout: Используйте для переключения веток или возврата к определённому коммиту в состоянии detached HEAD.

    git checkout <commit>
  • git restore: Используйте для восстановления файлов из коммита или индекса без изменения состояния ветки или истории.

    git restore --source=<commit> --staged --worktree <file>

Команда git reset – это мощный инструмент для управления историей коммитов и состоянием репозитория в Git. Понимание различных режимов работы этой команды и их правильное использование поможет вам эффективно управлять изменениями и сохранять чистую историю вашего проекта. Всегда помните о последствиях использования git reset и выбирайте наиболее подходящий инструмент для вашей задачи.

Chery-pick

Что такое git cherry-pick?

git cherry-pick – это команда Git, которая позволяет перенести изменения из одного или нескольких коммитов в текущую ветку. Эта команда создаёт новые коммиты в текущей ветке с теми же изменениями, что и в выбранных коммитах, сохраняя их идентичность.

Синтаксис команды git cherry-pick

git cherry-pick [options] <commit-hash>...

Где <commit-hash> – это идентификаторы коммитов, которые вы хотите перенести.

Основные опции git cherry-pick

  • -e или --edit: Открыть редактор для изменения сообщения коммита перед созданием нового коммита.
  • -n или --no-commit: Применить изменения, но не делать новый коммит автоматически.
  • -x: Добавить строку в сообщение коммита, указывающую на оригинальный коммит.
  • --continue: Продолжить выполнение cherry-pick после разрешения конфликтов.
  • --abort: Прервать операцию cherry-pick и вернуть ветку в исходное состояние до начала операции.
  • --skip: Пропустить коммит, вызвавший конфликт, и продолжить выполнение cherry-pick.

Примеры использования git cherry-pick

  1. Применение одного коммита в текущую ветку:

    git cherry-pick abc123
    # Применить изменения из коммита abc123 в текущую ветку
  2. Применение нескольких коммитов в текущую ветку:

    git cherry-pick abc123 def456 ghi789
    # Применить изменения из коммитов abc123, def456 и ghi789 в текущую ветку
  3. Применение диапазона коммитов:

    git cherry-pick abc123..def456
    # Применить изменения из всех коммитов в диапазоне от abc123 до def456 (исключая abc123)
  4. Применение коммита с редактированием сообщения:

    git cherry-pick -e abc123
    # Применить изменения из коммита abc123 и открыть редактор для изменения сообщения коммита
  5. Применение коммита без автоматического создания нового коммита:

    git cherry-pick -n abc123
    # Применить изменения из коммита abc123, но не делать новый коммит автоматически
  6. Применение коммита с добавлением ссылки на оригинальный коммит:

    git cherry-pick -x abc123
    # Применить изменения из коммита abc123 и добавить строку в сообщение коммита с ссылкой на оригинальный коммит

Разрешение конфликтов при git cherry-pick

Иногда при выполнении команды git cherry-pick могут возникать конфликты. В таких случаях Git остановит выполнение и предоставит возможность вручную разрешить конфликты.

  1. Разрешение конфликтов:

    • Откройте файлы с конфликтами и внесите необходимые изменения.
    • Добавьте исправленные файлы в индекс с помощью команды git add.
  2. Продолжение выполнения cherry-pick:

    git cherry-pick --continue
    # Продолжить выполнение cherry-pick после разрешения конфликтов
  3. Прерывание выполнения cherry-pick:

    git cherry-pick --abort
    # Прервать операцию cherry-pick и вернуть ветку в исходное состояние

Примеры ситуаций для использования git cherry-pick

  1. Перенос фикса ошибок в другие ветки:

    • Вы обнаружили ошибку в основной ветке и исправили её, создав коммит. Теперь вы хотите перенести это исправление в релизную ветку.
  2. Выборочное применение изменений:

    • Вы работаете над несколькими задачами в одной ветке, но хотите перенести только некоторые из них в другую ветку.
  3. Слияние отдельных изменений:

    • Вы хотите объединить только определённые изменения из одной ветки в другую, без выполнения полного слияния веток.

Команда git cherry-pick – это мощный инструмент для выборочного применения изменений из одного или нескольких коммитов в текущую ветку. Понимание работы этой команды и её правильное использование помогут вам эффективно управлять изменениями в вашем проекте и поддерживать чистую историю коммитов.

Домашка:

Все еще пройдите вот это