Используем Гит

Git как полезный инструмент для хобби-программиста

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

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

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

Основные концепции Git вращаются вокруг репозиториев, коммитов и ветвей. Репозиторий — это набор файлов, изменения в которых вы хотите отслеживать, например файлы в вашем проекте Arduino. Коммиты — это сохраненные изменения, или скажем отпечатки состояния проекта, которые можно использовать как точки восстановления. Ветки - цепочки последовательных коммитов. Параллельные ветки предоставляют безопасную площадку для тестирования новых идей, не влияя на основной код, и их можно объединять или отбрасывать в зависимости от результата.

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

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

Вот несколько ссылок, если вы хотите узнать больше о том, как работает Git и обо всех поддерживаемых им функциях (англ)

8 лайков

Установка и настройка Git

Инсталляция в Линукс

(коммент от b707: В раздел для Линукс я просто скопирую часть из руководства с английского сайта, поскольку на всех моих машинах с Линукс Гит давно установлен. Возможно, и вам не придется его устанавливать вручную, так как многие дистрибутивы Линукс его уже содержат.)

Проверить наличие Git в линукс можно в консоли:

david@VirtualUbuntu:~$ git --version

Если в ответ вы получаете что-то типа

Command 'git' not found, but can be installed with:
sudo apt install git

Воспользуемся советом и сделаем как предлагают:

david@VirtualUbuntu:~$ sudo apt install git

проверка после установки:

david@VirtualUbuntu:~$ git --version
git version 2.34.1

Теперь Git установлен.

Инсталляция в Windows

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

D:\dde\tt>git --version
git version 2.44.0.windows.1

Настройка Git

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

Открываем окно терминала в линукс или командную строку в винде и даем две команды:

git config --global user.name "<UserName>"
git config --global user.email "<Email>"

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

2 лайка

1 сообщение было перемещено в эту тему: Обсуждение руководства “Используем Гит”

3 сообщения были перемещены в эту тему: Обсуждение руководства “Используем Гит”

Работа с Git из командной строки

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

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

Я использую Линукс, поэтому мои пути к файлам могут отличаться от ваших, но все команды одинаковы на любой ОС.

Шаг 1: Инициализация и первый коммит

Первый шаг в любом проекте Arduino — это пустой скетч. Нет необходимости начинать именно с пустого скетча, начальное состояние репозитория может быть любое, вы можете добавить в Git свои старые проекты, которыми занимаетесь уже давно - но в учебнике лучше начинать с самого начала.

Итак, я создаю новый скетч и сохраняю его как GitBlink.ino

void setup() {

}

void loop() {

}

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

cd Arduino/GitBlink

даем команду

git init

и получаем в ответ:

hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint: 
hint: 	git config --global init.defaultBranch <name>
hint: 
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint: 
hint: 	git branch -m <name>

Initialized empty Git repository in /home/dmit/Arduino/GitBlink/.git/

Репо инициализируется пустым. Добавим в него все файлы из текущего каталога (в нашем случае файл один):

git add --all

Теперь все готово, чтобы выполнить наш первый коммит:

git commit -am"Blank"

Эту команду вы будете повторять снова и снова, после каждого изменения в проекте, которое вы хотите сохранить. Опция -a означает обработать все изменившиеся файлы, а опция -m - что далее следует комментарий к коммиту (message). Если давать команду коммит без -m, то Git запустит встроенный редактор системы и будет ждать от вас ввода сообщения в нем. В линуксе встроенным консольным редактором по умолчанию является vim и я не советую с ним связыватся тем, кто не знает что это такое :slight_smile: Лучше всегда задавайте коммент к коммиту через опцию -m.

Команда выдает в терминал результат своей работы:

master (root-commit) 845e514] Blank
 1 file changed, 9 insertions(+)
 create mode 100644 GitBlink.ino

Можно приступать к написанию кода.

2 лайка

Шаг 2: Добавляем код

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

Предположим, мы хотим мигать светодиодом с частотой 1 Гц. Итак, давайте напишем Blink.

void setup() {
  pinMode(13, OUTPUT);
}

void loop() {
  digitalWrite(13, HIGH);
  delay(500);
  digitalWrite(13, LOW);
  delay(500);
}

Сохраняем и компилируем. Компиляция прошла без ошибок, так что мы можем выполнить коммит:

git commit -am "Blink"

Команда та же, что и раньше, только я изменил комментарий с «Пустой»(Blank) на «Мигать» (Blink). Теперь это сохранено в истории :slight_smile:

Опция -a говорит команде commit, что мы хотим зафиксировать все изменения и скрывает от нас промежуточную стадию - индексацию или staging, на которой мы можем выбрать только некоторые изменения для фиксации. подробнее об этом - в Приложении А сообщение 12.

Шаг 3: Продолжаем разработку

Мне кажется, этот код нехорош. К чему эти магические числа? Добавим осмысленности введением переменных:

const int ledPin = 13;
const int delayTime = 500; 

void setup() {
  pinMode(ledPin, OUTPUT);
}

void loop() {
  digitalWrite(ledPin, HIGH);
  delay(delayTime);
  digitalWrite(ledPin, LOW);
  delay(delayTime);
}

Снова сохраняем и компилируем. Компилируется успешно, значит мы можем закоммитить изменения.

git commit -am "Added Variable Names"

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

Отличный код и работает хорошо, отправляем заказчику :slight_smile:

3 лайка

Шаг 4: Branches

Клиент тут же перезванивает: " - Там же должна быть кнопка, чтобы остановить мигание! Это же очевидно, разве об этом надо отдельно говорить? Ты должен был сам догадаться!"

Итак, возвращаемся к монитору.

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

Мы используем команду git checkout с флагом -b, который указывает гит создать новую ветку, и даем ей имя:

git checkout -b button

Теперь начнем добавлять кнопку… я тут что-то накидал, посмотрите что не так…

const int ledPin = 13;
const int delayTime = 500;
const int buttonPin = 7;

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);
}

void loop() {
  // Мигаем только если кнопка не нажата
  if (digitalRead(buttonPin) == HIGH) {
    digitalWrite(ledPin, HIGH);
    delay(delayTime);
    digitalWrite(ledPin, LOW);
    delay(delayTime);
  }
}

и оно даже компилируется… скорей коммит:

git commit -am "new button code"

(обратите внимание, что мы чаще всего используем эту команду - снова и снова.)

Мы тестируем код и он вроде работает - вроде как. Кнопка что-то не очень отзывчивая… Проблема в задержках.

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

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

2 лайка

Шаг 5: Возвращаемся назад к работающему коду

Я не стану начинать новую ветку для перевода кода на миллис от ветки кнопки. Хорошим тоном будет не смешивать разные изменения. Я хочу вернуться и создать новую ветку от основной ветки master, потому что это наш основной код. Поэтому сначала нужно выполнить chekout ветки мастер, а затем создать новую ветку.

Это шаг, на котором вы поймете, почему git — это круто. Пожалуйста, проделайте это с открытой Arduino IDE и посмотрите, что там произойдет. Код волшебным образом, автоматически и мгновенно вернется к старой версии из основной ветки.

Команда для извлечения ветки — это просто git checkout и имя ветки.

Но сначала надо проверить, что мы закоммитили все изменения. Имейте в виду, что вы не сможете сменить ветку, пока в ней есть незафиксированные изменения. Проверяем статус:

git status

и он рапортует, что все отлично, в текущей ветке “нечего фиксировать”:

On branch button
nothing to commit, working tree clean

Если бы это было не так, нам бы пришлось сначала закоммитить или спрятать (stash) изменения.

(b707 - последним я никогда не пользовался и не очень понимаю, как это работает).

Но раз статус сказал, что директория чистая - мы можем, наконец, извлечь ветку мастер:

git checkout master

и код в Ардуино ИДЕ, как волшебству, вернется к прежней версии:

const int ledPin = 13;
const int delayTime = 500; 

void setup() {
  pinMode(ledPin, OUTPUT);
}

void loop() {
  digitalWrite(ledPin, HIGH);
  delay(delayTime);
  digitalWrite(ledPin, LOW);
  delay(delayTime);
}

(b707 важно! - В ИДЕ версий 1.х никакого “волшебства” не происходит, ИДЕ не умеет отслеживать изменения в файлах, происходящие за пределами самой ИДЕ. Чтобы не попасть в довольно неприятную ситуацию, лучше закрывать окно ИДЕ перед выполнением команд Git, которые меняют содержимое проекта)

Но версия с кнопкой не сгинула. Гит ее просто спрятал внутри своего файла версий.

Снова создаем новую ветку, как мы это уже делали прежде:

git checkout -b BWoD

BWoD - BlinkWithoutOfDelay

и можем занятся внедрением миллис:

const int ledPin = 13;
const int delayTime = 500;

unsigned long previousMillis;
uint8_t ledState = LOW;

void setup() {
  pinMode(ledPin, OUTPUT);
}

void loop() {
  if (millis() - previousMillis >= delayTime) {
    ledState = 1 - ledState;
    digitalWrite(ledPin, ledState);
  }
}

код компилируется, поэтому я снова фиксируюсь:

git commit -am "change to BWoD"

Но… он не работает. Ага… вижу, мы с вами посадили баг. Нужно добавить previousMillis = millis(); после оператора условия.

Добавляем и проверяем. Теперь все Ок. Фиксируемся снова:

git commit -am "bugFix add update previousMillis"

проблема решена.

В следующей части мы выполним слияние этой ветки с основным кодом.

3 лайка

Шаг 6: Собираем изменения вместе

Итак, что мы имеем:
git3

у нас есть три разные версии нашего кода в трех разных ветвях Git. При этом это только один файл, а не папка, полная исходных текстов с разными именами. В этом красота Git. Однако у нас нет единого готового кода - есть главная ветка с кодом, использующим задержки, есть ветка button с тем же кодом и добавленной кнопкой и ветка BWoD с кодом «Блинк без делей», но без кнопки.

Помните, как я говорил, что у нас есть рабочий код только в основной ветке? Что ж, теперь код ветки BWoD тоже работает. Поэтому пришла пора слить ветку BWoD в ветку master.

Команда для этого — git merge. Прежде всего следует перейти в ветку мастер командой checkout.

Помните, при слиянии двух веток GIt должен находится в ветке, которая принимает изменения. Это не одно и то же и результат вливания ветки BWoD в мастер может отличатся от вливания мастер в BWoD.

Итак, сначала мы выполняем

git checkout master

а затем объединим с ней ветку BWoD.

git merge BWoD

Это обьединит все изменения. И опять же, вы можете сделать это с открытой IDE и наблюдать, как текст просто волшебным образом меняется на экране…

Пользователям Ардуино ИДЕ 1.х придется закрыть ИДЕ и войти в нее вновь, чтобы исходные файлы перезагрузились.

В консоли вы увидите примерно такой вывод Git:

Updating d12af3d..9ec2432
Fast-forward
 GitBlink.ino | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

И вот что стало с нашим деревом версий:
git4

Git пишет, что выполнил так называемый fast-forward.

Если вы сравните изменения в дереве с картинкой в начале этой части - вы можете заметить, что никакого слияния ветвей не потребовалось. Ветка мастер и так была частью ветви BWoD. Что сделал Гит - это “перемотал” (fast-forward) указатель ветки мастер на вершину ветви BWoD.

Естесственно, что при таком слиянии в основной ветке не было изменений, которые конфиктовали бы с изменениями в ветке BWoD. Так бывает не всегда. Как разрешать конфликты, будет рассказано в части 8.
Теперь в нашей основной ветке есть код Blink Without Delay. Также после успешного слияния автоматически выполняется фиксация, поэтому у нас есть чистое рабочее дерево для дальнейшей разработки.

При желании, вы можете удалить ветку BWoD. Она нам больше не нужна.

(b707 - я обычно оставляю все ветки, чтобы проще потом проследить историю)

Используйте флаг -d с именем ветки, чтобы удалить ветку.

git branch -d BWoD

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

3 лайка

Шаг 7: Обновление другой ветки

Можно было бы слить обновленную ветку мастер в ветку кнопки. Но интереснее перенести точку ответвления ветки button от основного ствола выше наших текущих изменений, так, будто мы ответвили ее только что. Заодно это позволит нам изучить новую команду - rebase.

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

git checkout button

Посмотрите на код в IDE. Что-то знакомое? Да это же версия скетча из шага 4!

const int ledPin = 13;
const int delayTime = 500;
const int buttonPin = 7;

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);
}

void loop() {
  // only run when button is not pressed
  if (digitalRead(buttonPin) == HIGH) {
    digitalWrite(ledPin, HIGH);
    delay(delayTime);
    digitalWrite(ledPin, LOW);
    delay(delayTime);
  }
}

Попробуем учесть в этом коде изменения из ветки мастер, для этого дадим команду rebase с именем ветки, на вершину которой мы хотим переместить ветвь button:

git rebase master

И у-у-пс… случилось что-то ужасное… Вот что мы видим в консоли:

Auto-merging GitBlink.ino
CONFLICT (content): Merge conflict in GitBlink.ino
error: could not apply 87e74c8... new button code
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply 87e74c8... new button code

Две ветви, которые мы пытались обьединить, имеют несовместимые изменения. Это называется “конфликт слияния” (merge conflict). Мы плохо спланировали работу со скетчем и изменили в нем одни и те же участки дважды в разных ветвях. Теперь Git не знает, как обьединить эти изменения. Ну что ж, пусть это послужит нам уроком . Хорошее правило - не работать с одними и теми же частями кода одновременно более чем в одной ветви.
Но что же делать с проектом? - Можно ли как-то все-таки обьединить ветви? - да, но нам придется приобрести опыт разрешения конфликтов.

3 лайка

Шаг 8: Разрешение конфликтов

Что же случилось с нашим кодом? Теперь в ИДЕ он выглядит так:

const int ledPin = 13;
const int delayTime = 500;
<<<<<<< HEAD

unsigned long previousMillis;
uint8_t ledState = LOW;
=======
const int buttonPin = 7;
>>>>>>> 87e74c8 (new button code)

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);
}

void loop() {
<<<<<<< HEAD
  if (millis() - previousMillis >= delayTime) {
    previousMillis = millis();
    ledState = 1 - ledState;
    digitalWrite(ledPin, ledState);
=======
  // only run when button is not pressed
  if (digitalRead(buttonPin) == HIGH) {
    digitalWrite(ledPin, HIGH);
    delay(delayTime);
    digitalWrite(ledPin, LOW);
    delay(delayTime);
>>>>>>> 87e74c8 (new button code)
  }
}

и уж точно не скомпилируется со всем этим мусором.

Разрешение конфликтов - это тот случай, где использование графического интерфейса НАМНОГО бы упростили то, что я собираюсь сделать. Но ради обучение проделаем это старым добрым способом.

Прежде всего разберемся с используемым синтаксисом. Каждый участок кода, где Гит не смог объединить изменения из двух ветвей, называется “конфликтом” и обозначен в тексте. Давайте посмотрим на первый конфликт:

<<<<<<< HEAD

unsigned long previousMillis;
uint8_t ledState = LOW;
=======
const int buttonPin = 7;
>>>>>>> 87e74c8 (new button code)

Строки <<<<<<< HEAD и >>>>>>> 87e74c8 (new button code) указывают границы конфликта. Они всегда идут парами, и вся работа будет выполняться между ними. В середине =======. Все, что расположено выше и обозначено HEAD - из ветки master. Все, что ниже - из ветки button. Конфликт означет, что git не знает, как вы хотите соединить их вместе.

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

unsigned long previousMillis;
uint8_t ledState = LOW;

const int buttonPin = 7;

Второй конфликт в loop():

void loop() {
<<<<<<< HEAD
  if (millis() - previousMillis >= delayTime) {
    previousMillis = millis();
    ledState = 1 - ledState;
    digitalWrite(ledPin, ledState);
=======
  // only run when button is not pressed
  if (digitalRead(buttonPin) == HIGH) {
    digitalWrite(ledPin, HIGH);
    delay(delayTime);
    digitalWrite(ledPin, LOW);
    delay(delayTime);
>>>>>>> 87e74c8 (new button code)
  }
}

Мы хотим сохранить кое-что в нижней части, строку кнопок, но нам нужна и верхняя часть в операторе if. Так что нам придется поработать и отредактировать это вручную, чтобы объединить их:

void loop() {
  // only run when button is not pressed
  if (digitalRead(buttonPin) == HIGH) {
    if (millis() - previousMillis >= delayTime) {
      previousMillis = millis();
      ledState = 1 - ledState;
      digitalWrite(ledPin, ledState);
    }
  }
}

Полученный код уже компилируется и может быть “закоммичен”.
Спросим git status, что нам делать дальше:

interactive rebase in progress; onto aea6e98
Last command done (1 command done):
   pick 87e74c8 new button code
No commands remaining.
You are currently rebasing branch 'button' on 'aea6e98'.
  (fix conflicts and then run "git rebase --continue")
  (use "git rebase --skip" to skip this patch)
  (use "git rebase --abort" to check out the original branch)

Unmerged paths:
  (use "git restore --staged <file>..." to unstage)
  (use "git add <file>..." to mark resolution)
	both modified:   GitBlink.ino

no changes added to commit (use "git add" and/or "git commit -a")

Обратите внимание, что Git предлагает несколько вариантов на выбор, что делать.

В нашем случае мы разрешили конфликты, код работает, поэтому мы можем выполнить фиксацию и дать Git продолжить(завершить) rebase.
Мы используем нашу старую знакомую команду:

git commit -am "rebase to BWoD code"

а потом

git rebase --continue

git6

Ветка button перемещена и изменения, касающиеся смены delay() на millis() в ней учтены. У нас снова чистое дерево Git и мы можем либо продолжить разработку, добавив какие-то новые функции, либо занятся чем-то другим :slight_smile:

3 лайка

Приложение А: Что такое индексация изменений (stage changes) и зачем оно нужно

перевод из StackOverflow

Вопрос

Я только осваиваю системы контроля версий. Я понимаю, что «фиксация»(коммит) — это, по сути, создание резервной копии при обновлении новой «текущей» версии проекта.

Чего я не понимаю, так это того, что такое staging с практической точки зрения. Является ли staging чем-то, что существует только номинально, например по традиции, или оно служит какой-то цели? Когда вы совершаете коммит, он все равно будет учитывать все, верно?

Ответ

Когда вы выполняете коммит, он фиксирует только изменения в индексе («staged» файлы). У этого есть множество применений, но наиболее очевидным является разбиение рабочих изменений на более мелкие, автономные части.
Допустим, при работе над кодом новой функции в файле function.cpp вы заметили ошибку в основном коде в main.cpp. Вы можете зафиксировать только это исправление, попросив git добавить в индекс только этот файл (или даже добавить только часть файла опцией git add -p (b707 - не спрашивайте что это, не слышал о таком :)), а когда закончите редактировать функцию - зафиксировать добавления отдельным коммитом.
Теперь, если с функцией что-то пойдет не так - вы сможете отменить ее добавление, не отменяя исправление бага в main.cpp, который вы исправили отдельным коммитом.
Если вы используете git commit -a, вы просто принудительно добавляете все прямо перед фиксацией.

Вы также можете использовать staged файлы как промежуточную рабочую копию с помощью опции --cached для многих команд. Например, git diff --cached покажет вам, чем staged changes отличаются от HEAD(последнего сделанного коммита), чтобы вы могли видеть, что вы собираетесь зафиксировать, не смешивая это с другими изменениями в проекте.

b707 - небольшое добавление
Точно также как в программировании существуют “правила хорошего тона” при написании программ - например использовать “говорящие” имена переменных и не использовать “магичесие числа” - в Git тоже есть свод таких правил. Одно из них гласит, что каждая фиксация должна содержать только правки, связанные общей логикой. Например, добавление нового метода - одна правка, устранение бага - другая, удаление комментов третья. Думаю что ответ выше обьясняет, зачем это нужно.

2 лайка

классное руководсво, но я неоднократно слышал в руководствак что использовать rebase плохая практика и ее лучше избегать.
так же могу порекомендовать сайт по практике гита : https://learngitbranching.js.org/ (англ)

1 лайк

Вероятно да. Но слова из песни не выкинешь, автор зачем-то счел необходимым обьяснить разрешение конфликтов именно на примере rebase

у меня на русском