Вместо того, чтобы сразу закрывать это как дубликат Оформить другую ветку, когда в текущей ветке есть незафиксированные изменения , давайте попробуем немного другой подход.
... Я создал новую ветку из другой ветви, например, ветку B из ветви A.
То есть вы запустили:
git checkout branch-a
git checkout -b branch-b
или:
git checkout -b branch-b branch-a
или одна из многих других возможных команд.
Затем я внес много изменений в мой код внутри ветви B ...
Воткорень проблемы: вы внесли изменения в ваше рабочее дерево . Вы не изменили любую ветку . Ветвь B по-прежнему точно такая же, как и ветка A. У вас есть изменения, но они вообще не находятся ни в одной ветви. Они незафиксированы изменения.
ХитростьДело в том, что Git мало заботится о ветке names . Git заботится о коммитах .
Каждый коммит имеет большой уродливый хеш-идентификатор, такой как 08da6496b61341ec45eac36afcc8f94242763468
. Этот хэш-идентификатор, по сути, является истинным именем коммита. Все остальные имена - это просто способы создания хеш-идентификатора.
Сам коммит хранит вещи. Как только вы делаете коммит, он сохраняет снимок всех файлов, которые вы зафиксировали. Этот снимок никогда не может быть изменен - ни одного бита. Идентификатор хэша, который кажется случайным, на самом деле представляет собой криптографическую контрольную сумму всего в коммите, включая сохраненный снимок (вместе с другими материалами). Так что, если бы вы были , чтобы каким-то образом что-то изменить, у вас был бы новый и другой коммит с новым и другим большим уродливым хеш-идентификатором. Существующий коммит все еще будет там, с его существующим хеш-идентификатором.
Git реально , действительно заботится об этих коммитах. Git постарается никогда не потерять ни одного из них. Даже если вы сделаете его по ошибке, например, включите пароль в файл или гигантский файл, который никогда не должен был быть зафиксирован, получить избавление от него трудно . 1 (Старайтесь не совершать подобные вещи случайно.)
Ветвь name , однако, это просто имя. Все, что он делает, это держит один хэш-идентификатор. Имя типа branch-a
или branch-b
или master
- это способ запоминать большой некрасивый хэш-идентификатор, поскольку в противном случае его слишком сложно запомнить.
Когда вы работаете с коммитамив Git есть один большой камень преткновения: файлы, хранящиеся в коммите, сжаты и заморожены. Это особенность: поскольку файл внутри коммита не может быть изменен, будущий коммит может просто повторно использовать файл. Таким образом, вы можете сделать тысячу коммитов с большим файлом в них, и если большой файл всегда один и тот же, то на самом деле есть только одна копия большого файла.
Но это также означает, что для работыс файлами Git должен извлечь их из коммита. Вот что такое ваше рабочее дерево . (У рабочего дерева есть несколько вариантов того, как его назвать, включая рабочий каталог или рабочее дерево; все они очень похожи здесь.) Здесь вы можете увидеть и работать с ним. ваши файлы.
Файлы в вашем рабочем дереве не являются коммитом. Их изменение не влияет на любой существующий коммит. Таким образом, вы можете изменить их так, как вам нравится, и ничего не произошло в Git . Вещи произошли только в вашем рабочем дереве, которое сейчас просто для того, чтобы вы могли возиться с тем, как вам нравится.
Когда вы собираетесь сделать новый коммит, есть еще одна хитрость,Git не делает новых коммитов из вашего рабочего дерева! Это своеобразно - большинство других систем контроля версий do делают новые коммиты из вашего рабочего дерева. Но Git отличается: он делает новые коммиты из чего-то, что он вызывает, по-разному, index или промежуточная область , или - редко в наши дни - кеш .
чтИндекс начинает содержать копии всех файлов с коммита , выбранного вами при git checkout
. 2 . Вы должны скопировать все обновленные файлы обратно в индекс, использующий git add
, для получения обновленных версий для использования в следующем коммите.
Следовательно, лучше всего описать эту вещь с тремя именами - индексом, областью подготовки и кэшем -как ваш предложенный следующий коммит. Когда вы запускаете git commit
, Git замораживает все, что находится в индексе, в новый коммит.
Но сейчас оба имени, branch-a
и branch-b
, называют одинаковыми совершить. Поэтому, когда вы делаете:
git checkout branch-a
Git проверяет фактический хэш-идентификатор и видит, что это такой же коммит. Ничего не нужно делать, поэтому Git просто обновляет свой специальный файл с именем HEAD
, чтобы вставить в него имя branch-a
. 3 Вы не изменились commits , но теперь вына branch-a
. Выполните:
git checkout branch-b
и вы все еще не изменили коммиты, но теперь HEAD
содержит branch-b
, так что вы находитесь на branch-b
.
Как только вы git add
ваши файлы и затем git commit
, у вас будет новый коммит с новым большим уродливым хеш-идентификатором. Git сохранит хеш-идентификатор нового коммита в любом имени в HEAD
, а сейчас Git действительно серьезно отнесется ко всем этим файлам, потому что сейчасони являются частью коммита.
1 Это не невозможно, просто сложно.
2 Технически, что в индексе естьна самом деле не копирует зафиксированных файлов замороженного формата, а скорее ссылается на зафиксированных файлов фиксированного формата. Поскольку они не могут быть изменены, это различие без разницы, с вашей собственной точки зрения. Индекс занимает меньше места, но не влияет на то, как вы используете индекс.
3 Этот специальный файл обычно представляет собой просто файл с именем .git/HEAD
,Это должно быть написано в верхнем регистре, как это, даже если вы находитесь в системе, где head
во всех строчных буквах работает, потому что время от времени 4 строчные head
относится к неверный файл. В Git есть несколько строковых сравнений, и он использует правильный специальный файл, если вы его пишете HEAD
.
4 Сегодня время от времени случается при использовании git worktree add
. Кто знает, когда это может произойти, в будущем.