Добавили изменения для ветки reset еще одна правка ## Про Git Существует несколько систем контроля версий: Git, Subversion, Team Foundation Server, Mercurial. Сегодня познакомимся и погорим о Git — [самой популярной](https://survey.stackoverflow.co/2022/#version-control-version-control-system) системой, ей пользуются более 90% разработчиков. Git появился 7 апреля 2005 года и был создан для управления разработкой ядра Linux. Кстати, создал его тот самый [Линусом Торвальдсом](https://ru.wikipedia.org/wiki/%D0%A2%D0%BE%D1%80%D0%B2%D0%B0%D0%BB%D1%8C%D0%B4%D1%81,_%D0%9B%D0%B8%D0%BD%D1%83%D1%81), а сегодня его развитием и поддержкой занимается [Джунио Хамано](https://ru.wikipedia.org/wiki/%D0%A5%D0%B0%D0%BC%D0%B0%D0%BD%D0%BE,_%D0%94%D0%B6%D1%83%D0%BD%D0%B8%D0%BE). Git — это распределённая система управления версиями. Что такое распределенная система: есть один сервер, через который разработчики обмениваются кодом. Разработчик копирует (клолнирует) проект к себе на локальную машину, делает изменения и сохраняет их на удаленный сервер. При необходимости, другие разработчики могут скопировать эти изменения к себе. Почти все разработка ведется локально, ведь история и копия проекта хранится локально и чаще всего не нужна никакая дополнительная информация с других клиентов. Вы можете работать с репозиторием и при отсутствии интернета (например, в самолете), а когда он появится, просто загрузить изменения в удаленный репозиторий (тот что на выделенном сервере). Если у разработчика сломается компьютер, то проект не потеряется - он сохранен на выделенный сервер. Такой выделенный сервер, можно [поднять и настроить самому](https://about.gitlab.com/), а можно использовать существующие сервисы. **GitHub** - крупнейший веб-сервис, который позволяет заниматься совместной разработкой с использованием Git и сохранять изменения на своих серверах (на самом деле, [функциональность](https://github.com/about) GitHub намного больше, но сейчас нас интересует только совместная разработка). Еще есть [Gitlab](https://about.gitlab.com/), [Bitbucket](https://bitbucket.org/product/ru/guides/basics/bitbucket-interface) и другие, но мы будем использовать GitHub, как самый популярный в настоящее время. ## Предварительная настройка Для начала немного подготовительной настройки. Для начала ааарегистрируйтесь на GitHub](https://github.com/join?source=header-home) при регистрации задайте логин, почту и придумайте пароль. После “Создать аккаунт” не забудьте проверить почту и подтвердить ее (опрос от Github после подтверждения почты можно пропустить). если все ок, экран GitHub будет выглядеть вот так  В GitHub есть разграничение прав на репозитории. Можно задавать различные политики для репозитория: сделать публичным и [приватны](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/managing-repository-settings/setting-repository-visibility)м, ограничить права кругу пользователей или кому то одному, например, разрешить просматривать репозиторий, но не изменять в нем данные. Для того, что бы сервис определил кто вы и имеете ли право работать с тем или иным репозиторием нужно представиться - пройти процесс [аутентификации](https://ru.wikipedia.org/wiki/Аутентификация). Для безопасной работы GitHub поддерживает два сетевых протокола [HTTPS](https://ru.wikipedia.org/wiki/HTTPS) и [SSH](https://docs.github.com/en/authentication/connecting-to-github-with-ssh) и вся работа с сервисом происходит через один из них. Работать с GitHub будем через терминал по SSH. Для этого мы один раз сгенирируем специальный ключи, добавим один из них в наш аккаунт на GitHub. Можно работать и через HTTPS, но нужно будет каждый раз вводить пароль и специальный [token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token). Пара слов про SSH и как он работает. SSH - это сетевой протокол для зашифрованного соединения между клиентом и сервером → данные по такому соединения можно передавать безопасно. При установлении соединения используется пара ключей: открытый (публичный, *public*) и закрытый (приватный, *private).* Пользователь создает пару ключей при помощи специальной команды и сохраняет закрытый ключ у себя, а открытый “кладет” на сервер (в нашем случае на GitHub). А работает это все благодаря [ассиметричному шифрованию.](https://ru.wikipedia.org/wiki/Криптосистема_с_открытым_ключом) Алгоритм работает так: отправитель (GitHub) шифрует сообщение публичным ключом и передает сообщение клиенту (нам), а мы его расшифровываем при помощи приватного ключа, который предусмотрительно сохранили у себя. То что зашифровано публичным ключом, расшифровать сможет только приватный ключ. Давай-те создадим пару ключей и добавим открытый ключ на GitHub Что-бы создать пару ключей, в терминале нужно ввести команду, задать путь где сохранить ключи и задать пароль к ключу (не обязательно). Будем дальше в статье основываться на том, что путь для ключей дефолтный и пароль на ключи не установлен. Пароль для ключей нужен, как дополнительная мера безопасности, если вдруг ваш приватный ключ попадёт не в те руки. ```python $ ssh-keygen Generating public/private rsa key pair. # путь до ключей, в скобках путь по умолчанию Enter file in which to save the key (/Users/ifireice/.ssh/id_rsa): # пароль для ключей, при задании пароля в консоли не отображается ничего, даже звездочки # если нажать Enter ничего не вводя, пароль будет пустым Enter passphrase (empty for no passphrase): # повторите пароль Enter same passphrase again: # после появится сообщение такого вида Your identification has been saved in /Users/ifireice/.ssh/id_rsa Your public key has been saved in /Users/ifireice/.ssh/id_rsa.pub The key fingerprint is: SHA256:Zu+HkZPC4ZP0veRmVjuKgylVvljHBNO8mHs+ieFFPvs ifireice@ifireice-osx The key's randomart image is: +---[RSA 3072]----+ | o | | o o | | = . | | o + + | | +S* X | | oB.@ X . | | . O.# * . | | . +.*.% o | | . o*.+E. | +----[SHA256]-----+ ``` Вуаля, ключи сгенирированы (в заданной директории появится 2 файла `id_rsa` и `id_rsa.pub`). Теперь надо добавить публичный ключ в аккаунт на GitHub. ```python # выведите содержимое публичного ключа в консоль $ cat ~/.ssh/id_rsa.pub ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDDJfHIi73sKd6cqm3RwKuY1zl46aAaE6X9Gp /6zJiY3BiJj95oJjPdpfpPhVFWLIbmT8zFAtOLbX9N4C3b0enHUzgMacP/Kl4AbrAkhLqaua9iD VNxxiTVxADG1M5525oc/eAvx7y0pXIb9ouWdYJSKa8/TUYFhWlCzV2quY9SA0FaMs7eY41+KWYpG..... tA0oGxv+7WmXQmQzleLIRG13KQ+VAbL2vabdPcRoGuZavh0smOr/GtVSnLdspZ5RgONMSPWlF2I1YHMR Q7CIKPs= ifireice@ifireice-osx $ ``` Скопируйте ключ от символов `ssh-rsa` и до конца файла и вставьте его в ваш аккаунт на GitHub. Идем в иконка пользователя (1) → Settings (2)  → SSH and GPG keys (3) → New SSH key (4)  → в **Title** дайте имя ключу, что бы понимать откуда он (мб в будущем, у вас будет несколько ключей) (5) → в **Key** вставляем скопированный из консоли ключ (6) → жмяк кнопку Add SSH key (7)  После этого в ваших SSH ключах появится новый ключ и с компьютера где лежит приватный ключ сможете работать с GitHub  Ну что, с настройкой GitHub пока закончили, осталось установить `git` на компьютер. Сделать это можно по [официальной](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) инструкции (выберете пункт для вашей ОС). ====== ## Терминология Немного терминологии, прежде чем начнем создадим первый PR. **Репозиторий** (repository)- директория проекта, который отслеживается Git. В директории хранится проект, история изменений и мета информация проекта (в скрытой директории `.git`) **Индекс** - такая хранилка, в которой содержатся имена файлов и изменения в них, которые должны быть в следующем коммите. По факту индекс просто файл. В индекс файлы сами не попадают, их нужно явно добавлять при помощи `git add` **Коммит** (commit) - это фиксация изменений в истории проекта (изменения, которые внесены в индекс). Коммит хранит измененные файлы, имя автора коммита и время, в которое был сделан коммит + каждый коммит имеет уникальный идентификатор, который позволяет в любое время к нему откатиться. **Ветка** (branch) - последовательность коммитов. По сути это ссылка на последний коммит в этой ветке. Ветки не зависят друг от друга, можно вносить изменения в одну ветки и они не повлияют на другую ветку (если вы явно этого не попросите). Изначально одну ветка - **main**, чуть позже увидим. **Пул реквест** - pull request PR (пиар) (он же merge request MR(мр)) - **Форк** (Fork) - ==== ## Начало работы Начнем с простого - создадим свой репозиторий и сделаем наш первый коммит. Открываем repositories (1) и создаем новый (2).  Зададим параметры: - (1) Repository name: имя нашего репозитория - (2) Description: описание репозитория - (3) [Тип репозитория](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/managing-repository-settings/setting-repository-visibility): Public (публичный) или Private (приватный). Сейчас выберем публичный - кто угодно может видеть содержимое репозитория. - (4) Ставим галку создать README файл. В этом файле в формате [MarkDown](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax) описывают проект или различную документацию. Именно содержимое этого файла можно увидеть, когда заходим на главную страницу репозитория. Пример [1](https://github.com/prometheus/prometheus), [2](https://github.com/django/django), [3](https://github.com/ohmyzsh/ohmyzsh). - (5) Если мы знаем на каком языке наш проект, можем добавить шаблон `.gitignore` для этого языка. Сейчас у нас нет какого то языка, мы не будем создавать `.gitignore`. - (6) Выбираем [тип лизенции](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/licensing-a-repository) для нашего кода. В лицензии оговариваются права на проект. Стоит обратить внимание на [BSD 3](https://opensource.org/licenses/BSD-3-Clause) или [MIT](https://opensource.org/licenses/MIT), тк они предоставляют хороший баланс прав и ответственности. - (7) По умолчанию имя основной ветки в GitHub носит имя `main`, но до [недавнего времени](https://www.theserverside.com/feature/Why-GitHub-renamed-its-master-branch-to-main) имя было `master` .  И нажимаем кнопку “Create repository”. Успех, у нас есть первый репозиторий!  ### А что будет, если не добавим README и .gitignore? На самом деле ничего страшного не произойдет, но придется выполнить еще ряд шагов, что бы [проинициализировать](https://git-scm.com/docs/git-init) git-репозиторий, прежде чем начать с ним работать. Не переживайте, Git очень дружелюбный и расскажет как это сделать.  Ну что, мы создали репозиторий на удаленном сервере, самое время “забрать” его к себе на локальную машину и внести какие-то изменения. Что бы “забрать” репозиторий его надо склонировать к себе при помощи команды `git clone` и пути до репозитория. Для начала получим путь до репозитория. Для этого заходим в созданный репозиторий и находим кнопочку “Code” (1) → нажимаем ее → выбираем SSH (2) → и копируем строку (3)  Теперь идем в консоль, переходим в директорию где хотим хранить проекты и выполним (`git@github.com:ifireiceya/MyFirstRepo.git` - путь который мы скопировали ранее) ```python $ git clone git@github.com:ifireiceya/MyFirstRepo.git Cloning into 'MyFirstRepo'... remote: Enumerating objects: 4, done. remote: Counting objects: 100% (4/4), done. remote: Compressing objects: 100% (4/4), done. remote: Total 4 (delta 0), reused 0 (delta 0), pack-reused 0 Receiving objects: 100% (4/4), done. ``` Переходим в новый каталог, в котором теперь лежит копия нашего проекта с GitHub ```python $ cd MyFirstRepo ``` Можем посмотреть, что у нас в этой директории уже есть ```python $ ls -a .git LICENSE README.md ``` Мы видим два знакомых нам файла `LICENSE` и `README.md`, а так же одну скрытую директорию `.git` В `.git` хранится мета информация проекта и вся история для проекта. На каждый проект есть только одна директория .git и лежит она в корне проекта. ```python $ ls .git HEAD # указатель на вашу активную ветку config # персональные настройки для проекта description # описание проекта hooks # pre/post action hooks index # индексный файл logs # история веток проекта (где они располагались) objects # ваши объекты (коммиты, теги и тд) packed-refs refs # указатели на ваши ветки разработки ``` Давайте немного поднастроим git под себя - делаем только один раз, потом настройки сохраняться, но при необходимости их можно изменить. При установке Git была установлена утилита `git config` , которая позволяет просматривать и изменять большинство параметров работы Git’а Будь-то данные пользователя или способ работы репозитория – это самый удобный способ настройки. Настроим имя пользователя и адрес электронной почты. Эта информация важна, потому что она включается в каждый коммит. Для этого в терминале переходим в git репозиторий для которого задаем настройки и выполняем: ```python $ git config user.name "Дарья Меленцова" $ git config user.email ifireice@example.com # Если добавить опцию --global, то эти настройки запишутся в настройки пользователя и будут действовать на все проекты. # Мы выполняем эту команду без параметра --global, чтобы настройки касались только вашего проекта. ``` Что еще можно настроить с помощью `git config` читать [тут](https://git-scm.com/docs/git-config). ### Вносим изменения Теперь нам нужно внести изменения в наш проект. Но перед этим посмотрим 2 полезных команды: - `git status` - показывает текущее состояние файлов в репозитории (какие файлы изменились, удалились, добавились) - `git log` - показывает историю изменений ( это про зафиксированные изменения - коммиты (commit)) Выполним эти команды и посмотрим, что они выведут для нашего репозитория. `git status` видим, что у нас нет изменений - коммитов в репозитории ( мы ведь только его склонировали и еще ничего не делали) ```python $ git status On branch main Your branch is up to date with 'origin/main'. nothing to commit, working tree clean ``` а `git log` покажет нам, что в проекте был только один Initial commit - когда мы создавали репозиторий с README.md ```python $ git log commit 9ae1cbcc77f3b64d604612d4a599bdbb8b1cf204 (HEAD -> main, origin/main, origin/HEAD) Author: ifireiceya <117034707+ifireiceya@users.noreply.github.com> Date: Mon Oct 31 00:01:05 2022 +0300 Initial commit (END) ``` Убедились, что у нас нет неучтенных изменений, пора бы уже что-то сделать. Открывайте любимый текстовый редактор и создаем новый файл с именем hw.py. Это будет небольшая программа на Python, которая при запуске печатает “Hello World!” ```python $ vi hw.py print("Hello World!") ``` Отлично, код написан и даже в есть локально в нашем репозитории (мы же в директории проекта все делали) Итак наша задача сохранить наши изменения в “оригинальный”(удаленный) репозиторий. Для этого нам нужно: 1. Познакомить Git с новым файлом - добавить файл в индекс - `git add` 2. Зафиксировать изменения “закоммитить” - `git commit` 3. Синхронизировать наши изменения с серверов - `git push` 4. Посмотреть в репозиторий и убедится, что все сработало Делаем: Мы уже создали файл, посмотрим в каком теперь у нас статусе Git  Мы видим, что появился файл `hw.py`, но он красный. Паника! Все сломалось?! Все в порядке, но прежде чем продолжить, стоит обсудить состояние файлов с точки зрения Git’а. По мнению Git’а файл может в одним из четырех состояний: 1. Неотслеживаемый (*untracked*) 1. измененный (modified) - файл, в котором есть изменения, но он еще не добавлен в коммит (не зафиксирован) 2. отслеживаемый (staged) - файл, который добавили в индекс 3. зафиксированный (committed) - файл уже сохранен в локальной базе и в нем не было изменений с последнего коммита.  В связке с состоянием файлов есть три основных секции проекта. - рабочая директория (working directory) - это директория которая содержит в себе то с чем вы работаете или то что вы извлекли из истории проекта в данный момент. рабочая директория это просто временное место где вы можете модифицировать файлы, а затем выполнить коммит. - область индексирования (staging area) - индекс - файл, в каталоге Git, который содержит информацию о том, что попадет в следующий коммит. - каталог Git - место, где Git хранит метаданные и базу объектов вашего проекта, помните еще про `.git`? На практике: Мы добавили новый файл [hw.py](http://hw.py) и видим, что у него состояние *untracked, т.е.* не важно что мы делаем с файлом, Git проигнорирует любые изменения в нем. Для того, что бы Git начал “следить” за изменениям в файле, его нужно добавить в индекс. Для этого используем команду `git add <имя файла>` Кстати, заметили, что Git довольно дружелюбный и часто подсказывает команды, который нужно выполнить ```python $ git add hw.py # если нужно добавить много файлов и не хочется описывать, можно использовать команду # git add . # но стоит точно понимать, что добавляем, иначе придется удалять потом файлы из индекса # кстати, для удаления используется команда git rm ,но стоит почитать доку перед использованием ``` И еще не забывайте о файле `.gitignore` в котором перечисляем папки и файлы репозитория, которые Git не должен отслеживать и синхронизировать их состояние (не добавлять их в индекс). Обычно в него добавляют файлы логов, результаты сборки и тд. Поддерживает [шаблоны](https://git-scm.com/docs/gitignore). `.gitignore` то же файл, который надо добавить в индекс. Если файл попадает в “правила” `.gitignore`, то он не появится в `git status` Если файл был добавлен в индекс, а потом добавлено правило для файла в `.gitignore` - файл все равно будет отслеживаться и его надо явно [удалить](https://git-scm.com/docs/git-rm) из индекса. Посмотрим как изменилось состояние нашего файла ```python $ git status ```  О, наш файл стал зеленым и сообщение от Git изменилось. Кстати, файл теперь имеет состояние *staged*. Хотим зафиксировать изменения, тк наша задача сейчас решена - мы написали программку на Python и хотим сказать Git, что вот сейчас мы закончили работать с файлом и надо запомнить текущее состояние. Для этого на нужно закомитить файл и поможет команда `git commit` При создании принято писать описание коммита и делается это с помощью ключа `-m` ```python $ git commit -m "add python hello world" [main 6d8a5c3] add python hello world 1 file changed, 1 insertion(+) create mode 100644 hw.py ``` Пара слов про то как писать сообщения для коммитов: - максимум 50 символов - осознано и понятно, как будто пишете для человека, который по описанию должен понять, что происходит внутри коммита, ведь этим человеком через какое то время можете стать вы, а о себе надо заботиться - сообщение стоит начинать с заглавной буквы - если меняли код пишите исходный код в сообщении ```python $ git log ```  Осталось отправить наши изменения на “удаленный” сервер. Используем `git push` ```python $ git push Counting objects: 100% (4/4), done. Delta compression using up to 12 threads Compressing objects: 100% (2/2), done. Writing objects: 100% (3/3), 341 bytes | 341.00 KiB/s, done. Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 To github.com:ifireiceya/MyFirstRepo.git 9ae1cbc..6d8a5c3 main -> main ``` Предлагаю проверить, что наши изменения есть на GitHub. Идем в репозиторий и смотрим на него → видим, что появился наш файл и даже видим нам commit message, которы задали.  ## Задача немного посложнее Все здорово, но мы не всегда создаем репозитории и часто нам нужно добавлять новые фичи или исправления в уже существующий репозиторий, да еще и не наш. Например, есть у нас наш любимый опенсорсный проект, в который мы хотим причинить добро и закрыть им какой нибудь [Issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/about-issues). В учебных целях у нас есть репозиторий этой статьи на GitHub и мы хотим исправить опечатку, которую нашли в статье. Но будем делать это как будто не наш репозиторий, а мы внешние пользователи. Репозиторий хранится в `ifireice/git` , а изменения у нас делает пользователь `ifireiceya` #TODO Дописать - squash - схлапывание коммитов в один - revert - rebase - cherry-pick