Git: наглядная справка
Если вы не видите иллюстраций, попробуйте переключиться на версию со стандартными картинками (без SVG).
SVG изображения были отключены. (Включить SVG изображения)
На этой странице представлена краткая наглядная справка для наиболее часто используемых команд git. Если у вас уже есть небольшой опыт работы с git, эта страница поможет вам закрепить ваши знания. Если вам интересно, как был создан этот сайт, загляните на мой репозиторий на GitHub.
Содержание
Основные команды
Следующие четыре команды предназначены для копирования файлов между рабочей директорией, сценой, также известной как «индекс», и историей, представленной в форме коммитов.
- git add файлы копирует файлы в их текущем состоянии на сцену.
- git commit сохраняет снимок сцены в виде коммита.
- git reset — файлы восстанавливает файлы на сцене, а именно копирует файлы из последнего коммита на сцену. Используйте эту команду для отмены изменений, внесённых командой git add файлы . Вы также можете выполнить git reset , чтобы восстановить все файлы на сцене.
- git checkout — файлы копирует файлы со сцены в рабочую директорию. Эту команду удобно использовать, чтобы сбросить нежелательные изменения в рабочей директории.
Вы можете использовать git reset -p , git checkout -p , и git add -p вместо имён файлов или вместе с ними, чтобы в интерактивном режиме выбирать, какие именно изменения будут скопированы.
Также можно перепрыгнуть через сцену и сразу же получить файлы из истории прямо в рабочую директорию или сделать коммит, минуя сцену.
- git commit -a аналогичен запуску двух команд: git add для всех файлов, которые существовали в предыдущем коммите, и git commit.
- git commit файлы создаёт новый коммит, в основе которого лежат уже существующие файлы, добавляя изменения только для указанных файлов. Одновременно, указанные файлы будут скопированы на сцену.
- git checkout HEAD — файлы копирует файлы из текущего коммита и на сцену, и в рабочую директорию.
Соглашения
Иллюстрации в этой справке выдержаны в единой цветовой схеме.
Коммиты раскрашены зелёным цветом и подписаны 5-ти буквенными идентификаторами. Каждый коммит указывает на своего родителя зелёной стрелочкой. Ветки раскрашены оранжевым цветом; ветки указывают на коммиты. Специальная ссылка HEAD указывает на текущую ветку. На иллюстрации вы можете увидеть последние пять коммитов. Самый последний коммит имеет хеш ed489. main (текущая ветка) указывает на этот коммит, stable (другая ветка) указывает на предка main-ового коммита.
Подробно о командах
Есть много способов посмотреть изменения между коммитами. Ниже вы увидите несколько простых примеров. К каждой из этих команд можно добавить имена файлов в качестве дополнительного аргумента. Так мы выведем информацию об изменениях только для перечисленных файлов.
Commit
Когда вы делаете коммит, git создаёт новый объект коммита, используя файлы со сцены, а текущей коммит становится родителем для нового. После этого указатель текущей ветки перемещается на новый коммит. Вы это видите на картинке, где main — это текущая ветка. До совершения коммита main указывал на коммит ed489. После добавления нового коммита f0cec, родителем которого стал ed489, указатель ветки main был перемещён на новый коммит.
То же самое происходит, если одна ветка является предком другой ветки. Ниже показан пример нового коммита 1800b в ветке stable, которая является предком ветки main. После этого ветка stable уже больше не является предком ветки main. И в случае необходимости объединения работы, проделанной в этих разделённых ветках, вам следует воспользоваться командой merge (что более предпочтительно) или rebase.
Если вы сделали ошибку в последнем коммите, её легко исправить с помощью команды git commit —amend . Эта команда создаёт новый коммит, родителем которого будет родитель ошибочного коммита. Старый ошибочный коммит будет отброшен, конечно же если только на него не будет ещё каких-либо других ссылок, что маловероятно.
Четвертый случай коммита из состояния «detached HEAD» будет рассмотрен далее.
Checkout
Команда checkout используется для копирования файлов из истории или сцены в рабочую директорию. Также она может использоваться для переключения между ветками.
Когда вы указываете имя файла (и/или ключ -p ), git копирует эти файлы из указанного коммита на сцену и в рабочую директорию. Например, git checkout HEAD
foo.c копирует файл foo.c из коммита HEAD
(предка текущего коммита) в рабочую директорию и на сцену. Если имя коммита не указано, то файл будет скопирован со сцены в рабочую директорию. Обратите внимание на то, что при выполнении команды checkout позиция указателя текущей ветки (HEAD) остаётся прежней, указатель никуда не перемещается.
В том случае, если мы не указываем имя файла, но указываем имя локальной ветки, то указатель HEAD будет перемещён на эту ветку, то есть мы переключимся на эту ветку. При этом сцена и рабочая директория будут приведены в соответствие с этим коммитом. Любой файл, который присутствует в новом коммите (a47c3 ниже), будет скопирован из истории; любой файл, который был в старом коммите (ed489), но отсутствует в новом, будет удалён; любой файл, который не записан ни в одном коммите, будет проигнорирован.
В том случае, если мы не указываем имя файла, и не указываем имя локальной ветки, а указываем тег, дистанционную (remote) ветку, SHA-1 хеш коммита или что-то вроде main
3, то мы получаем безымянную ветку, называемую «Detached HEAD» (оторванная голова). Это очень полезная штука, если нам надо осмотреться в истории коммитов. К примеру, вам захочется скомпилировать git версии 1.6.6.1. Вы можете набрать git checkout v1.6.6.1 (это тег, не ветка), скомпилировать, установить, а затем вернуться в другую ветку, скажем git checkout main . Тем не менее, коммиты из состояния «Detached HEAD» происходят по своим особым важным правилам, и мы рассмотрим их ниже.
Коммит из состояния «Detached HEAD»
Когда мы находимся в состоянии оторванной головы (Detached HEAD), коммит совершается по тем же правилам, что и обычно, за исключением одной маленькой особенности: ни один указатель ветки не будет изменён или добавлен к новому коммиту. Вы можете представить эту ситуацию как работу с анонимной веткой.
Если после такого коммита вы переключитесь в ветку main, то коммит 2eecb, совершённый из состояния «Detached HEAD», потеряется и попросту будет уничтожен очередной сборкой мусора только потому, что нет ни одного объекта, который бы на него ссылался: ни ветки, ни тега.
В том случае, если вы хотите сохранить этот коммит на будущее, вы можете создать на основе него новую ветку командой git checkout -b new .
Reset
Команда reset перемещает указатель текущей ветки в другую позицию и дополнительно может обновить сцену и рабочую директорию. Эту команду можно также использовать для того, чтобы скопировать файл из истории на сцену, не задевая рабочую директорию.
Если коммит указан без имён файлов, указатель ветки будет перемещён на этот коммит, а затем сцена приведётся в соответствие с этим коммитом. Если мы используем ключ —soft , то сцена не будет изменена. Если мы используем ключ —hard , то будет обновлена и сцена, и рабочая директория.
Если имя коммита не будет указано, по умолчанию оно будет HEAD. В этом случае указатель ветки не будет перемещён, но сцена (а также и рабочая директория, если был использован ключ —hard ) будет приведена к состоянию последнего коммита.
Если в команде указано имя файла (и/или ключ -p ), то команда работает так же, как checkout с именем файла, за исключением того, что только сцена (но не рабочая директория) будет изменена. Если вы подставите имя коммита на место двойной черты, вы сможете получить состояние файла из этого коммита, тогда как в случае с двойной чертой вы получите состояние файла из коммита, на который указывает HEAD.
Merge
Команда merge (слияние) создает новый коммит на основе текущего коммита, применяя изменения других коммитов. Перед слиянием сцена должна быть приведена в соответствие с текущим коммитом. Самый простой случай слияния — это когда другой коммит является предком текущего коммита: в этом случае ничего не происходит. Другой простой случай слияния — когда текущий коммит является предком другого коммита: в этом случае происходит быстрая перемотка (fast-forward). Ссылка текущей ветки будет просто перемещена на новый коммит, а сцена и рабочая директория будут приведены в соответствие с новым коммитом.
Во всех других случаях выполняется «настоящее» слияние. Вы можете изменить стратегию слияния, но по умолчанию будет выполнено «рекурсивное» слияние, для которого будет взят текущий коммит (ed489 ниже на схеме), другой коммит (33104) и их общий предок (b325c); и для этих трех коммитов будет выполнено трёхстороннее слияние. Результат этого слияния будет записан в рабочую директорию и на сцену, и будет добавлен результирующий коммит со вторым родителем (33104).
Cherry Pick
Команда cherry-pick («вишенка в тортике») создаёт новый коммит на основе только одного сладкого «коммита-вишенки», применив все его изменения и сообщение.
Rebase
Перебазирование (rebase) — это альтернатива слиянию для задач объединения нескольких веток. Если слияние создаёт новый коммит с двумя родителями, оставляя нелинейную историю, то перебазирование применяет все коммиты один за одним из одной ветки в другую, оставляя за собой линейную историю коммитов. По сути это автоматическое выполнение нескольких команд cherry-pick подряд.
На схеме выше вы видите как команда берёт все коммиты, которые есть в ветке topic, но отсутствуют в ветке main (коммиты 169a6 and 2c33a), и воспроизводит их в ветке main. Затем указатель ветки перемещается на новое место. Следует заметить, что старые коммиты будут уничтожены сборщиком мусора, если на них уже ничего не будет ссылаться.
Используйте ключ —onto чтобы ограничить глубину захвата объединяемой ветки. На следующей схеме вы можете увидеть как в ветку main приходят лишь последние коммиты из текущей ветки, а именно коммиты после (но не включая) 169a6, т. е. 2c33a.
Есть также интерактивный режим перебазирования git rebase —interactive , с помощью которого вы сможете сделать вещи похитрее простого линейного применения коммитов, а именно сбрасывание (dropping), изменение порядка (reordering), правка (modifying) и выдавливание (squashing) коммитов. Нет наглядной схемы, чтобы показать эти возможности; за описанием лучше обратиться к справке по git-rebase(1).
Технические заметки
Содержание файлов не хранится в индексе (.git/index) или в объектах коммитов. Правильнее было бы сказать, что каждый файл хранится в базе данных объектов (.git/objects) в двоичном представлении; найти этот файл можно по его SHA-1 хешу. В файле индекса записаны имена файлов, их хеши и дополнительная информация. В информации о коммитах вы встретите тип данных дерево, для идентификации которого также используется SHA-1 хеш. Деревья описывают директории в рабочей директории, а также содержат информацию о других деревьях и файлах, принадлежащих обозначенному дереву. Каждый коммит хранит идентификатор своего верхнего дерева, которое содержит все файлы и другие деревья, изменённые в этом коммите.
Если вы делаете коммит из состояния «оторванной головы» (detached HEAD), то на этот коммит будет ссылаться ссылка истории HEAD. Но рано или поздно время хранения этой ссылки истечёт, и этот коммит будет уничтожен сборщиком мусора точно так же, как это делается при выполнении команд git commit —amend и git rebase .
Copyright © 2010, Mark Lodato. Russian translation © 2012, Alex Sychev.
/> Это произведение доступно по лицензии Creative Commons Attribution-NonCommercial-ShareAlike (Атрибуция — Некоммерческое использование — С сохранением условий) 3.0 США.
Основы работы с Git
В процессе разработки ПО значимая роль отводится сотрудничеству. В большинстве случаев деятельность разработчика включает работу в команде и совместное использование проекта с другими специалистами. Практический опыт использования системы контроля версий не просто важен, а ВАЖЕН для всех, кто намерен заниматься разработкой ПО. В то же время будет сложно привить навык использования контроля версий тем начинающим программистам, которые во время рабочего процесса позволяют коду изливаться из них бурным потоком, вместо того чтобы придержать обороты и размещать его по частям.
Время и целеустремленность все расставляют на свои места, и соблюдение всех правил использования контроля версий постепенно входит в привычку. Предлагаю разбить процесс написания кода на последовательные этапы.
Git послужит в качестве системы контроля версий, а Github — веб-сервиса для хостинга репозиториев Git. Осуществление этого проекта предполагает предварительное создание копии или нового репозитория. Если же вы этого еще не сделали, но хотите научиться, то добро пожаловать на этот ресурс.
Этап 1. Проверка ветки
Итак, у вас есть собственный репозиторий на локальном компьютере. Прекрасно! И вам уже не терпится написать код, но прошу вас немного подождать и кое-что сделать. Проверьте ветку, на которой вы находитесь. Для этого введите следующую команду в терминал:
Если увидели этот результат, то притормозите!
Можно написать новый код непосредственно в ветку master при условии, что вы не работаете с директорией приложения, содержащей несколько папок и файлов. Но если вы планируете работу над большим проектом, то лучше этого не делать.
Написание кода прямо в ветку master может повлечь за собой его отправку в онлайн-репозиторий без каких-либо мер предосторожности, а мы же, наоборот, хотим убедиться, что отправленный код работает должным образом.
Итак, что же следует делать, если вы находитесь на ветке master ?
Этап 2. Переключение на новую ветку
Во избежание сложностей, связанных с написанием кода прямо в ветку master , следует создать новую ветку на своем локальном компьютере. Для этого введите следующее в терминал:
Имя ветки <your-new-branch-name> должно отражать проблему, ради решения которой она и создается. Если вы намерены создать базу данных, то в качестве имени ветки следует указать create-database .
Этап 3. Написание кода
Приступаем к основной части статьи: непосредственно процесс создания кода!
Будет целесообразно сосредоточиться только на решении задачи, указанной в имени текущей ветки. Основываясь на нашем примере, код в create-database должен способствовать созданию базы данных. Как только вы его написали и он заработал согласно вашему замыслу, самое время им поделиться!
Этап 4. Просмотр статуса
Используя команду git status , мы сможем увидеть все файлы, которые были добавлены, изменены или удалены во время нашего искрометного сеанса программирования.
Если все в полном порядке, то для индексации этих изменений просто введите в терминал следующую команду:
Зеленый цвет файлов означает, что изменения были проиндексированы:
Этап 5. Создание коммита
Проиндексировав изменения, мы переходим к их фиксации в коде. Git commit сохраняет эти изменения и готовит их для отправки в онлайн-репозиторий. Но не будем спешить — с этой командой мы еще не закончили.
Git предлагает написать комментарий к коммиту. А так как гордое звание программиста (и человека) обязывает развивать в себе коммуникационные навыки, то мы с вами сейчас это сделаем:
Флаг -m указывает команде git commit , что вы добавляете полезный комментарий о коде. Итак, его уже можно отправлять, но прежде немного задержимся еще на одном этапе.
Этап 6. Проверка ветки
Догадываюсь, что вас не обрадует предложение по нескольку раз вводить в терминал команду git branch . Но так надо. Проверим дважды — от нас не убудет. Зато вы избавите себя от необходимости запоминать имена веток, поскольку за вас это сделает инструмент!
Этап 7. Отправка
Итак, код написан, коммиты изменений созданы — пора отправлять их в онлайн-репозиторий, чтобы ваши коллеги-разработчики получили к ним доступ и добавили их на свои локальные компьютеры. Вводим следующую команду:
Вы увидите нечто подобное:
Если вы используете VScode, то эта команда + клик на http-адрес перенесут вас на этап 8. И вот ваша ветка запущена в эфир!
Этап 8. Запросы на слияние
На этом этапе мы готовы, можно сказать сгораем от нетерпения, написать дополнительный код. Но прежде посмотрим, что же мы отправили. Перейдите на онлайн-репозиторий Github и сделайте запрос на слияние ветки:
Таким образом вы даете понять, что содержимое ветки безопасно для слияния с веткой master .
Если все идет по плану, то произойдет успешное слияние веток и другие разработчики получат доступ к написанному вами коду.
Этап 9. Лицом к лицу с master
На данный момент ветка master в онлайн-репозитории содержит больше кода, чем в локальном. Надо бы это исправить. Вернитесь на ветку master и введите в терминал следующую команду:
Если все сработало, то вы увидите эти зеленые строки плюсов:
Этап 10. Итоги
На этом этапе вы должны определиться с функциональностями, которые хотели бы разрабатывать в дальнейшем. Начинайте процесс с этапа 2, и пусть осознание того, что вы четко выполняете все правила работы с Git, бережет ваш покой!
Name already in use
If nothing happens, download GitHub Desktop and try again.
Launching GitHub Desktop
If nothing happens, download GitHub Desktop and try again.
Launching Xcode
If nothing happens, download Xcode and try again.
Launching Visual Studio Code
Your codespace will open once ready.
There was a problem preparing your codespace, please try again.
Latest commit
Git stats
Files
Failed to load latest commit information.
README.md
Шпаргалка по консольным командам Git
Создать новый репозиторий
Добавление файлов к отслеживанию, индексация отслеживаемых
Убирание файла, папки из отслеживания
Временно переключиться на другой коммит
Переключиться на другой коммит и продолжить работу с него
Потребуется создание новой ветки, начинающейся с указанного коммита.
Удаление файла (просто удалить отслеживаемый файл из папки недостаточно, нужно сделать его неотслеживаемым и отправить коммит)
Перемещение/переименование файлов (Git не отслеживает перемещения/переименование, но пытается его угадать)
Собираем коллекцию простых и сложных примеров работы
Создание нового репозитория, первый коммит, привязка удалённого репозитория с gthub.com, отправка изменений в удалённый репозиторий.
Обычный рабочий процесс
Создание нового репозитория на github.com, клонирование к себе, работа, периодическая «синхронизация с github.com».
Не обязательно после каждого коммита отправлять изменения в удаленный репозиторий, можно сделать это один раз в конце работы.
Внесение изменений в коммит
Работа с ветками
Есть master (публичная версия сайта), хотим масштабно что-то поменять (переверстать «шапку»), но по ходу работ возникает необходимость подправить критичный баг (неправильно указан контакт в «подвале»).
Работа с ветками, конфликт слияния
Есть master (публичная версия сайта), в двух параллельных ветках (branch_1 и branch_2) было отредактировано одно и то же место одного и того же файла, первую ветку (branch_1) влили в master, попытка влить вторую вызывает конфликт.
Синхронизация репозитория-форка с мастер-репозиторием
Есть некий репозиторий на github.com, он него нами был сделан форк, добавлены какие-то изменения. Оригинальный (мастер-) репозиторий был как-то обновлён. Задача: стянуть с мастер-репозитория изменения (которые там внесены уже после того, как мы его форкнули).
Ошибка в работе: закоммитили в мастер, но поняли, что нужно было коммитить в новую ветку (ВАЖНО: это сработает только если коммит еще не отправлен в удалённый репозиторий)
Нужно вернуть содержимое файла к состоянию, бывшему в каком-либо коммите (известна SHA коммита)
При любом действии с github (или другим удалённым сервисом) запрашивается логин/пароль
Как переключаться между коммитами git
Как переключиться на нужный коммит?
Для переключения на нужный коммит используется действие checkout . После переключения, все файлы в проекте станут такими, какими они были в данном коммите.
git checkout commit
Где commit — это хеш (обозначение, имя) коммита, причем можно указывать не весь хеш, а несколько начальных символов хеша.
Примечание: переключение на интересующий пользователя коммит всегда будет приводить репозитарий в состояние detached HEAD . Это нормально, не стоит этого бояться.
Нахождение в состоянии "detached HEAD" можно проверить командой git status :
$ git checkout 3c53ec44
HEAD отделён на 3c53ec44
Состояние "detached HEAD" означает, что текущий рабочий указатель не находится ни на какой ветке. Но как же так? Ведь коммит всегда принадлежит какой-то ветке! Это можно увидеть в том же gitk. А разгадка в том, что коммиты в Git — это, конечно, "снимки состояния репозитария, которые связаны между собой, образуя цепочки". Но нужно понимать, что цепочки коммитов в Git не считаются ветками! Вот это поворот!
Веткой в Git называется указатель на коммит, и этому указателю задано определенное имя. Если такой указатель указывает на последний коммит в цепочке, то в момент добавления нового коммита (у которого текущий является родителем) этот именованный указатель автоматически "переместится": то есть он начнет указывать на новый коммит. А имя указателя останется, естественно, без изменений. Таким образом, создается иллюзия, что программист работает в именованной ветке, и при добавлении коммитов ветка прирастает новыми коммитами. Хотя, на деле, система Git оперирует не ветками, а именно указателями на коммиты, не более того.
Нужно запомнить: никаких веток, в естественном человеческом понимании, в Git нет.
Вышеуказанные размышления можно продемонстрировать и по-другому. Нахождение в состоянии "detached HEAD" можно проверить командой git branch :
* (HEAD отделён на 3c53ec44)
Здесь видно, что пользователь переключился на какой-то коммит. Но не видно на какой ветке находится пользователь, и, тем более, не видно на какой ветке он находился ранее. (Перед переключением, в gitk, было видно, что коммит 3c53ec44 находится в ветке control_panel , но не является в ней последним). А так как коммит не последний в ветке, то после переключения рабочий указатель не начинает указывать ни на какую ветку (то есть рабочий указатель не совпадает с каким-либо именованным указателем, находящимся на конце какой-либо ветки). А такое состояние, на первый взгляд, и считается "detached HEAD".
Но тогда возникает вопрос: а что произойдет, если с помощью хеша коммита переключиться на коммит, который является последним в какой-нибудь цепочке, и в gitk видно, что на данном коммите завершается ветка control_panel ? Поймет ли Git, что произошло переключение на коммит, на который указывает именованный указатель с именем control_panel ? То есть, поймет ли Git, что происходит переключение на ветку control_panel ?
Следующие команды показывают, что произошло переключение на коммит, на который так же указывает указатель ветки control_panel . И видно, что хеш коммита (на который переключились) 4c171d82 и хеш ветки 4c171d82 — совпадают. Но состояние "detached HEAD" все равно возникло:
$ git checkout 4c171d82
* (HEAD отделён на 4c171d82) 4c171d82 Manager и регулятор громкости
control_panel 4c171d82 Manager и регулятор громкости
master c4bfddfd ALS перенесен в разел коммутаторов
new_engine b9bcf376 Merge branch ‘new_engine’ of .
То есть, даже если пользователь переключился на конечный коммит какой-либо ветки, состояние считается все равно как "detached HEAD". Надо разобраться почему так происходит.
А дело вот в чем. В Git есть два указателя:
- Указатель рабочей области проекта — так называемый working tree, или WT-указатель.
- Указатель рабочей ветки — так называемый HEAD-указатель
Так вот, надо знать что:
- Команда git checkout ХЕШ_КОММИТА — перемещает WT-указатель, но HEAD-указатель не трогает.
- Команда git checkout ИМЯ_ВЕТКИ — перемещает WT-указатель и HEAD-указатель.
Если WT-указатель и HEAD-указатель не совпадают, такое состояние и называется "detached HEAD". А когда они совпадают — значит можно нормально работать. Причем работа будет проиcходить в ветке, имя которой соответствует именованному указателю на коммит, на который так же указывает HEAD.
А как вернуться обратно после просмотра коммита?
(да, в конце команды ставится символ тире "-")
вернет состояние репозитария в ту точку, где пользователь Git был до перехода. Даже если переход производился на коммит в другой ветке, возврат будет происходить с перепрыгиванием на ту ветку, где пользователь находился изначально.
Примечание: по-сути, данная команда просмативает историю перемещений пользователя по коммитам.