В чем разница между "git checkout -". и "git reset HEAD --hard"?
Это не общий вопрос о том, что делает "-", как в отмеченном дубликате. Это специфический для git вопрос, требующий ясности в том, каковы операционные различия между упомянутыми командами.
Если я хочу очистить свой текущий каталог без сохранения или фиксации, я обычно использую эти команды:
git reset HEAD --hard
git clean -fd
Сотрудник также упомянул, используя эту команду:
git checkout -- .
Это сложная команда для google, и мне не ясно из документации git, что на самом деле делает эта команда. Похоже, это одно из упомянутых в дальнейшем употреблений в руководстве.
На предположение, что это повторяет git reset HEAD --hard
, но что именно он делает по сравнению с командами, которые я уже использую?
Копирует ли он одну или обе команды или похож, но слегка отличается?
1 ответ
Во-первых, давайте просто обратимся к двойному дефису или двойному тире, чтобы убрать его с пути (тем более, что у этого вопроса больше нет отмеченного дубликата).
Git в основном использует это POSIX-одобренным способом (см. Рекомендацию 10), чтобы указать разделительную линию между аргументами-опционами и аргументами-не-опционами. поскольку git checkout
принимает имена филиалов, как в git checkout master
а также имена файлов (пути), как в git checkout README.txt
, вы можете использовать --
заставить Git интерпретировать то, что следует после --
в качестве имени файла, даже если в противном случае это будет допустимое имя ветви. То есть, если у вас есть как ветка, так и файл с именем master
:
git checkout master
проверим ветку, но:
git checkout -- master
проверим файл (смущенно, из текущего индекса).
Ветви, индекс и файлы, о боже
Далее нам нужно обратиться к причуде git checkout
, Как видно из документации, существует множество "режимов" git checkout
(документация перечисляет шесть отдельных вызовов в кратком изложении!). Существуют различные высказывания (различного качества: Стив Беннет на самом деле полезен, на мой взгляд, хотя, естественно, я не согласен с этим на 100%:-)) о плохой модели "пользовательского опыта" Git, включая тот факт, что git checkout
имеет слишком много режимов работы.
В частности, вы можете git checkout
ветвь (для переключения веток), или git checkout
один или несколько файлов. Последний извлекает файлы из определенного коммита или из индекса. Когда Git извлекает файлы из коммита, он сначала копирует их в индекс, а затем копирует их из индекса в рабочее дерево.
Существует основная причина реализации этой последовательности, но тот факт, что она полностью просвечивает, является ключевым элементом. Нам нужно много знать об индексе Git, потому что оба git checkout
а также git reset
использовать его, а иногда и по-разному.
Думаю, это хорошая идея - нарисовать трехстороннюю диаграмму или таблицу, иллюстрирующую HEAD
—Коммит, индекс и рабочее дерево. Предположим, что:
- есть два обычных, переданных файла
README.md
а такжеfile.txt
; - есть новый,
git add
, но без обязательствnew.txt
; - есть файл с именем
rmd.txt
это былоgit rm
но не совершено; - и есть неотслеживаемый файл с именем
untr.txt
,
Каждый объект - HEAD
commit, index и work-tree - содержат три файла прямо сейчас, но каждый содержит свой набор файлов. Таблица всего состояния тогда выглядит так:
HEAD index work-tree
-------------------------------
README.md README.md README.md
file.txt file.txt file.txt
new.txt new.txt
rmd.txt
untr.txt
Существует гораздо больше возможных состояний, чем только эти: на самом деле для каждого имени файла существует семь возможных комбинаций HEAD, индекса и рабочего дерева "in / not-in" (восьмая комбинация - "не во всех трех". msgstr "в каком случае, о каком файле мы вообще говорим?!"
checkout
а также reset
команды
Две команды, о которых вы спрашиваете, git checkout
а также git reset
, оба умеют делать много вещей. Тем не менее, конкретные вызовы каждого из них сводят "выполненные действия" к одному из двух, к которым я добавлю еще несколько:
git checkout -- .
: только копии из индекса в рабочее деревоgit checkout HEAD -- .
: копии из HEAD, для индексации, а затем для рабочего дереваgit reset --mixed
: сбрасывает индекс из HEAD (и оставляет рабочее дерево в покое)git reset --hard
: сбрасывает индекс из HEAD, затем сбрасывает рабочее дерево из индекса
Они во многом совпадают, но есть несколько принципиально разных частей.
Давайте рассмотрим файл с именем new.txt
выше в частности. Сейчас он находится в индексе, поэтому, если мы копируем из индекса в рабочее дерево, мы заменяем копию рабочего дерева на индексную копию. Это то, что git checkout -- new.txt
делает, например.
Если вместо этого мы начнем с копирования из HEAD
с индексом ничего не происходит new.txt
в индексе: new.txt
не существует в HEAD
, Отсюда явный git checkout HEAD -- new.txt
просто терпит неудачу, в то время как git checkout HEAD -- .
копирует файлы, которые находятся в HEAD
и оставляет два существующих new.txt
Версии нетронутые.
Файл rmd.txt
ушел из индекса, поэтому если мы git checkout -- .
Git этого не видит и ничего с этим не делает. Но если мы git checkout HEAD -- .
Git копии rmd.txt
от HEAD
в индекс (теперь он вернулся), а затем из индекса в рабочее дерево (и теперь он тоже там).
git reset
Команда имеет ключевое различие, когда используется без аргументов имени пути. Здесь он буквально сбрасывает индекс в соответствии с коммитом. Это означает, что для new.txt
, он замечает, что файл не находится в HEAD
, поэтому он удаляет запись индекса. Если используется с --hard
поэтому он также удаляет запись рабочего дерева. между тем rmd.txt
находится в HEAD
, поэтому он копирует это обратно в индекс, и с --hard
к рабочему дереву.
Если есть неустановленные, т. Е. Только рабочее дерево, изменения в двух других файлах README.md
а также file.txt
Обе формы git checkout
и --hard
форма git reset
уничтожить эти изменения.
Если в этих файлах имеются поэтапные изменения - изменения, которые были скопированы в рабочее дерево, - тогда git reset
снимает их. Так же, как вариант git checkout
где вы даете ему имя HEAD
, Тем не менее, вариант git checkout
когда вы копируете файлы индекса обратно в рабочее дерево, эти поэтапные изменения сохраняются!
Верхний уровень против текущего каталога
Наконец, стоит отметить, что .
, то есть текущий каталог, может в любое время отличаться от "top of git repository":
$ git rev-parse --show-toplevel
/home/torek/src/kernel.org/git
$ pwd
/home/torek/src/kernel.org/git/Documentation
$ git rev-parse --show-cdup
../
Здесь я в Documentation
подкаталог каталога верхнего уровня git
, так .
означает все в Documentation
и его подкаталоги. С помощью git checkout -- .
проверим (из индекса) все Documentation
а также Documentation/RelNotes
файлы, но не любой из ../builtin
файлы, например. Но git reset
при использовании без имен путей сбросит все записи, в том числе и для ..
а также ../builtin
,