IntelliJ IDEA Changelists и Git Staging
С момента выпуска IntelliJ IDEA 2020.3 есть два способа управлять своими коммитами в Git. Первый — посредством существующей функциональности со списками изменений (Changelists) IntelliJ IDEA, второй — благодаря поддержке Git staging. Это сообщение блога знакомит с обоими подходами и показывает различия. Не существует правильного или неправильного ответа, это случай выбора метода, который лучше всего подходит для вас или который вам больше всего знаком.
Прежде чем мы начнем, важно знать, что как списки изменений IntelliJ IDEA, так и Git staging позволяют закоммитить часть файла, целый файл или несколько файлов в Git. То, как они этого достигают, немного отличается, но конечный результат тот же. Список изменений IntelliJ IDEA работает с понятием диапазона в вашем контенте. Все изменения в этом диапазоне будут частью коммита. Git staging использует стандартное для git понятие staging области (также известное как «index»).
Оба варианта: IntelliJ IDEA Changelists и Git Staging доступны из Commit окна инструментов. Из IntelliJ IDEA 2020.1 вы можете переключиться на использование этого немодального окна Commit с помощью ⌘, в macOS или Ctrl + Alt + S в Windows / Linux, чтобы отобразить Preferences/Settings. Оттуда введите commit и установите флажок «Use non-model commit interface». Вы также можете использовать ⌘⇧A (macOS) или Ctrl + Shift + A (Windows / Linux) для поиска действий и ввести «Commit». Затем вы можете получить к нему доступ, нажав ⌘0 в macOS или Alt+ 0 в Windows и Linux.
Наконец, прежде чем мы начнем сравнение, вы не можете использовать списки изменений IntelliJ IDEA и промежуточную область Git одновременно. Вы можете переключаться между ними, но не можете использовать их одновременно. Начнем с Changelists IntelliJ IDEA.
Что такое «Список изменений IntelliJ IDEA»?
До выпуска 2020.3 списки изменений IntelliJ IDEA были единственным способом закоммитить изменения в вашем репозитории Git.
Списки изменений IntelliJ IDEA предназначены не только для Git, они для любой поддерживаемой системы VCS, но в этом блоге мы сосредоточимся на Git, чтобы мы могли сравнить их с новой функциональностью Git staging.
Коммит всего файла
IntelliJ IDEA всегда предоставляет вам список изменений по умолчанию, и при изменении файла файл будет отображаться в списке изменений по умолчанию с флажком, который не установлен:

Оттуда, если вы хотите выбрать весь файл для коммита, вы можете установить флажок слева от имени файла:

Это означает, что, когда вы коммитите свои файлы в Git, все изменения в выбранном вами файле будут добавлены, а затем сохранены в git. IntelliJ IDEA запускает за вас как команду, так git add так и команду git commit .
Коммит части файла
В качестве альтернативы, если вы хотите закоммитить часть файла, а не весь, вы можете дважды щелкнуть по имени файла в Default Changelist (списке изменений по умолчанию), чтобы открыть представление diff. Это представление показывает последнюю известную версию Git слева, а вашу локальную копию справа с выделенными синим цветом изменениями, которую вы можете редактировать. Вы можете установить флажки рядом с каждым изменением кода, которое вы внесли справа, чтобы сказать, что вы хотите закоммитить изменения только в этом диапазоне, а не во всем файле.

Обратите внимание, что если вы выбираете только часть файла для коммита, как в этом примере, Default Changelist будет указывать, что файл будет частично закоммитен, с помощью линии внутри чекбокса рядом с именем файла в Default Changelist, как вы можете видеть выше.
Совет: Вы также можете использовать ⌘D или Ctrl + D, чтобы открыть представление diff из окна инструмента commit.
Отмена изменений
В представлении diff вы также можете отменить изменения индивидуально, используя стрелку >> на файле слева, чтобы отменить изменения в вашем локальном файле. В этом случае правая часть обновится, чтобы отразить ваши изменения. Если вы допустили ошибку, вы можете отменить изменение или использовать локальную историю, чтобы вернуть свои изменения.

Вы также можете откатить весь файл, щелкнув его правой кнопкой мыши и выбрав Rollback.
Несколько Changelists
Список изменений по умолчанию (Default Changelist) в IntelliJ IDEA — это только часть истории. IntelliJ IDEA поддерживает несколько списков изменений. Допустим, у вас есть изменения, которые не следует закоммитить, вы можете переместить их в отдельный список изменений. Списки изменений в IntelliJ IDEA используются для группировки изменений. Вы можете назначить только один Changelist за раз. Итак, чтобы создавать группы изменений одновременно, вам нужно создать несколько списков изменений. Полезно называть списки изменений в соответствии с функцией или ошибкой, к которой они относятся. Это поможет вам отслеживать, как следует разбивать коммиты на списки изменений.
Чтобы создать несколько списков изменений, вы можете щелкнуть правой кнопкой мыши на Default Changelist и выбрать «New Changelist»:

Перемещение изменений между списками изменений
Вы также можете перемещать файлы между списками изменений (Changelists). Вы можете переместить весь файл в новый список изменений и создать этот новый список изменений, если он еще не существует в рамках этого действия. Для этого вы можете щелкнуть правой кнопкой мыши файл в списке изменений в окне Commit и выбрать «Move to Another Changelist». Вам будет предложено выбрать список изменений, если он существует, или создать список изменений, если его нет. Когда вы создаете новый список изменений, вы можете дополнительно установить для него значение «Active». Это означает, что все будущие изменения будут назначены этому Changelist.
В этом примере все будущие изменения будут теперь назначены нашему списку изменений DateFormat, потому что мы установили его как «Активный» при его создании.
В диалоговом окне «New Changelist» есть флажок, который называется «Track context». Если вы работаете с задачами и контекстами и подключили IntelliJ IDEA к соответствующему стороннему приложению, вы можете использовать этот флажок, чтобы заставить IntelliJ IDEA управлять контекстом задачи.
Помимо перемещения целых файлов между списками изменений, вы также можете перемещать отдельные изменения в файле между списками изменений. Это особенно полезно, если вы работаете над изменениями, которые влияют на один файл, но вы хотите разделить коммиты по причинам, о которых мы говорили ранее. Для того, чтобы присвоить некоторые, но не все изменения в файле на другую группу изменений, щелкните правой кнопкой мыши на изменение в представлении diff в Your version на правой стороне. Затем вы можете выбрать «Move to another changelist». Вы также можете использовать клавиши ⇧⌘M в macOS или Alt + Shift + M в Windows и Linux.
Вы также можете перемещать изменения между списками изменений, используя цветные полосы в gutter:

Как сделать Changelist активным
Наконец, мы уже показали вам, как сделать новый список изменений активным, но стоит упомянуть, что IntelliJ IDEA необходимо знать, какой список изменений использовать для новых изменений; вам всегда нужен один активный список изменений. Вы можете выбрать, какой список изменений является активным, если у вас их несколько, щелкнув правой кнопкой мыши список изменений и выбрав «Set Active Changelist». Если вы не видите эту опцию, это потому, что выбранный вами Changelist уже является активным Changelist.

Когда вы коммитите какие-либо новые изменения, они по умолчанию будут помещены в ваш активный список изменений IntelliJ IDEA Changelist.
Коммит ваших изменений в Git
Теперь, когда у вас есть списки изменений IntelliJ IDEA и ваши изменения разделены так, как вы хотите, вы готовы закоммитить их в Git. Вы можете увидеть, что будет закоммитено в Git, в окне «Commit».
Когда вас это устраивает, вы можете использовать ⌘K в macOS или Ctrl + K в Windows и Linux, чтобы открыть окно Commit. Перед тем, как нажать «Commit», вам необходимо ввести комментарий к коммиту. После того, как вы это сделаете и нажмете Commit, чтобы закоммитить их в истории Git локально, IntelliJ IDEA выполнит две команды git:
git add
git commit
Это добавляет файлы и закоммитит их за один шаг в вашей локальной истории Git. Затем вы можете продолжить и отправить изменения в удаленный репозиторий, если хотите.
Что такое Git Staging?
IntelliJ IDEA 2020.3 представила поддержку Git staging. По умолчанию он не включен, но самый быстрый способ включить его — это использовать команду Find Actions ( ⇧⌘A в macOS или Ctrl + Shift + A в Windows и Linux) и ввести git staging. Git staging — это нативный для git способ коммита изменений файлов в репозитории git.
Затем вы можете включить его:

Вы также можете включить Git staging из диалогового окна Settings/Preferences с помощью команд ⌘ в macOS или Ctrl + Alt + S, а затем введя git staging.
С помощью Git staging процесс коммита управляется в два этапа. Когда вы обрабатываете файл или его часть, IntelliJ IDEA запускает команду git add для внесения изменений. Когда вы впоследствии закоммитите эти файлы или некоторые изменения файла, IntelliJ IDEA запускает команду git commit . Конечный результат тот же, однако с Git staging вы можете воспользоваться преимуществами добавления ваших изменений перед их коммитом, если вы более знакомы с этой моделью.
Папки Staged и Unstaged
С Git Staging вы увидите две папки, а не одну как в IntelliJ IDEA Changelist в окне Commit. Каждое изменение, которое вы вносите в свой файл, представляет собой разницу между вашим локальным файлом и HEAD. Папка Unstaged, где все ваши изменения будут появляться на начальном этапе. Чтобы включить изменения в следующий коммит, вам необходимо переместить его из Unstaged папки в Staged папки. Это означает, что IntelliJ IDEA выполняет команду git add для всех изменений в файле.
Staging — перемещение файла из папки Unstaged в папку Staged
Когда вы вносите изменения в файл, они сначала появятся в вашей папке Unstaged как изменения, которые вы можете подготовить к коммиту (stage). Вы можете подготовить весь файл, перетащив его в папку Staged, используя значок + в дереве или щелкнув правой кнопкой мыши и выбрав +Stage. IntelliJ IDEA запустит команду git add , когда вы выполните эти действия:

Git add изменяет содержимое файла в индексе (поэтапное содержимое). Если вы впоследствии измените контент внутри того же диапазона, он не будет закоммитен, пока не будет помещен в папку Staged. Вы можете использовать Staged область, чтобы изменить то, что будет закоммитено, независимо от любых изменений в локальных файлах. С помощью IntelliJ Changelists любое изменение внутри того же диапазона будет закоммитено.
Staging — перемещение части файла из папки Unstaged в папку Staged
Кроме того, вы можете добавить часть файла, дважды щелкнув файл в папке Unstaged и используя стрелки <> на Staged области слева:

Вы также можете откатить весь файл, выбрав его в области Unstaged и выбрав «Rollback» (или «Revert» до версии 2021.1»). Это откат файла до состояния в индексе, а не в HEAD.
Давайте посмотрим на эту функциональность в Staged области. Изменения в Staged области означают, что IntelliJ IDEA выполнила операцию git add для изменения файла.
Unstaging — перемещение файла из папки Staged в папку Unstaged
Вы можете передумать и решить, что хотите отменить изменения (Unstage) файла целиком. Как при выполнении Staging для файла, вы можете перетащить его из Staged папки в Unstaged папку, нажав значок * — ** в дереве, или правой кнопкой мыши и выбрав «Unstage»:

Когда вы Unstage файл или часть файла, IntelliJ IDEA запускает команду git reset для изменения файла.
Unstaging — перемещение части файла из папки Staged в папку Unstaged
Вы также можете отменить изменение в файле, если вам нужно. Чтобы сделать это, вам нужно открыть в представлении diff файл, который содержит изменения, которые вы хотите убрать из папки Staged. Затем вы можете использовать стрелки >> в staged части слева, чтобы отменить изменение (Unstage). Это приведет к отмене этого конкретного изменения, и снова IntelliJ IDEA запустит команду Git, чтобы отразить изменение. Вы также можете ввести текст в редакторе, если хотите.

Staging и Unstaging отдельных изменений с помощью значков в Gutter
Вы также можете использовать значки Gutter в IntelliJ IDEA для внесения отдельных изменений.
Когда вы кликните на сплошную цветную панель, вы можете выбрать внесение изменений (Staging), панель изменит вид после добавления изменений. Нажав на панель в gutter, вы сможете отменить эти изменения.

Коммит изменений
Если Git Staging включен, ваша коммит будет состоять из изменений (различий), которые есть в вашей Staging папке. Если вас они устраивают, вы можете использовать команду ⌘K (macOS) или Ctrl + K (Windows / Linux) для открытия окна Commit. Затем вы можете ввести комментарий к коммиту и нажать Commit, чтобы закоммитить выбранные вами изменения в Git. Кроме того, вы можете использовать команду ⌘⏎ (macOS) или Ctrl + Enter (Windows / Linux), чтобы закоммитить изменения. После чего IntelliJ IDEA выполнит необходимые команды Git для выбранных вами изменений.
Затем вы можете продолжить и выполнить push изменений в удаленный репозиторий, если хотите.
Резюме
Вам решать, какой подход вы предпочитаете. Оба они позволяют достичь одного и того же результата немного по-разному.
- Changelists фокусируется на диапазонах в вашем контенте, то есть любые изменения в этом диапазоне в вашем файле включаются в коммит.
- Git Staging фокусируется на создании коммита моментального снимка staging области. Staged контент эффективно блокируется. Вы можете приступить к редактированию файла, даже если он был помещен в папку Staged; Staged контент не изменится. Это позволяет вам готовить коммиты поэтапно.
Зачем нужен индекс stage в git?
Индекс stage в Git Индекс stage в Git играет важную роль при управлении версиями кода. Он позволяет выбирать изменения, которые будут включены в следующий коммит. Зачем нужен индекс stage в Git? Он дает вам полный контроль над тем, какие изменения будут сохранены и отправлены в репозиторий. Когда вы делаете изменения в рабочей директории, они сначала попадают в индекс stage, а затем могут быть зафиксированы с помощью коммита. Вот пример использования индекса stage в Git:
git add файл.txt # Добавляет изменения файла в индекс stage git commit -m "Добавить файл" # Фиксирует изменения из индекса stage в репозитории
Использование индекса stage позволяет вам разделять изменения на логические блоки и делать коммиты, содержащие только необходимые изменения. Это помогает упростить процесс разработки, повысить понятность истории изменений, а также восстановить предыдущие состояния проекта при необходимости.
Детальный ответ
Зачем нужен индекс stage в Git?
Индекс stage – это один из наиболее важных и полезных аспектов работы с Git. Этот инструмент играет ключевую роль в процессе управления версиями и совместной работы над проектами с использованием системы контроля версий Git.
Что такое индекс stage?
Индекс stage — это промежуточный слой между рабочим каталогом и репозиторием Git. Он позволяет выбирать, контролировать и подготавливать файлы, которые вы хотите включить в следующий коммит. Когда вы вносите изменения в файлы в рабочем каталоге, Git предоставляет вам возможность выбрать, какие файлы вы хотите добавить в индекс stage. Это позволяет вам выбирать только необходимые изменения, которые вы хотите сохранить в следующем коммите, вместо добавления всех изменений в репозиторий.
Зачем это нужно?
- Контроль за коммитами: Использование индекса позволяет вам тщательно выбирать, какие изменения будут включены в следующий коммит. Вы можете добавлять и комбинировать изменения, составлять понятные коммиты и избегать случайно включения нежелательных изменений.
- Ревизия изменений: Индекс stage также позволяет вам просматривать и анализировать изменения, которые вы собираетесь включить в следующий коммит. Вы можете использовать команды «git diff» или графические инструменты для отображения различий между рабочим каталогом, индексом и последним коммитом.
- Интерактивное добавление изменений: Индекс stage позволяет вам взаимодействовать с Git и выбирать конкретные файлы или части файлов для включения в следующий коммит. Вы можете использовать команду «git add -p» для интерактивного добавления изменений и контроля за тем, что будет включено или исключено из следующего коммита.
Примеры использования
Давайте рассмотрим некоторые примеры использования индекса stage в Git:
$ git add file1.txt $ git status
В этом примере мы добавляем новый файл file1.txt в индекс stage с помощью команды «git add». Затем мы можем проверить статус индекса stage с помощью команды «git status».
$ git add file2.txt $ git add file3.txt $ git status
В этом примере мы добавляем изменения в существующих файлах file2.txt и file3.txt в индекс stage. Затем мы снова проверяем статус индекса stage.
$ git add -p $ git status
В этом примере мы используем команду «git add -p» для интерактивного добавления изменений. Git покажет нам различные части файла и позволит выбрать, какие изменения мы хотим добавить в индекс stage.
Вывод
Индекс stage является важным инструментом в системе контроля версий Git. Он позволяет контролировать, выбирать и подготавливать изменения перед коммитом. Использование индекса stage обеспечивает контроль над изменениями и позволяет создавать понятные и логические коммиты.
Помните, что индекс stage является неотъемлемой частью рабочего процесса с Git, и его использование будет способствовать более эффективной и организованной работе с вашими проектами.
2.2 Основы Git — Запись изменений в репозиторий
Итак, у вас имеется настоящий Git-репозиторий и рабочая копия файлов для некоторого проекта. Вам нужно делать некоторые изменения и фиксировать «снимки» состояния (snapshots) этих изменений в вашем репозитории каждый раз, когда проект достигает состояния, которое вам хотелось бы сохранить.
Запомните, каждый файл в вашем рабочем каталоге может находиться в одном из двух состояний: под версионным контролем (отслеживаемые) и нет (неотслеживаемые). Отслеживаемые файлы — это те файлы, которые были в последнем снимке состояния проекта; они могут быть неизменёнными, изменёнными или подготовленными к коммиту. Если кратко, то отслеживаемые файлы — это те файлы, о которых знает Git.
Неотслеживаемые файлы — это всё остальное, любые файлы в вашем рабочем каталоге, которые не входили в ваш последний снимок состояния и не подготовлены к коммиту. Когда вы впервые клонируете репозиторий, все файлы будут отслеживаемыми и неизменёнными, потому что Git только что их извлек и вы ничего пока не редактировали.
Как только вы отредактируете файлы, Git будет рассматривать их как изменённые, так как вы изменили их с момента последнего коммита. Вы индексируете эти изменения, затем фиксируете все проиндексированные изменения, а затем цикл повторяется.

Рисунок 8. Жизненный цикл состояний файлов
Определение состояния файлов
Основной инструмент, используемый для определения, какие файлы в каком состоянии находятся — это команда git status . Если вы выполните эту команду сразу после клонирования, вы увидите что-то вроде этого:
$ git status On branch master Your branch is up-to-date with 'origin/master'. nothing to commit, working tree clean
Это означает, что у вас чистый рабочий каталог, другими словами — в нём нет отслеживаемых изменённых файлов. Git также не обнаружил неотслеживаемых файлов, в противном случае они бы были перечислены здесь. Наконец, команда сообщает вам на какой ветке вы находитесь и сообщает вам, что она не расходится с веткой на сервере. Пока что это всегда ветка master , ветка по умолчанию; в этой главе это не важно. В главе Ветвление в Git будут рассмотрены ветки и ссылки более детально.
Примечание
В 2020 году GitHub изменил имя ветки по умолчанию с master на main , другие же git-хостинг платформы последовали этому примеру. Поэтому, вы можете обнаружить, что ветка по умолчанию для новых репозиториев — main , а не master . Более того, имя ветки по умолчанию можно изменить (как вы видели в Настройка ветки по умолчанию), поэтому вам может встретиться и другое имя. При этом Git продолжает использовать имя master , поэтому далее в книге мы используем именно его.
Предположим, вы добавили в свой проект новый файл, простой файл README . Если этого файла раньше не было, и вы выполните git status , вы увидите свой неотслеживаемый файл вот так:
$ echo 'My Project' > README $ git status On branch master Your branch is up-to-date with 'origin/master'. Untracked files: (use "git add . " to include in what will be committed) README nothing added to commit but untracked files present (use "git add" to track)
Понять, что новый файл README неотслеживаемый можно по тому, что он находится в секции «Untracked files» в выводе команды status . Статус Untracked означает, что Git видит файл, которого не было в предыдущем снимке состояния (коммите); Git не станет добавлять его в ваши коммиты, пока вы его явно об этом не попросите. Это предохранит вас от случайного добавления в репозиторий сгенерированных бинарных файлов или каких-либо других, которые вы и не думали добавлять. Мы хотели добавить README, так давайте сделаем это.
Отслеживание новых файлов
Для того чтобы начать отслеживать (добавить под версионный контроль) новый файл, используется команда git add . Чтобы начать отслеживание файла README , вы можете выполнить следующее:
$ git add README
Если вы снова выполните команду status , то увидите, что файл README теперь отслеживаемый и добавлен в индекс:
$ git status On branch master Your branch is up-to-date with 'origin/master'. Changes to be committed: (use "git restore --staged . " to unstage) new file: README
Вы можете видеть, что файл проиндексирован, так как он находится в секции «Changes to be committed». Если вы выполните коммит в этот момент, то версия файла, существовавшая на момент выполнения вами команды git add , будет добавлена в историю снимков состояния. Как вы помните, когда вы ранее выполнили git init , затем вы выполнили git add (файлы) — это было сделано для того, чтобы добавить файлы в вашем каталоге под версионный контроль. Команда git add принимает параметром путь к файлу или каталогу, если это каталог, команда рекурсивно добавляет все файлы из указанного каталога в индекс.
Индексация изменённых файлов
Давайте модифицируем файл, уже находящийся под версионным контролем. Если вы измените отслеживаемый файл CONTRIBUTING.md и после этого снова выполните команду git status , то результат будет примерно следующим:
$ git status On branch master Your branch is up-to-date with 'origin/master'. Changes to be committed: (use "git reset HEAD . " to unstage) new file: README Changes not staged for commit: (use "git add . " to update what will be committed) (use "git checkout -- . " to discard changes in working directory) modified: CONTRIBUTING.md
Файл CONTRIBUTING.md находится в секции «Changes not staged for commit» — это означает, что отслеживаемый файл был изменён в рабочем каталоге, но пока не проиндексирован. Чтобы проиндексировать его, необходимо выполнить команду git add . Это многофункциональная команда, она используется для добавления под версионный контроль новых файлов, для индексации изменений, а также для других целей, например для указания файлов с исправленным конфликтом слияния. Вам может быть понятнее, если вы будете думать об этом как «добавить этот контент в следующий коммит», а не как «добавить этот файл в проект». Выполним git add , чтобы проиндексировать CONTRIBUTING.md , а затем снова выполним git status :
$ git add CONTRIBUTING.md $ git status On branch master Your branch is up-to-date with 'origin/master'. Changes to be committed: (use "git reset HEAD . " to unstage) new file: README modified: CONTRIBUTING.md
Теперь оба файла проиндексированы и войдут в следующий коммит. В этот момент вы, предположим, вспомнили одно небольшое изменение, которое вы хотите сделать в CONTRIBUTING.md до коммита. Вы открываете файл, вносите и сохраняете необходимые изменения и вроде бы готовы к коммиту. Но давайте-ка ещё раз выполним git status :
$ vim CONTRIBUTING.md $ git status On branch master Your branch is up-to-date with 'origin/master'. Changes to be committed: (use "git reset HEAD . " to unstage) new file: README modified: CONTRIBUTING.md Changes not staged for commit: (use "git add . " to update what will be committed) (use "git checkout -- . " to discard changes in working directory) modified: CONTRIBUTING.md
Что за чёрт? Теперь CONTRIBUTING.md отображается как проиндексированный и непроиндексированный одновременно. Как такое возможно? Такая ситуация наглядно демонстрирует, что Git индексирует файл в точности в том состоянии, в котором он находился, когда вы выполнили команду git add . Если вы выполните коммит сейчас, то файл CONTRIBUTING.md попадёт в коммит в том состоянии, в котором он находился, когда вы последний раз выполняли команду git add , а не в том, в котором он находится в вашем рабочем каталоге в момент выполнения git commit . Если вы изменили файл после выполнения git add , вам придётся снова выполнить git add , чтобы проиндексировать последнюю версию файла:
$ git add CONTRIBUTING.md $ git status On branch master Your branch is up-to-date with 'origin/master'. Changes to be committed: (use "git reset HEAD . " to unstage) new file: README modified: CONTRIBUTING.md
Сокращённый вывод статуса
Вывод команды git status довольно всеобъемлющий и многословный. Git также имеет флаг вывода сокращённого статуса, так что вы можете увидеть изменения в более компактном виде. Если вы выполните git status -s или git status —short вы получите гораздо более упрощённый вывод:
$ git status -s M README MM Rakefile A lib/git.rb M lib/simplegit.rb ?? LICENSE.txt
Новые неотслеживаемые файлы помечены ?? слева от них, файлы добавленные в отслеживаемые помечены A , отредактированные файлы помечены M и так далее. В выводе содержится два столбца — в левом указывается статус файла, а в правом модифицирован ли он после этого. К примеру в нашем выводе, файл README модифицирован в рабочем каталоге, но не проиндексирован, а файл lib/simplegit.rb модифицирован и проиндексирован. Файл Rakefile модифицирован, проиндексирован и ещё раз модифицирован, таким образом на данный момент у него есть те изменения, которые попадут в коммит, и те, которые не попадут.
Игнорирование файлов
Зачастую, у вас имеется группа файлов, которые вы не только не хотите автоматически добавлять в репозиторий, но и видеть в списках неотслеживаемых. К таким файлам обычно относятся автоматически генерируемые файлы (различные логи, результаты сборки программ и т. п.). В таком случае, вы можете создать файл .gitignore . с перечислением шаблонов соответствующих таким файлам. Вот пример файла .gitignore :
$ cat .gitignore *.[oa] *~
Первая строка предписывает Git игнорировать любые файлы заканчивающиеся на «.o» или «.a» — объектные и архивные файлы, которые могут появиться во время сборки кода. Вторая строка предписывает игнорировать все файлы заканчивающиеся на тильду ( ~ ), которая используется во многих текстовых редакторах, например Emacs, для обозначения временных файлов. Вы можете также включить каталоги log, tmp или pid; автоматически создаваемую документацию; и т. д. и т. п. Хорошая практика заключается в настройке файла .gitignore до того, как начать серьёзно работать, это защитит вас от случайного добавления в репозиторий файлов, которых вы там видеть не хотите.
К шаблонам в файле .gitignore применяются следующие правила:
- Пустые строки, а также строки, начинающиеся с # , игнорируются.
- Стандартные шаблоны являются глобальными и применяются рекурсивно для всего дерева каталогов.
- Чтобы избежать рекурсии используйте символ слеш (/) в начале шаблона.
- Чтобы исключить каталог добавьте слеш (/) в конец шаблона.
- Можно инвертировать шаблон, использовав восклицательный знак (!) в качестве первого символа.
Glob-шаблоны представляют собой упрощённые регулярные выражения, используемые командными интерпретаторами. Символ ( * ) соответствует 0 или более символам; последовательность [abc] — любому символу из указанных в скобках (в данном примере a, b или c); знак вопроса ( ? ) соответствует одному символу; и квадратные скобки, в которые заключены символы, разделённые дефисом ( [0-9] ), соответствуют любому символу из интервала (в данном случае от 0 до 9). Вы также можете использовать две звёздочки, чтобы указать на вложенные каталоги: a/**/z соответствует a/z , a/b/z , a/b/c/z , и так далее.
Вот ещё один пример файла .gitignore :
# Исключить все файлы с расширением .a *.a # Но отслеживать файл lib.a даже если он подпадает под исключение выше !lib.a # Исключить файл TODO в корневом каталоге, но не файл в subdir/TODO /TODO # Игнорировать все файлы в каталоге build/ build/ # Игнорировать файл doc/notes.txt, но не файл doc/server/arch.txt doc/*.txt # Игнорировать все .txt файлы в каталоге doc/ doc/**/*.txt
GitHub поддерживает довольно полный список примеров .gitignore файлов для множества проектов и языков https://github.com/github/gitignore это может стать отправной точкой для .gitignore в вашем проекте.
Примечание
В простейшем случае репозиторий будет иметь один файл .gitignore в корневом каталоге, правила из которого будут рекурсивно применяться ко всем подкаталогам. Так же возможно использовать .gitignore файлы в подкаталогах. Правила из этих файлов будут применяться только к каталогам, в которых они находятся. Например, репозиторий исходного кода ядра Linux содержит 206 файлов .gitignore .
Детальное рассмотрение использования нескольких .gitignore файлов выходит за пределы этой книги; детали доступны в справке man gitignore .
Просмотр индексированных и неиндексированных изменений
Если результат работы команды git status недостаточно информативен для вас — вам хочется знать, что конкретно поменялось, а не только какие файлы были изменены — вы можете использовать команду git diff . Позже мы рассмотрим команду git diff подробнее; вы, скорее всего, будете использовать эту команду для получения ответов на два вопроса: что вы изменили, но ещё не проиндексировали, и что вы проиндексировали и собираетесь включить в коммит. Если git status отвечает на эти вопросы в самом общем виде, перечисляя имена файлов, git diff показывает вам непосредственно добавленные и удалённые строки — патч как он есть.
Допустим, вы снова изменили и проиндексировали файл README , а затем изменили файл CONTRIBUTING.md без индексирования. Если вы выполните команду git status , вы опять увидите что-то вроде:
$ git status On branch master Your branch is up-to-date with 'origin/master'. Changes to be committed: (use "git reset HEAD . " to unstage) modified: README Changes not staged for commit: (use "git add . " to update what will be committed) (use "git checkout -- . " to discard changes in working directory) modified: CONTRIBUTING.md
Чтобы увидеть, что же вы изменили, но пока не проиндексировали, наберите git diff без аргументов:
$ git diff diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8ebb991..643e24f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -65,7 +65,8 @@ branch directly, things can get messy. Please include a nice description of your changes when you submit your PR; if we have to read the whole diff to figure out why you're contributing in the first place, you're less likely to get feedback and have your change -merged in. +merged in. Also, split your changes into comprehensive chunks if you patch is +longer than a dozen lines. If you are starting to work on a particular area, feel free to submit a PR that highlights your work in progress (and note in the PR title that it's
Эта команда сравнивает содержимое вашего рабочего каталога с содержимым индекса. Результат показывает ещё не проиндексированные изменения.
Если вы хотите посмотреть, что вы проиндексировали и что войдёт в следующий коммит, вы можете выполнить git diff —staged . Эта команда сравнивает ваши проиндексированные изменения с последним коммитом:
$ git diff --staged diff --git a/README b/README new file mode 100644 index 0000000..03902a1 --- /dev/null +++ b/README @@ -0,0 +1 @@ +My Project
Важно отметить, что git diff сама по себе не показывает все изменения сделанные с последнего коммита — только те, что ещё не проиндексированы. Такое поведение может сбивать с толку, так как если вы проиндексируете все свои изменения, то git diff ничего не вернёт.
Другой пример: вы проиндексировали файл CONTRIBUTING.md и затем изменили его, вы можете использовать git diff для просмотра как проиндексированных изменений в этом файле, так и тех, что пока не проиндексированы. Если наше окружение выглядит вот так:
$ git add CONTRIBUTING.md $ echo '# test line' >> CONTRIBUTING.md $ git status On branch master Your branch is up-to-date with 'origin/master'. Changes to be committed: (use "git reset HEAD . " to unstage) modified: CONTRIBUTING.md Changes not staged for commit: (use "git add . " to update what will be committed) (use "git checkout -- . " to discard changes in working directory) modified: CONTRIBUTING.md
Используйте git diff для просмотра непроиндексированных изменений
$ git diff diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 643e24f..87f08c8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -119,3 +119,4 @@ at the ## Starter Projects See our [projects list](https://github.com/libgit2/libgit2/blob/development/PROJECTS.md). +# test line
а так же git diff —cached для просмотра проиндексированных изменений ( —staged и —cached синонимы):
$ git diff --cached diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8ebb991..643e24f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -65,7 +65,8 @@ branch directly, things can get messy. Please include a nice description of your changes when you submit your PR; if we have to read the whole diff to figure out why you're contributing in the first place, you're less likely to get feedback and have your change -merged in. +merged in. Also, split your changes into comprehensive chunks if you patch is +longer than a dozen lines. If you are starting to work on a particular area, feel free to submit a PR that highlights your work in progress (and note in the PR title that it's
Примечание
Git Diff во внешних инструментах
Мы будем продолжать использовать команду git diff различными способами на протяжении всей книги. Существует ещё один способ просматривать эти изменения, если вы предпочитаете графический просмотр или внешнюю программу просмотра различий, вместо консоли. Выполнив команду git difftool вместо git diff , вы сможете просмотреть изменения в файле с помощью таких программ как emerge, vimdiff и других (включая коммерческие продукты). Выполните git difftool —tool-help чтобы увидеть какие из них уже установлены в вашей системе.
Коммит изменений
Теперь, когда ваш индекс находится в таком состоянии, как вам и хотелось, вы можете зафиксировать свои изменения. Запомните, всё, что до сих пор не проиндексировано — любые файлы, созданные или изменённые вами, и для которых вы не выполнили git add после редактирования — не войдут в этот коммит. Они останутся изменёнными файлами на вашем диске. В нашем случае, когда вы в последний раз выполняли git status , вы видели что всё проиндексировано, и вот, вы готовы к коммиту. Простейший способ зафиксировать изменения — это набрать git commit :
$ git commit
Эта команда откроет выбранный вами текстовый редактор.
Примечание
Редактор устанавливается переменной окружения EDITOR — обычно это vim или emacs, хотя вы можете установить любой другой с помощью команды git config —global core.editor , как было показано в главе Введение).
В редакторе будет отображён следующий текст (это пример окна Vim):
# Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # On branch master # Your branch is up-to-date with 'origin/master'. # # Changes to be committed: # new file: README # modified: CONTRIBUTING.md # ~ ~ ~ ".git/COMMIT_EDITMSG" 9L, 283C
Вы можете видеть, что комментарий по умолчанию для коммита содержит закомментированный результат работы команды git status и ещё одну пустую строку сверху. Вы можете удалить эти комментарии и набрать своё сообщение или же оставить их для напоминания о том, что вы фиксируете.
Примечание
Для ещё более подробного напоминания, что же именно вы поменяли, можете передать аргумент -v в команду git commit . Это приведёт к тому, что в комментарий будет также помещена дельта/diff изменений, таким образом вы сможете точно увидеть все изменения которые вы совершили.
Когда вы выходите из редактора, Git создаёт для вас коммит с этим сообщением, удаляя комментарии и вывод команды diff .
Есть и другой способ — вы можете набрать свой комментарий к коммиту в командной строке вместе с командой commit указав его после параметра -m , как в следующем примере:
$ git commit -m "Story 182: fix benchmarks for speed" [master 463dc4f] Story 182: fix benchmarks for speed 2 files changed, 2 insertions(+) create mode 100644 README
Итак, вы создали свой первый коммит! Вы можете видеть, что коммит вывел вам немного информации о себе: на какую ветку вы выполнили коммит ( master ), какая контрольная сумма SHA-1 у этого коммита ( 463dc4f ), сколько файлов было изменено, а также статистику по добавленным/удалённым строкам в этом коммите.
Запомните, что коммит сохраняет снимок состояния вашего индекса. Всё, что вы не проиндексировали, так и висит в рабочем каталоге как изменённое; вы можете сделать ещё один коммит, чтобы добавить эти изменения в репозиторий. Каждый раз, когда вы делаете коммит, вы сохраняете снимок состояния вашего проекта, который позже вы можете восстановить или с которым можно сравнить текущее состояние.
Игнорирование индексации
Несмотря на то, что индекс может быть удивительно полезным для создания коммитов именно такими, как вам и хотелось, он временами несколько сложнее, чем вам нужно в процессе работы. Если у вас есть желание пропустить этап индексирования, Git предоставляет простой способ. Добавление параметра -a в команду git commit заставляет Git автоматически индексировать каждый уже отслеживаемый на момент коммита файл, позволяя вам обойтись без git add :
$ git status On branch master Your branch is up-to-date with 'origin/master'. Changes not staged for commit: (use "git add . " to update what will be committed) (use "git checkout -- . " to discard changes in working directory) modified: CONTRIBUTING.md no changes added to commit (use "git add" and/or "git commit -a") $ git commit -a -m 'Add new benchmarks' [master 83e38c7] Add new benchmarks 1 file changed, 5 insertions(+), 0 deletions(-)
Обратите внимание, что в данном случае перед коммитом вам не нужно выполнять git add для файла CONTRIBUTING.md , потому что флаг -a включает все файлы. Это удобно, но будьте осторожны: флаг -a может включить в коммит нежелательные изменения.
Удаление файлов
Для того чтобы удалить файл из Git, вам необходимо удалить его из отслеживаемых файлов (точнее, удалить его из вашего индекса) а затем выполнить коммит. Это позволяет сделать команда git rm , которая также удаляет файл из вашего рабочего каталога, так что в следующий раз вы не увидите его как «неотслеживаемый».
Если вы просто удалите файл из своего рабочего каталога, он будет показан в секции «Changes not staged for commit» (изменённые, но не проиндексированные) вывода команды git status :
$ rm PROJECTS.md $ git status On branch master Your branch is up-to-date with 'origin/master'. Changes not staged for commit: (use "git add/rm . " to update what will be committed) (use "git checkout -- . " to discard changes in working directory) deleted: PROJECTS.md no changes added to commit (use "git add" and/or "git commit -a")
Затем, если вы выполните команду git rm , удаление файла попадёт в индекс:
$ git rm PROJECTS.md rm 'PROJECTS.md' $ git status On branch master Your branch is up-to-date with 'origin/master'. Changes to be committed: (use "git reset HEAD . " to unstage) deleted: PROJECTS.md
После следующего коммита файл исчезнет и больше не будет отслеживаться. Если вы изменили файл и уже проиндексировали его, вы должны использовать принудительное удаление с помощью параметра -f . Это сделано для повышения безопасности, чтобы предотвратить ошибочное удаление данных, которые ещё не были записаны в снимок состояния и которые нельзя восстановить из Git.
Другая полезная штука, которую вы можете захотеть сделать — это удалить файл из индекса, оставив его при этом в рабочем каталоге. Другими словами, вы можете захотеть оставить файл на жёстком диске, но перестать отслеживать изменения в нём. Это особенно полезно, если вы забыли добавить что-то в файл .gitignore и по ошибке проиндексировали, например, большой файл с логами, или кучу промежуточных файлов компиляции. Чтобы сделать это, используйте опцию —cached :
$ git rm --cached README
В команду git rm можно передавать файлы, каталоги или шаблоны. Это означает, что вы можете сделать что-то вроде:
$ git rm log/\*.log
Обратите внимание на обратный слеш ( \ ) перед * . Он необходим из-за того, что Git использует свой собственный обработчик имён файлов вдобавок к обработчику вашего командного интерпретатора. Эта команда удаляет все файлы, имеющие расширение .log и находящиеся в каталоге log/ . Или же вы можете сделать вот так:
$ git rm \*~
Эта команда удаляет все файлы, имена которых заканчиваются на ~ .
Перемещение файлов
В отличие от многих других систем контроля версий, Git не отслеживает перемещение файлов явно. Когда вы переименовываете файл в Git, в нём не сохраняется никаких метаданных, говорящих о том, что файл был переименован. Однако, Git довольно умён в плане обнаружения перемещений постфактум — мы рассмотрим обнаружение перемещения файлов чуть позже.
Таким образом, наличие в Git команды mv выглядит несколько странным. Если вам хочется переименовать файл в Git, вы можете сделать что-то вроде:
$ git mv file_from file_to
и это отлично сработает. На самом деле, если вы выполните что-то вроде этого и посмотрите на статус, вы увидите, что Git считает, что произошло переименование файла:
$ git mv README.md README $ git status On branch master Your branch is up-to-date with 'origin/master'. Changes to be committed: (use "git reset HEAD . " to unstage) renamed: README.md -> README
Однако, это эквивалентно выполнению следующих команд:
$ mv README.md README $ git rm README.md $ git add README
Git неявно определяет, что произошло переименование, поэтому неважно, переименуете вы файл так или используя команду mv . Единственное отличие состоит лишь в том, что mv — одна команда вместо трёх — это функция для удобства. Важнее другое — вы можете использовать любой удобный способ для переименования файла, а затем воспользоваться командами add или rm перед коммитом.
Git для начинающих. Часть 5. Создание репозитория и первый коммит
![]()
В этом уроке мы рассмотрим, как создать пустой git репозиторий, добавить в него файлы и сделать первый коммит. Также коснемся вопроса просмотра коммитов и состояния рабочего каталога.
- Создание репозитория git
- Создание первого коммита
Создание репозитория
Для того чтобы создать репозиторий, для начала, создайте папку, в которой он будет располагаться. В нашем случае это будет каталог с названием repo .
> mkdir repo
Теперь перейдем в этот каталог.
>cd repo
Создадим в нем пустой git репозиторий.
> git init
Создание первого коммита
Если мы посмотрим на список коммитов, которые были отправлены в репозиторий, то увидим, что он пустой – это правильно, т.к. мы пока только создали репозиторий и ничего ещё туда не отправляли.
> git log fatal: your current branch 'master' does not have any commits yet
Для просмотра состояния рабочего каталога воспользуемся командой git status .
> git status On branch master Initial commit nothing to commit (create/copy files and use "git add" to track)
Создадим в нашем каталоге пустой файл.
> touch README.md
Теперь, если мы выполним команду git status , то увидим, что в нашем каталоге появился один неотслеживаемый файл: README.md .
> git status On branch master Initial commit Untracked files: (use "git add . " to include in what will be committed) README.md nothing added to commit but untracked files present (use "git add" to track)
Добавим, созданный файл в stage . Stage (или cache ) – это хранилище для файлов с изменениями, информация о которых попадет в единый коммит. Stage является элементом архитектуры трех деревьев, на базе которой построен git , более подробно смотрите здесь. Для добавления файла README.md в stage необходимо воспользоваться командой git add .
> git add README.md
Если изменение было произведено в нескольких файлах, и мы хотим их все отправить в stage , то вместо имени файла поставьте точку.
Выполним git status для того, чтобы посмотреть на то, что сейчас происходит в нашем каталоге.
> git status On branch master Initial commit Changes to be committed: (use "git rm --cached . " to unstage) new file: README.md
Как видно, в stage был добавлен один файл с именем README.md и теперь представленный набор изменений готов к отправке в репозиторий – т.е. к коммиту. Сделаем это.
> git commit -m "[create repository]" [master (root-commit) 500067c] [create repository] 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 README.md
Проверим статус каталога.
> git status On branch master nothing to commit, working tree clean
Как видно с момента последнего коммита никаких изменений в рабочем каталоге не производилось.
Теперь взглянем на список коммитов.
> git log commit 500067cc0b80643d38e2a24e9e0699031ada6be3 Author: Writer Date: Mon Feb 12 22:51:14 2018 +0500 [create repository]
Из приведенной информации видно, что был отправлен один коммит, который имеет ID : 500067cc0b80643d38e2a24e9e0699031ada6be3, более подробно об идентификаторах будет рассказано в следующих уроках. Автор данного коммита Writer , он (коммит) был создан Mon Feb 12 22:51:14 2018 +0500, с сообщением: [create repository] . Это довольно подробная информация, когда коммитов станет много, такой формат вывода будет не очень удобным, сокращенный вариант выглядит так.
> git log --oneline 500067c [create repository]
Подведем небольшое резюме вышесказанному.
Создание пустого репозитория.
> git init
Добавление файлов в stage .
> git add filename
> git commit -m “message”
Просмотр статуса каталога.
> git status
Просмотр коммитов в репозитории.
> git log
Просмотр коммитов в репозитории с сокращенным выводом информации.
> git log --oneline
Отличный курс по git делают ребята из GeekBrains , найдите в разделе “Курсы” курс “Git. Быстрый старт” , он бесплатный!
Раздел: Git Git для начинающих Метки: Git, Git для начинающих, Уроки по Git
Git для начинающих. Часть 5. Создание репозитория и первый коммит : 4 комментария
- SGate 06.03.2019 Так все хорошо в этом курсе, все четко ясно до тех пор пока не было сказано ввести команду touch README.md потому что сразу получил ошибку “touch” является внутренней или внешней командой и т.д. Система Windows 10
- writer 16.03.2019 Да, эта команда доступна только в Linux (по умолчанию). В Windows необходимо установить специальный пакет (cygwin) или, если это Windows 10, то можно прямо Ubuntu установить как приложение.
Самый простой способ заменить эту команду в Windows 10 будет использование echo:
echo “” > README.md
В Linux эта команда должна выполниться без проблем)))