Почему git не может сделать жесткий / мягкий сброс по пути?


138

$ git reset -- <file_path> можно сбросить по пути.

Тем не менее, $ git reset (--hard|--soft) <file_path>сообщит об ошибке, как показано ниже:

Cannot do hard|soft reset with paths.

Ответы:


143

Потому что в этом нет смысла (другие команды уже предоставляют эту функциональность), и это снижает вероятность случайного неправильного действия.

«Жесткий сброс» для пути только что сделан git checkout HEAD -- <path>(проверяя существующую версию файла).

Мягкий сброс для пути не имеет смысла.

Смешанный сброс для пути это то, что git reset -- <path>делает.


72
Лично я думаю, что git checkout -- <path>следует заменить на git reset --hard <path>. Это имеет гораздо больше смысла ...
vergenzt

24
git checkout -- <path>не делает хард ресет; он заменяет содержимое рабочего дерева поэтапным содержимым. git checkout HEAD -- <path>выполняет полный сброс пути, заменяя индекс и рабочее дерево версией из коммита HEAD.
Дан Фабулич

1
@EdPlunkett Er, второе предложение в ответе говорит вам, какая другая команда обеспечивает функциональность.
Янтарь

16
-1: возврат к указанной ревизии не приведет к удалению файлов из рабочей копии, если указанная ревизия содержит удаленные файлы. reset --hardс путем обеспечил бы этот недостающий кусок. Git уже настолько силен, что «Мы не позволяем вам сделать это для вашей собственной защиты», оправдание не содержит воды: существует множество способов сделать неправильную вещь «случайно». Ничего из этого не имеет значения, если у вас есть git reflog.
void.pointer

1
как упомянуто @ void.pointer checkout не удалит файлы. Если вы хотите такое поведение, посмотрите на этот ответ. Тем не менее, я надеюсь, что когда-нибудь мы получим git reset --hard -- <path>. Есть законные варианты использования для этого.
Мариуш Павельский

18

Вы можете выполнить то, что вы пытаетесь сделать, используя git checkout HEAD <path>.

Тем не менее, предоставленное сообщение об ошибке не имеет смысла для меня (так git resetкак прекрасно работает на подкаталогах), и я не вижу причин, почему git reset --hardне следует делать именно то, что вы просите об этом.


с помощью checkout вносит изменения, которые не совпадают со сбросом --soft
worc

11

На вопрос, как уже ответили , я объясню, почему часть.

Итак, что делает git reset ? В зависимости от указанных параметров он может выполнять две разные функции:

  • Если вы укажете путь, он заменит сопоставленные файлы в индексе файлами из фиксации (по умолчанию HEAD). Это действие вообще не влияет на рабочее дерево и обычно используется как противоположность git add.

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

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

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


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

Может быть, потому что эта функциональность (сброс рабочего дерева для определенных файлов) уже доступна как git checkoutкоманда? А сброс настроек для выполнения той же задачи может еще больше запутать пользователей. Я ответил, что эта --hardопция не применима к определенным файлам, потому что это режим сброса ветвей, а не индексации. И сброс рабочего дерева называется checkout, как вы можете прочитать в других ответах. Все это просто плохой дизайн пользовательского интерфейса Git, ИМХО.
пользователь

Сравнение первого варианта с git checkout: git reset --устанавливает только индекс, а git checkout --устанавливает только рабочее дерево?
seeker_of_bacon

4

Убедитесь, что вы поставили косую черту между origin или upstream (source) и фактической веткой:

git reset --hard origin/branch

или

git reset --hard upstream/branch`

Пожалуйста, прочитайте вопрос снова.
Xerus

3

За этим стоит очень важная причина: принципы checkoutиreset .

В терминах Git оформление заказа означает «внести в текущее рабочее дерево». И с помощью git checkoutмы можем заполнить рабочее дерево данными из любого области, будь то из коммита в репозитории или отдельных файлов из коммита или промежуточной области (что даже по умолчанию).

В свою очередь, git reset не имеет этой роли. Как следует из названия, он будет сбрасывать текущий ref, но всегда имея хранилище в качестве источника, независимо от «досягаемости» (--soft, --mixed или --hard).

Резюме:

  • проверять, выписываться : из любого места (индекс / фиксация репо) -> рабочее дерево
  • сброс : Repo commit -> Overwrite HEAD (и, возможно, индексирование и рабочее дерево)

Поэтому то, что может быть немного запутанным, это существование git reset COMMIT -- files поскольку «перезапись HEAD» только некоторыми файлами не имеет смысла!

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

Так что как-то git reset -- <files>уже немного исключительно: оно не перезаписывает ГОЛОВУ. ИМХО все такие вариации были бы исключениями. Даже если мы сможем придумать --hardверсию, другие (например --soft) не будут иметь смысла.


Мне нравится этот ответ. Действительно, git reset -- <files>упал так, как будто он был добавлен, потому что это полезная функция, но никто не был уверен, в какую команду ее следует ставить. К счастью, теперь у нас гораздо больше здравомыслящих, git restoreкоторые имеют функциональность git checkout -- <path> git checkout <commit> -- <path>и git reset [<commit>] -- <path>гораздо более разумные настройки по умолчанию и еще больше функций, которые вы не могли сделать раньше (вопреки тому, что говорит принятый ответ. Теперь вы можете легко восстановить только рабочее дерево, не касаясь индекса).
Мариуш Павельски

0

объяснение

В git resetруководстве перечислены 3 способа вызова:

  • 2 относятся к файлам: они не влияют на рабочее дерево , а работают только с файлами в индексе, указанном <paths>:

    • git reset [-q] [<tree-ish>] [--] <paths>..
    • git reset (--patch | -p) [<tree-ish>] [--] [<paths>...]
  • 1 является обязательным: работает со всеми файлами в ссылках <commit>и может влиять на рабочее дерево:

    • git reset [<mode>] [<commit>]

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

Временное решение

Если вы хотите оба:

  • Сброс версии индекса / кэша файла (ов)
  • Извлечь файл (ы) (то есть, чтобы рабочее дерево соответствовало индексу и версии фиксации)

Вы можете использовать этот псевдоним в вашем файле конфигурации git:

[alias]
  reco   = !"cd \"${GIT_PREFIX:-.}\" && git reset \"$@\" && git checkout \"$@\" && git status --short #"  # Avoid: "fatal: Cannot do hard reset with paths."

Затем вы можете сделать одно из:

$ git reco <paths>

$ git reco <branch/commit> <paths>

$ git reco -- <paths>

(Мненоник для reco: reset && check out)


-2

git reset --soft HEAD ~ 1 имя файла отменяет фиксацию, но изменения остаются локальными. имя файла может быть - для всех переданных файлов


6
со смертельным исходомCannot do soft reset with paths.
альт
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.