Сброс команды в Git - PullRequest
       27

Сброс команды в Git

2 голосов
/ 07 марта 2019

Я знаю, что команды сброса содержат 3 параметра -

  1. Hard - которые изменяют файлы в нашем рабочем каталоге на конкретный идентификатор фиксации

  2. смешанный (по умолчанию) - который удаляет и снимает файлы

  3. soft - который только удаляет файлы

я знаю, uncommomit - перемещает ГОЛОВУ исвязанный указатель ветви и фактически не изменяет дерево коммитов, но я не уверен, что это значит?Какой смысл двигать головой?

1 Ответ

1 голос
/ 07 марта 2019

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

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

В более простой форме git reset записывает один, два или три элемента в вашем Git-хранилище. Чтобы понять это , вы должны сначала понять, как работают коммиты и ветки, функция хэш-идентификатора Git и роли HEAD, index и work. -tree . Давайте начнем с хеш-идентификаторов.

Хеш-идентификаторы

В Git идентификатор хеша выглядит так: b5101f929789889c2e536d915698f58d5c5c6b7a. Это большая уродливая строка букв и цифр. Но на самом деле это контрольная сумма , в частности криптографическая, для некоторых данных. Это означает, что:

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

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

На практике это означает, что любые два Gits могут собраться вместе и вести сокращенный разговор: У вас есть ID X? Как насчет Y и Z? Если в одном Git отсутствует один из этих идентификаторов, другой может дать ему данные, и теперь у него есть и идентификатор хеша, и данные. Если у обоих Gits есть все идентификаторы, у них есть все данные. Таким образом, два Git могут очень быстро синхронизироваться друг с другом, так как отправитель дает получателю все, что есть у отправителя, а у получателя нет.

Это уже несколько полезно само по себе, но когда мы объединяем его с коммитами , оно становится чрезвычайно полезным.

Фиксирует

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

Поскольку это данные только для чтения , поскольку их нельзя изменить, мы можем вычислить хэш-идентификатор этого коммита. Этот коммит теперь навсегда этот коммит с этим хеш-идентификатором. Ни одна из его данных не может измениться: у нас есть хеш-идентификатор, который уникально идентифицирует эти данные, и никакие другие данные не могут использовать этот хеш-идентификатор для чего-либо. (Об очевидном возражении против этого см. Как недавно обнаруженное столкновение SHA-1 влияет на Git? )

Но, потому что этот коммит содержит хеш-идентификатор его родительского коммита как часть его данных, все что нам нужно сделать, это убедиться, что у нас есть каждый коммит в этой цепочке , Скажем, например, у нас есть коммит с хэш-идентификатором H:

                          <-H

Одна из вещей, которая в H, - это хэш-идентификатор родительского коммита. Давайте назовем этого родителя G. Таким образом, мы гарантируем, что у нас есть , что также фиксирует, и мы говорим, что H указывает на G:

                      <-G <-H

Что ж, в G есть хеш-идентификатор его родительского элемента, F. Таким образом, мы удостоверимся, что у нас тоже есть F, и у него есть другой хэш-идентификатор E, который имеет хэш-идентификатор D, и так далее, вплоть до самого первого коммита, который мы когда-либо делали в репозитории, чей хеш-идентификатор мы называем A:

A <-B <-C <-D <-E <-F <-G <-H

Поскольку A является первым коммитом, у него нет родителя, и мы остановимся здесь.

Эти стрелки запекаются в коммитах: H всегда указывает на G, потому что идентификатор хеша G запекается в H и не может быть изменен и, конечно, H само по себе также заморожено, и его хэш-идентификатор также никогда не изменится. Таким образом, для рисования мы можем просто нарисовать их как соединительные линии Просто помните, что сама стрелка выходит из коммита child , возвращаясь к parent . Когда мы сделали A, мы не знали, каким будет хеш-идентификатор B, поэтому A буквально не может указывать на B; но когда мы сделали B, мы знали, что такое A, поэтому B указывает на A.

Это означает, что дано:

A--B--C--D--E--F--G--H

все внутренние стрелки идут строго назад . У нас есть , чтобы начать с H и работать в обратном направлении. Если мы начнем, скажем, с D, мы можем вернуться назад к C, затем к B и A, но буквально не можем перейти к E.

Филиалы, названия филиалов и HEAD

Вся ветвь name в Git is - это читаемое человеком имя, которое содержит один-единственный хэш-идентификатор. Идентификатор хэша, который содержит имя, является идентификатором хэша последнего коммита в этой ветви!

Таким образом, с приведенным выше графиком - коммиты A - H - мы можем иметь одно или несколько имен ветвей, указывающих на любой из восьми коммитов. Давайте нарисуем некоторые в:

A--B--C--D--E--F   <-- master
                \
                 G--H   <-- develop

Здесь имя master представляет коммит F, удерживая фактический хэш-идентификатор F. Нам не нужно самим запоминать этот хэш-идентификатор: мы просто говорим master. имя develop запоминает хэш-идентификатор H.

Начиная с H, мы можем работать в обратном направлении через каждый коммит. Начиная с F, мы можем работать в обратном направлении через большинство коммитов, но мы не можем видеть H и G с F, потому что для этого требуется идти вперед , что невозможно. Нам отчаянно нужно имя develop, чтобы мы могли найти H, из которого мы находим G. После этого, пока имя master все еще существует, мы можем найти F и более ранние коммиты.

Коммиты A - H находятся в Git на ветви develop, а A - F - master.

Мы добавляем новое имя, также указывающее на F, выполнив:

git checkout master
git checkout -b feature

Теперь у нас есть этот рисунок:

A--B--C--D--E--F   <-- master, feature (HEAD)
                \
                 G--H   <-- develop

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

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

Если мытеперь сделайте новый коммит, он получит новый и уникальный хэш-идентификатор.Давайте назовем это I.Мы рассмотрим процесс, с помощью которого мы сделаем этот новый коммит за мгновение, но сейчас давайте просто скажем «мы сделали это», и он теперь существует.График теперь выглядит следующим образом:

                 I   <-- feature (HEAD)
                /
A--B--C--D--E--F   <-- master
                \
                 G--H   <-- develop

То есть наш новый коммит I указывает на F, а имя feature теперь указывает на новый коммит II мы можем найти F;из F мы можем найти E и так далее.Мы не можем достичь G или H таким образом.Коммиты G и H являются только на master.Фиксация I - это только в feature.Коммиты A - F включены в все три ветви.

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

Поздравляем!Теперь вы понимаете ветки Git.A branch - это серия коммитов , обычно начиная с end и , работающих в обратном направлении .Вы выбираете, как далеко назад вы хотите пойти - вы можете продолжать идти до корневого коммита , то есть без родительского.

Ветвь идентифицируется имя ветви , которое содержит хэш-идентификатор последнего коммита, который является частью ветви.Обратите внимание, что когда люди произносят слово branch , они часто означают название ветви , а не строка коммитов .Таким образом, слово ответвление неоднозначно в реальной жизни, и вам нужен некоторый контекст, чтобы выяснить, означает ли кто-то, что совершает , имя или и то, и другое.См. Также Что именно мы подразумеваем под «ветвью»?

Между тем, специальное имя HEAD, написанное во всех таких прописных буквах, обычно прикрепляется к одному имени ветви.Вы можете прикрепить его к имени ветви, используя для этого git checkout, или отсоединить от имени ветви, также используя git checkout.Мы не будем входить в этот режим отсоединенного заголовка, за исключением того, что в этом режиме имя HEAD просто содержит фактический хэш-идентификатор некоторого коммита.Однако при обычном использовании роль HEAD заключается в том, чтобы помнить, какое имя ветви мы используем .

Обратите внимание, что когда вы используете git checkout с именем ветви, Git присоединитHEAD на название филиала.Коммит, который находит имя - например, F для master - теперь ваш текущий коммит .Итак, чтобы найти текущее имя ветки , мы спрашиваем Git к какому имени HEAD присоединено , а чтобы найти текущий коммит , мы спрашиваем Git какой коммит делает HEAD через какое-то имя ветви? Имя HEAD обрабатывает обе этих операций, в зависимости от , какой вопрос мы задаем .Мы спрашиваем «что такое имя ветки» или «что такое хеш коммита» и получаем соответствующий ответ.

Индекс и рабочее дерево, или как мы строим и работаем с коммитами

Пришло время взглянуть на роли индекса и рабочего дерева в работе с Git.

В Git каждый репозиторий (кроме --bare one) имеет один index и одно рабочее дерево для всех замороженных коммитов и имен веток.Как вы теперь знаете, коммиты хранят снимки всех ваших файлов.Но материал в коммите - метаданные о самом коммите, а также копии имен и содержимого всех файлов - все эти вещи заморожены навсегда .Ничто из этого не может быть изменено, ни один бит.Это отлично подходит для архивирования и изучения прошлого, но не позволит нам выполнить какую-либо работу.

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

Опять же, это отлично подходит для архивирования, но чтобы выполнить работу, нам нужен способ разморозить замороженный коммит. Нам нужно извлечь замороженное содержимое из замороженных имен файлов. Нам нужно разморозить и распаковать замороженные файлы Git-ified в место, где мы можем работать с ними и вместе с ними. Это место - рабочее дерево (или рабочее дерево или рабочий каталог или некоторая комбинация таких имен).

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

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

Индекс показывает, как Git отслеживает ваше рабочее дерево. Фактически наличие файла в индексе - это то, что делает файл отслеженным . Если в коммите есть файл типа README.md, Git копирует его в индекс, а затем копирует из индекса в рабочее дерево. Таким образом, README.md теперь находится в во всех трех местах и, поскольку он находится в индексе, он отслеживается.

Файлы в индексе находятся в специальной сжатой форме Git-only. Они готовы заморозить в новый коммит. Git требует, чтобы это было верно все время . Поэтому, если вы измените файл в своем рабочем дереве, Git заставит вас использовать git add в копировать файл обратно в индекс , чтобы обновить копию индекса. Это повторно сжимает и Git-ifies содержимое файла, так что он готов к заморозке.

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

Когда git checkout сначала проверяет какой-то коммит, чтобы сделать текущий коммит, Git копирует файл в индекс, так что предложенный new коммит имеет тот же файл с тем же содержанием, что и текущий коммит. Затем вы настраиваете файл столько раз, сколько хотите в рабочем дереве, а затем используете git add, чтобы скопировать его обратно, чтобы обновить предложенный коммит.

Этот шаг копирования - подготовка файла . Если у предложенного коммита еще нет обновленного файла, файл не подготовлен , потому что, если вы сейчас запустите git commit, то будет использоваться старая копия файла тот, который вышел из коммита. После того, как вы скопировали файл из рабочего дерева в область index / staging, предлагаемый коммит теперь имеет копию new .

ThСледовательно, три активных копий каждого файла! В текущем коммите есть замороженный; в индексе есть вторая копия; и есть третья копия в рабочем дереве. Вы должны использовать что-то вроде git show или другую команду Git, чтобы увидеть копии только для Git:

git show HEAD:README.md     # view the frozen current-commit copy
git show :README.md         # view the index copy

Конечно, вы можете просто использовать обычные компьютерные команды, чтобы увидеть обычную копию рабочего дерева, README.md. Но поскольку составляет три копии, все три копии могут быть разными. Обычно, по крайней мере, два из них совпадают, потому что индекс начинается так же, как и зафиксированный коммит, а затем git add делает его таким же, как и у рабочего дерева. Но все они могут быть разными.

В любом случае, когда мы сделали новый коммит I на feature, way мы сделали это:

git checkout master
git checkout -b feature
... do some work ...
... run `git add` on our changed files ...
git commit

Шаг git checkout master прикрепил наш HEAD к имени master и извлек коммит F в наш индекс и рабочее дерево. Шаг git checkout -b feature создал новое имя feature, указывающее на фиксацию F, и прикрепил HEAD к этому новому имени. Наш индекс и рабочее дерево все еще соответствуют текущему коммиту F.

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

Новый коммит с его замороженным деревом файлов и замороженными метаданными, как обычно, указывает на существующий коммит F. У него новый хэш-идентификатор - теперь это наш коммит I - и Git записал этот новый хэш-идентификатор в текущее имя , используя вопрос «какое имя ветви имеет HEAD». Так что теперь имя feature указывает на новый коммит I.

Теперь, когда мы понимаем все вышесказанное, теперь мы можем объяснить git reset

Как я упоминал выше, команда git reset в трех основных формах - git reset --soft, git reset --mixed и git reset --hard - записывает в одну, две или три вещи.

Три вещи, которые git reset пишет или может писать - это:

  1. идентификатор хеша, хранящийся в имени текущей ветви;
  2. указатель; и
  3. дерево работы.

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

Смешанный вид сброса записывает в # 1 и # 2, а затем останавливается. То есть он записывает хэш-идентификатор в имя ветви, а затем записывает некоторые данные в индекс. Однако дерево работы не меняется.

Жесткий вид сброса пишет в # 1, # 2 и # 3. Таким образом, он записывает хэш-идентификатор в имя ветви, затем записывает некоторые данные в индекс, а затем записывает также все рабочее дерево.

Итак, то, что мы делаем с жесткими, смешанными или мягкими флагами, говорит git reset , когда останавливаться . всегда будет писать в текущую ветку, используя имя HEAD, чтобы выяснить , что это имя ветви. Он может записать в индекс, и если он это сделает, он может записать материал по всему рабочему дереву.

Но нам также нужно посмотреть , что git reset пишет для каждого из них, и вот тут все становится сложным и полезным.

Вы сообщаете git reset, какой хэш-идентификатор следует хранить в имени филиала

SYNOPSIS раздел git reset документация говорит, частично:

<em>git reset</em> [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>]

Мы идемигнорировать --merge и --keep здесь и флаг -N.-q или "тихий" флаг просто закрывает git reset.Ключевым моментом здесь является последняя часть, необязательный commit .Это необязательно , но если мы его опускаем, Git предполагает, что мы имеем в виду HEAD .

Что Git делает с этим последним аргументом, так это находит идентификатор хеша коммита.Так, если мы скажем, например:

git reset --hard b5101f929789889c2e536d915698f58d5c5c6b7a

, мы дали Git хэш-идентификатор, и Git просто проверяет, что он действителен, и называет коммит.Или мы можем сказать:

git reset --hard master

Здесь Git берет имя master и переводит его в хэш-идентификатор.В нашем примере репозитория выше, это будет любой хеш-идентификатор commit F.Мы также можем сказать:

git reset --hard HEAD~1

, который отсчитывает один коммит от HEAD;в нашем примере репозитория, который может начинаться с I и переходить на один шаг назад к F, и, следовательно, иметь то же значение, что и master здесь.

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

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

Теперьчто у нас есть хеш-идентификатор, Git записывает его в текущую ветвь

Как только git reset имеет хеш-идентификатор, он обновляет текущую ветку - ту, к которой присоединена HEAD- записав хеш-идентификатор, который вы дали, в текущее имя.Так что, если в нашем примере мы находимся на ветке feature, и вы запускаете:

git reset --soft master

Git запишет хэш-идентификатор commit F в имя feature:

                 I   ???
                /
A--B--C--D--E--F   <-- master,  feature (HEAD)
                \
                 G--H   <-- develop

Обратите внимание, что коммит I все еще там .Просто мы больше не можем его найти. Без имени мы должны найти I, перейдя от F.Мы не можем идти вперед;Git этого не делает.(Если бы мы пошли вперёд, разве мы не пришли бы к G? Ну, может быть. Это вопрос для другого упражнения, возможно, для другого дня.) Если вы * сохранили хеш-код I где-нибудь, вы можетеТеперь запустите:

git reset --soft <hash-ID-of-I>

чтобы вернуть вещи обратно.Если нет, то есть несколько хитростей для поиска хеш-идентификатора I.Некоторые из них даже довольно просты.Один из них такой:

git reset --soft feature@{1}

, потому что Git автоматически сохраняет старые идентификаторы ветки в reflog ветки.(Остальные способы поиска I мы оставим для других вопросов.)

Более мощные сбросы

Теперь, предположим, вместо git reset --soft master, вы просто запустите:

git reset --soft

с feature, все еще указывающим на I?Затем Git прочитает HEAD, чтобы найти хеш-код I, и в качестве операции сброса запишите этот хэш-идентификатор коммита обратно в feature.Мы закончим в точности там, где начали:

                 I   <-- feature (HEAD)
                /
A--B--C--D--E--F   <-- master
                \
                 G--H   <-- develop

Git прочитал хэш-идентификатор I из feature, затем записал это обратно в feature, оставив feature без изменений.Так что без спецификатора хеш-идентификатора , git reset --soft не имеет никакого эффекта.

А как насчет --mixed?Здесь Git будет писать в index .Помните, индекс - это предлагаемый следующий коммит: он содержит копию каждого файла, который мы, возможно, обновили.git reset --mixed делает то, что после переустанавливает текущую ветку с использованием хеш-идентификатора, копирует файлы из выбранного нами коммита в индекс .

Итак, если мы на коммите I вот так, и мы используем:

git reset --mixed HEAD

мы говорим Git: Скопируйте идентификатор хеша feature в feature, оставив feature без изменений;затем, после этого, скопируйте содержимое commit I в индекс. Первый шаг на самом деле не изменяет ничего, но второй шаг *1730* имеетэффект "отмены" любого git add, который мы запустили.

Другими словами, оставив feature без изменений, но повторно установив index , мы отменили наши git add s.

Обратите внимание, что если бы мы использовали git reset --mixed master, мы бы feature указали на F (не I) и , чтобы обновить индекс для соответствия фиксации F(не I)!Так что git reset довольно мощный.Все, что мы поставили, ушло, заменено тем, что в коммите.Конечно, если мы поставили копирование из рабочего дерева , оно останется в рабочем дереве.

Наконец, мы можем использовать git reset --hard.Это делает те же самые первые два шага, что и раньше.То есть сначала он записывает новый идентификатор хэша в текущее имя ветви, которое, если мы не сказали, какой из них использовать, является старым идентификатором хэша и оставляет имя ветви без изменений.Затем он использует любую фиксацию, которую имя ветви теперь идентифицирует , чтобы переустановить индекс.Все, что мы поставили, ушло.Наконец, он записывает в рабочее дерево . 1

Конечно, это самый мощный сброс, потому что он забивает все, что мы изменили в работе-дерево ... и это нигде не сохранено в Git .В дереве работы есть наша работа.Если мы потеряем это, это просто ушло .В некотором смысле, git reset --hard является наиболее опасным случаем.

Но помните, как мы потеряли коммит I, когда мы небрежно сбрасывали, даже с --soft, и не спасли идентификатор хэша где-то первым?Так что даже мягкий сброс опасен.К счастью, Git имеет тенденцию сохранять хеш-идентификаторы во многих местах, но это оказывается почти такой же проблемой, как и сохранение их вообще.Если вам нужно найти потерянный хеш-идентификатор, вы можете посмотреть в журналах.Но там часто сотни или тысячи хеш-идентификаторов , и все они выглядят совершенно случайными.Найти правильного одного, иголку в стоге сена, может быть ужасно утомительно.

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


1 Я ухожу отсюда что git reset --hard пишет в рабочее дерево.Это потому, что эта часть немного сложна.Технически любопытно см. документацию git read-tree , но подытожим: пока Git обновляет индекс, индекс сообщает Git, какие файлы он должен принимать в рабочем дереве. потому что они в индексе.Это файлы, которые Git может и должен ударить.Другими словами, неотслеживаемые файлы в основном остаются нетронутыми.Отслеживаемые файлы заменяются их новыми отслеженными аналогами из коммита, в который вы сбрасываете данные.Но здесь есть несколько угловых случаев: предположим, что файл X отслеживается в старом коммите и вообще не в новом коммите.Затем Git должен удалить X из рабочего дерева.Аналогично, предположим, что файл Y не отслеживается в старом коммите, но равен в новом.Тогда Git должен создать Y в рабочем дереве - но там может быть уже неотслеживаемый файл Y;должен Git клоббер это?(Обычно Git этого не делает, но иногда запись .gitignore дает Git разрешение на копирование файла Y.)

...