Что такое команда `git restore` и в чем разница между` git restore` и `git reset`?

Когда я хочу отключить поэтапный файл, все мои руководства по Git показывают что-то вроде:

$ git add *
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    renamed:    README.md -> README
    modified:   CONTRIBUTING.md

Эта подсказка говорит нам использовать git reset для удаления подготовленного файла.

Но вместо этого в моем терминале я вижу:

git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
    renamed:    cat.js -> catcat.js
    renamed:    tolendo.gogo -> tolendo.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)
    readme (copy).md
    tolendo (copy).txt
    zing (copy).html

Мой терминал говорит мне использовать git restore --stagedно учебники, а также веб-сайт Git, говорят мне использоватьgit reset HEAD.

Я понятия не имею о новом restoreкоманда. Я попытался найти в Google разницу междуgit reset а также git restore но ничего не подходило к моему вопросу.

Можешь мне помочь?

Большое спасибо!

5 ответов

Решение

Я представил git restore(который по-прежнему помечен как "экспериментальный") в статье " Как сбросить все файлы из рабочего каталога, но не из промежуточной области? " с недавним Git 2.23 (август 2019 г.).

Это помогает отделить git checkout на две команды:

  • один для файлов ( git restore), который может покрывать git reset случаи.
  • один для филиалов ( git switch, как показано в разделе " Смущает git checkout"), который имеет дело только с ветками, а не с файлами.

Как указано в документации для сброса, восстановления и возврата:

Есть три команды с похожими названиями: git reset, git restore а также git revert.

  • git-revert о создании нового коммита, который отменяет изменения, сделанные другими коммитами.
  • git-restoreкасается восстановления файлов в рабочем дереве либо из индекса, либо из другого коммита.
    Эта команда не обновляет вашу ветку.
    Команду также можно использовать для восстановления файлов в индексе из другой фиксации.
  • git-resetкасается обновления вашей ветки, перемещения подсказки для добавления или удаления коммитов из ветки. Эта операция изменяет историю коммитов.
    git reset также можно использовать для восстановления индекса, перекрывая git restore.

Так:

Чтобы восстановить файл в индексе, чтобы он соответствовал версии в HEAD (это то же самое, что использовать git-reset)

git restore --staged hello.c

или вы можете восстановить как индекс, так и рабочее дерево (это то же самое, что использовать git-checkout)

git restore --source=HEAD --staged --worktree hello.c

или краткая форма, более практичная, но менее читаемая:

git restore -s@ -SW hello.c

С Git 2.25.1 (февраль 2020 г.) "git restore --staged"некорректно обновлял структуру дерева кэша, что приводило к последующему написанию ложных деревьев, что было исправлено.

См. Обсуждение.

См. Commit e701bab (8 января 2020 г.) Джефф Кинг (peff).
(Слияние Junio ​​C Hamano -gitster- в коммите 09e393d, 22 января 2020 г.)

restore: сделать недействительным дерево кэша при удалении записей с --staged

Автор отчета: Торстен Кра.
Подпись: Джефф Кинг.

Когда " git restore --staged "удаляет путь из индекса, он отмечает запись CE_REMOVE,но мы не делаем ничего, чтобы сделать дерево кэша недействительным.
В неэтапном случае мы попадаем вcheckout_worktree(), который вызывает remove_marked_cache_entries(). Это фактически удаляет записи из индекса, а также делает недействительным дерево кэша и неотслеживаемый кеш.

Но с --stagedмы никогда не звоним checkout_worktree(), а CE_REMOVEзаписи остаются. Интересно, что они отбрасываются, когда мы записываем индекс, но это означает, что результирующий индекс несовместим: его дерево кэша не будет соответствовать фактическим записям и выполняется "git commit"сразу после этого создаст неправильное дерево.

Мы можем решить эту проблему, позвонив remove_marked_cache_entries()перед тем, как написать индекс. Обратите внимание, что мы не можем просто поднять его изcheckout_worktree(); эта функция должна перебиратьCE_REMOVE записей (чтобы удалить соответствующие файлы рабочего дерева) перед их удалением.

Одно любопытство по поводу теста: без этого патча он фактически запускает BUG() при запуске git-restore:

BUG: cache-tree.c:810: new1 with flags 0x4420000 should not be in cache-tree

Но в исходном отчете о проблеме, в котором использовался аналогичный рецепт, git restore фактически создает фиктивный индекс (и фиксация создается с неправильным деревом). Я не уверен, почему тест здесь ведет себя иначе, чем мой тест вне набора, но то, что здесь, должно улавливать любой симптом (и исправление исправляет оба случая).


С Git 2.27 (второй квартал 2020 г.) "git restore --staged --worktree" теперь по умолчанию извлекает содержимое из" HEAD", а не ошибается.

См. Коммит 088018e (5 мая 2020 г.) Эрика Саншайна (sunshineco).
(Слияние Junio ​​C Hamano -gitster- в коммите 4c2941a, 08 мая 2020 г.)

restore: по умолчанию HEAD при объединении --staged и --worktree

Подписано: Эрик Саншайн
Рецензент: Тейлор Блау

По умолчанию файлы восстанавливаются из индекса для --worktree, и из HEAD для --staged.

когда --worktree а также --staged объединены, --source должен быть указан для устранения неоднозначности источника восстановления, что затрудняет восстановление файла как в рабочем дереве, так и в индексе.

(По недосмотру --source требование, хотя и задокументировано, на самом деле не выполняется.)

Однако HEAD также является разумным значением по умолчанию для --worktree в сочетании с --staged, поэтому сделайте это значение по умолчанию в любое время --staged используется (в сочетании с --worktree или не).

Итак, теперь это работает:

git restore --staged --worktree
git restore -SW

Чтобы добавить к ответу VonC и отобразить на картинке все соответствующие команды в алфавитном порядке.

Я добавлю еще одного, тоже с неверным названием.

С точки зрения конечного пользователя

Все, что вам нужно, это, и. Эти команды всегда были в Git.

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

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

С исторической точки зрения

является новым , впервые появившись в августе 2019 года в Git 2.23. очень старый, он был в Git все время, еще до 2005 года. Обе команды могут уничтожать несохраненную работу.

Эта команда также является новой, введенной вместе с Git 2.23. Реализует «безопасную половину»; реализует «небезопасную половину».

Когда бы вы использовали какую команду?

Это самая сложная часть, и чтобы по-настоящему ее понять, нам нужно знать следующие моменты:

  • Git - это действительно все о коммитах . Коммиты сохраняются в репозитории Git. В git push

и git fetchКоманды передают коммиты - все коммиты, как договор "все или ничего" 1 - в другой Git. У вас либо есть вся фиксация, либо ее нет. Другие команды, например git merge или же git rebase, все работают с локальными коммитами. В pull команда запускается fetch (чтобы получить коммиты), а затем вторая команда для работы с коммитами, когда они локальны.
  • Новые коммиты добавляются в репозиторий . Вы почти никогда не удаляете коммит из репозитория. Только одна из пяти перечисленных здесь команд - проверка, сброс, восстановление, возврат и переключение - способна удалять фиксации. 2

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

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

  • Имя ветки содержит хэш-идентификатор одной фиксации. Это заставляет имя ветки находить этот коммит, что, в свою очередь, означает две вещи:

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

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

                  o--o---o   <-- feature-top
           /        \
    o--o--o--o--...--o---o--o   <-- main
        \               /
         o--o--...--o--o   <-- feature-hull
    

    который, как видите, является хранилищем лодок. 😀 Есть три филиала. Филиал магистральный держит каждой фиксации , включая все коммиты в верхнем ряду и нижнем ряду (корпуса). В feature-top

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

    Эти «стрелки» или односторонние соединения от фиксации к фиксации технически являются <em>дугами</em> или односторонними ребрами в <em>ориентированном графе</em> . Этот ориентированный граф не имеет циклов, что делает его направленным ациклическим графом или DAG , у которого есть набор свойств, полезных для Git.

    Если вы просто используете Git для хранения файлов внутри коммитов, все, что вас действительно волнует, - это раунд o

    <em>узлы</em> или <em>вершины</em> (снова два слова для одного и того же) , каждая из которых служит для хранения ваших файлов, но вы должны хотя бы смутно знать, как они устроены. Это имеет значение, особенно из-за слияний . Коммиты слияния - это те, у которых две исходящие дуги, указывающие назад на две из того, что Git называет родительскими коммитами . Дочерняя фиксация - одна «позже»: так же, как человеческие родители всегда старше своих детей, родительские коммиты Git старше своих детей.

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

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

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

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

    Как я уже упоминал, индекс имеет три имени: индекс, промежуточная область и кеш. Все относятся к одному и тому же: к месту, куда Git прикрепляет эти «копии» каждого файла. Каждый из них фактически предварительно дедуплицирован, поэтому слово «копировать» немного неверно, но - в отличие от большей части остальной его внутренней сущности - Git действительно хорошо справляется с сокрытием аспекта дедупликации. Если вы не начнете использовать внутренние команды вроде git ls-files

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

    Все это означает для вас, просто использующего Git, то, что область index / staging-area действует как ваш предложенный следующий коммит . Когда вы запустите, Git упакует эти копии файла как те, которые будут заархивированы в моментальном снимке. Копии, которые есть в вашем рабочем дереве, принадлежат вам; что индекс / постановка-зона копия Git и , готова к работе. Итак, если вы меняете свои копии и хотите, чтобы измененная копия была тем, что будет в следующем снимке, вы должны сообщить Git: Обновите копию Git в области индекса / подготовки Git. Вы делаете это с помощью. 3 Команда означаетсделать копию предложенной следующей фиксации совпадающей с копией рабочего дерева . Это команда, которая выполняет обновление: это когда Git сжимает и дедуплицирует файл и подготавливает его к архивированию, а не во время. 4

    Затем, если у вас есть серия коммитов, оканчивающаяся на hash-N

    :
          [hash1] <-[hash2] ... <-[hashN]   <--branch
    

    вы запускаете, даете ему любые метаданные, которые ему нужны (сообщение журнала фиксации), и вы получаете N + 1-й коммит:

          [hash1] <-[hash2] ... <-[hashN] <-[hashN+1]   <--branch
    

    Git автоматически обновляет имя ветки, чтобы указать на новую фиксацию , которая поэтому была добавлена ​​в ветку .

    Давайте теперь посмотрим на каждую из различных команд:

    • : это большая и сложная команда.

      Мы уже видели это, или, по крайней мере, половину этого. Мы использовали его, чтобы выбрать имя ветки и, следовательно, конкретную фиксацию. Этот вид проверки сначала смотрит на нашу текущую фиксацию, индекс и рабочее дерево. Это гарантирует, что мы зафиксировали все наши измененные файлы или - эта часть становится немного сложнее - что, если мы не зафиксировали все наши измененные файлы, переключение на эту другую ветвь будет «безопасным». Если это не безопасно, говорит вам , что вы не можете переключаться из - за наличия измененных файлов. Если это безопасно, переключит; если вы не хотели переключаться, вы можете просто переключиться обратно. (См. Также Оформить заказ в другой ветке, если в текущей ветке есть незафиксированные изменения )

      Но есть небезопасная половина. Предположим, вы изменили какой-то файл в своем рабочем дереве, например или aux.h

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

    Чтобы получить это - стереть ваши изменения, скажем, README.md

    -Вы можете запустить:
            git checkout -- README.md
    

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

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

            git checkout hello
    

    иметь в виду? Просим ли мы Git очистить файл, чтобы удалить внесенные нами изменения, или мы просим Git проверить ветку hello

    ? Чтобы сделать это недвусмысленным, вы должны написать либо:
            git checkout -- hello        (clobber the file)
    

    или же:

            git checkout hello --        (get the branch)
    

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

    (Команда также была усовершенствована, так что если у вас есть новые команды и вы запускаете «плохой» вид неоднозначности, Git просто будет жаловаться на вас и вообще ничего не сделает. Используйте либо более умные команды разделения, либо добавьте в нужное место, чтобы выбрать, какой тип операции вы хотите.)

    Точнее, этот вид , в идеале пишется git checkout -- paths

    , это запрос к Git на копирование файлов из индекса Git в ваше рабочее дерево. Это означает затирать мои файлы . Вы также можете запустить git checkout tree-ish -- paths, где вы добавляете к команде хеш-код фиксации 5 . Это указывает Git скопировать файлы из этого коммита сначала в индекс Git, а затем в ваше рабочее дерево. Это тоже означает затирание моих файлов: разница в том, где Git получает копии файлов, которые он извлекает.

    Если вы запустили какой-то файл и скопировали его в индекс Git, вам понадобится git checkout HEAD -- file

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

    В зависимости от того, как вы считаете, существует до пяти или шести различных форм. Здесь мы сосредоточимся на меньшем подмножестве.

    • git reset [ --hard | --mixed | --soft ] [ commit ]

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

    Покажем это в виде рисунка. Предположим, у нас есть:

              ...--E--F--G--H   <-- branch
    

    То есть эта названная ветка заканчивается четырьмя коммитами, хэш-ID которых мы будем называть,, и в указанном порядке. Имя в настоящее время хранит хэш-идентификатор последнего из этих коммитов,. Если мы используем git reset --hard HEAD~3

    , мы говорим Git, что нужно удалить последние три коммита . Результат:
                     F--G--H   ???
          /
    ...--E   <-- branch
    

    Название branch

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

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

    означает вернуться на три первых родительских шага , что в данном случае возвращает нас от фиксации к фиксации.

    Часть этого состоит в том, как мы сообщаем Git, что делать с (а) его индексом и (б) нашими файлами рабочего дерева. У нас есть три варианта:

    • --soft

    говорит Git: оставьте обоих в покое . Git переместит имя ветки, не касаясь индекса или нашего рабочего дерева. Если ты бежишь git commitтеперь все, что есть (все еще) в индексе, входит в новую фиксацию. Если индекс совпадает с моментальным снимком в фиксации, это дает вам новую фиксацию, у которой есть моментальный снимок , но чей родительский , как если бы все коммиты были свернуты в одну новую фиксацию. Обычно это называют раздавливанием .
  • сообщает Git: сбросьте ваш индекс, но не трогайте мое рабочее дерево . Git переместит имя ветки, а затем заменит каждый файл в индексе на файл из недавно выбранной фиксации . Но Git оставит все ваши файлы рабочего дерева в покое. Это означает, что что касается Git, вы можете запускать файлы, чтобы сделать новую фиксацию. Ваша новая фиксация не будет соответствовать, если вы не все , поэтому это означает, что вы могли бы, например, создать новую промежуточную фиксацию, вроде как E+F

  • или что-то, если хотите.
  • сообщает Git: сбросьте ваш индекс и мое рабочее дерево. Git переместит имя ветки, заменит все файлы в своем индексе и заменит все файлы в вашем рабочем дереве, и все это как единое целое. Теперь это как если бы вы вообще не совершали этих трех коммитов. У вас больше нет файлов из F

  • , или, или: у вас есть файлы из коммита.

    Обратите внимание, что если вы не укажете commit

    часть этого вида (твердый / мягкий / смешанный) reset, Git будет использовать. Поскольку именуется текущая фиксация (выбранная текущим именем ветки), это оставляет само имя ветки неизменным: она по-прежнему выбирает ту же фиксацию, что и раньше. Так что это полезно только с --mixed или же --hard, потому что git reset --soft, без хеш-идентификатора фиксации, означает, что не перемещайте имя ветки, не меняйте индекс Git и не трогайте мое рабочее дерево . Это три вещи, которые этот тип может сделать - переместить имя ветки, изменить то, что находится в индексе Git, и изменить то, что находится в вашем рабочем дереве, - и вы просто исключили все три. Git ничего не делает, но зачем?
  • git reset [ tree-ish ] -- path

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

    Вместо этого вы выбираете, какие файлы хотите откуда-то скопировать. Где - то есть tree-ish

    вы даете; если вы его не дадите, то где-то есть HEAD, то есть текущая фиксация. Это может только восстановить файлы в предлагаемой следующей фиксации до той формы, которую они имеют в существующей фиксации . По умолчанию на текущую существующую фиксацию этот вид git reset -- path имеет эффект отмены git add -- path. 6

    Есть несколько других форм. Чтобы узнать, что все они означают, обратитесь к документации .

  • : это отделилось от.

    По сути, это то же самое, что и различные формы и файлы clobber (в вашем рабочем дереве и / или в индексе Git). Это умнее старого варианта -and-clobber-my-work, поскольку вы можете выбрать, откуда и куда будут отправляться файлы , в одной командной строке.

    Чтобы делать то, что вы делали с git checkout -- file

  • ты просто бежишь git restore --staged --worktree -- file. (Вы можете опустить часть, как и в большинстве случаев, но в целом разумно иметь привычку использовать ее. Например, эта команда разработана таким образом, что только файлы с именами -whatever на самом деле проблематичны.)

    Чтобы делать то, что вы делали с git reset -- file

    ты просто бежишь git restore --worktree -- file, или даже просто git restore -- file поскольку --worktree здесь по умолчанию.

    Обратите внимание, что вы можете скопировать файл из существующего коммита в индекс Git, не касаясь копии этого файла в рабочем дереве: git restore --source commit --staged -- file

    делает это. Вы не можете сделать этого со старым, но можете сделать то же самое со старым, как git reset commit -- file. Это совпадение существует потому, что оно новое, и такое восстановление имеет смысл; вероятно, в идеале мы всегда должны использовать git restore здесь вместо использования старого git reset способ делать что-то, но Git пытается поддерживать обратную совместимость.
  • : это как раз и делает "безопасную половину". Это действительно все, что вам нужно знать. С помощью git switch

  • , без --force, Git не перезапишет вашу несохраненную работу, даже если вы сделаете опечатку или что-то еще. Старый git checkout команда может перезаписать несохраненную работу: если ваша опечатка превращает имя ветки в имя файла, например, ну, упс.
  • git revert

  • (Я добавил это для полноты): это делает новую фиксацию . Смысл новой фиксации - отменить то, что кто-то сделал в существующей фиксации. Поэтому вам нужно назвать существующую фиксацию, откат которой должен быть отменен. Вероятно, эту команду следовало назвать git backout.

    Если вы откажетесь от самой последней фиксации, произойдет возврат ко второму последнему моментальному снимку:

              ...--G--H   <-- branch
    

    становится:

              ...--G--H--Ħ   <-- branch
    

    где совершить Ħ

    (H-bar) "отменяет" фиксацию Hи поэтому оставляет нам те же файлы, что и коммит G. Но нам не нужно отменять самую последнюю фиксацию. Мы могли взять:
              ...--E--F--G--H   <-- branch
    

    и добавить коммит Ǝ

    это отменяет E получить:
              ...--E--F--G--H--Ǝ   <-- branch
    

    который может не совпадать с исходным снимком любой предыдущей фиксации!


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

    2 Даже в этом случае «удаленная» фиксация еще не исчезла : вы можете вернуть ее. Однако в этом ответе не будет рассказано, как это сделать. Также, git commit --amend

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

    3 Чтобы удалить файл как из рабочего дерева, так и из индекса Git, вы можете использовать git rm

    . Если вы удалите файл из рабочего дерева, а затем запустите его с этим именем, Git «добавит» удаление, так что это тоже сработает.

    4 Если вы используете git commit -a

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

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

    6 Как и все остальные команды Git, вы можете использовать --

    между командой и путями, которые нужно добавить. На самом деле это хорошая привычка, поскольку это означает, что вы можете добавить путь с именем, если у вас есть такой путь: git add -- -uозначает добавить файл с именем -u но git add -uэто совсем не значит. Конечно, файлы, имена которых соответствуют последовательностям опций, менее распространены и менее удивительны, чем файлы, имена которых соответствуют именам веток: действительно легко иметь devветка и набор файлов с именем dev/whatever. Поскольку пути к файлам будут совпадать с использованием каталогов, для добавления, извлечения, сброса и восстановления они могут перепутаться. В addкоманда не принимает имя ветки , поэтому в этом отношении она безопаснее.

    На ваш 1-й вопрос "Что такое git-restore?":

    git-restore - инструмент для отмены незавершенных изменений. Незавершенные изменения: а) изменения в вашей рабочей копии или б) содержимое в вашем индексе (также известном как промежуточная область).

    Эта команда была введена в git 2.23 (вместе с git-switch) для разделения нескольких задач, ранее объединенных в git-checkout.

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

    git restore [--worktree] <file>перезаписывает <файл> в вашей рабочей копии содержимым вашего индекса (*). Другими словами, он отменяет ваши изменения в рабочей копии. Указываете ли вы--worktree или нет, не имеет значения, потому что это подразумевается, если вы не говорите иначе.

    git restore --staged <file>перезаписывает <файл> в вашем индексе текущим заголовком из локального репозитория. Другими словами, он отключает ранее подготовленный контент. Пока что он действительно эквивалентен старомуgit reset HEAD <file>.

    Чтобы перезаписать и рабочую копию, и индекс текущим HEAD, используйте git restore --staged --worktree --source HEAD <file>. Эта версия делает и то, и другое: возвращает вашу рабочую копию в HEAD и отключает ранее поставленную работу.

    На ваш второй вопрос "В чем разница между git-restore и git-reset?":

    Между этими двумя командами есть как совпадения, так и различия.

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

    Есть еще отличия, которые я не могу здесь перечислить.

    (*) Файл не added в индекс по-прежнему считается находящимся в индексе, но в "чистом" состоянии из текущей ревизии HEAD.

    В качестве краткого справочника может оказаться полезным рисунок ( стрелки обозначают место и источник обновления): Обратите внимание, что эти









    gitкомандам также нужны другие параметры, такие какpath.
    Примеры:

          git restore . 
    git add .
    git commit -m "commit name here"
    git restore --staged .
    

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

    git сброс -- :

             This command is used to unstaged changes that were previously added to the 
       staging area.
    
      The <mode> parameter specifies the reset mode. The commonly used modes for 
      unstaging are mixed, soft, and hard.
    
      mixed (default): Unstages changes but keeps them in the working directory. It 
     resets the index to match the HEAD commit.
    
      soft: Unstages changes and keeps them in the index (staging area). It does 
      not modify the working directory.
    
      hard: Unstages changes and discards them both from the index and the working 
      directory.
      <file> specifies the file or files you want to unstage.
    Example usage:
    
    # Unstage changes and keep them in the working directory
    git reset <file>
    
    # Unstage changes and keep them in the index (staging area)
    git reset --soft <file>
    
    # Unstage changes and discard them from both index and working directory
    git reset --hard <file>
    
    **git restore --staged <file>:**
    
    This command is used to unstaged changes from the index (staging area) and revert them to the state of the last commit.
    It does not modify the working directory; it only affects the staging area.
    <file> specifies the file you want to unstage.
    

    Пример использования:

          # Unstage changes from the index (staging area)
    git restore --staged <file>
    In summary, both git reset --<mode> <file> and git restore --staged <file> can be used to unstage changes, but the key differences are:
    
    git reset has more flexibility in terms of the reset mode (mixed, soft, hard), which determines what happens to the changes in the working directory.
    
    git restore --staged is focused specifically on unstaging changes from the index while keeping the working directory unchanged.
    
    You can choose the appropriate command based on your desired outcome: whether you want to unstage changes while preserving them in the working directory, or unstage changes solely from the index/staging area.
    
    Другие вопросы по тегам