Dlaczego git nie może wykonać twardego / miękkiego resetu ścieżką?

138

$ git reset -- <file_path> można zresetować ścieżką.

Jednak $ git reset (--hard|--soft) <file_path>zgłosi błąd jak poniżej:

Cannot do hard|soft reset with paths.
yao
źródło

Odpowiedzi:

143

Ponieważ nie ma to sensu (inne polecenia już zapewniają tę funkcjonalność) i zmniejsza możliwość przypadkowego zrobienia niewłaściwej rzeczy.

„Twardy reset” ścieżki jest właśnie wykonywany git checkout HEAD -- <path>(sprawdzanie istniejącej wersji pliku).

Miękki reset ścieżki nie ma sensu.

Powoduje to mieszany reset ścieżki git reset -- <path>.

Bursztyn
źródło
72
Osobiście uważam, że git checkout -- <path>powinien zostać zastąpiony z git reset --hard <path>. To ma o wiele więcej sensu ...
vergenzt
24
git checkout -- <path>nie wykonuje twardego resetu; zastępuje zawartość drzewa roboczego zawartością pomostową. git checkout HEAD -- <path>wykonuje twardy reset ścieżki, zastępując zarówno indeks, jak i drzewo robocze wersją z zatwierdzenia HEAD.
Dan Fabulich
1
@EdPlunkett Er, drugie zdanie odpowiedzi mówi, jakie inne polecenie zapewnia tę funkcjonalność.
Bursztyn
16
-1: Wyrejestrowanie do wspomnianej wersji nie spowoduje usunięcia plików z kopii roboczej, jeśli ta wersja zawiera usunięte pliki. reset --hardze ścieżką zapewniłby ten brakujący element. Git jest już tak potężny, że wymówka „Nie pozwalamy ci tego robić dla własnego bezpieczeństwa” nie zawiera wody: istnieje wiele sposobów, aby zrobić coś złego „przez przypadek”. Zresztą nic z tego nie ma znaczenia, jeśli masz git reflog.
void.pointer
1
jak wspomniano w @ void.pointer, checkout nie usunie plików. Jeśli chcesz takiego zachowania, spójrz na odpowiedź. Mimo to mam nadzieję, że pewnego dnia to się uda git reset --hard -- <path>. Istnieją dla niego uzasadnione przypadki użycia.
Mariusz Pawelski
18

Możesz osiągnąć to, co próbujesz zrobić, używając git checkout HEAD <path>.

To powiedziawszy, dostarczony komunikat o błędzie nie ma dla mnie sensu (ponieważ git resetdziała dobrze w podkatalogach) i nie widzę powodu, dla którego git reset --hardnie powinienem robić dokładnie tego, o co prosisz.

Aaron Kent
źródło
używając checkout etapów zmiany, co nie jest tym samym co reset --soft
worc
11

Pytanie, jak już zostało udzielone , wyjaśnię, dlaczego część.

Więc co robi reset git ? W zależności od określonych parametrów może robić dwie różne rzeczy:

  • Jeśli określisz ścieżkę, zastępuje ona dopasowane pliki w indeksie plikami z zatwierdzenia (domyślnie HEAD). Ta akcja w ogóle nie wpływa na drzewo robocze i jest zwykle używana jako przeciwieństwo git add.

  • Jeśli nie określisz ścieżki, przenosi ona bieżącą gałąź do określonego zatwierdzenia i razem z tym opcjonalnie resetuje indeks i drzewo robocze do stanu tego zatwierdzenia. To dodatkowe zachowanie jest kontrolowane przez parametr mode:
    --soft : nie dotykaj indeksu i drzewa roboczego.
    --mixed (domyślne): resetuje indeks, ale nie drzewo robocze.
    --hard : resetuje indeks i drzewo robocze.
    Istnieją również inne opcje, zapoznaj się z dokumentacją, aby uzyskać pełną listę i niektóre przypadki użycia.

    Kiedy nie określisz zatwierdzenia, domyślnie jest to HEAD, więc git reset --softnic nie zrobi, ponieważ jest to polecenie przeniesienia głowy do HEAD (do jego obecnego stanu). git reset --hardz drugiej strony ma sens ze względu na efekty uboczne , mówi, że przesuń głowę do HEAD i zresetuj indeks i drzewo robocze do HEAD.

    Myślę, że powinno być już jasne, dlaczego ta operacja ze swej natury nie dotyczy konkretnych plików - ma na celu przede wszystkim przesunięcie głowicy gałęzi, resetowanie drzewa roboczego, a indeks jest funkcją drugorzędną.

użytkownik
źródło
jasne jest, że reset ma na celu przede wszystkim przesunięcie głowicy gałęzi, ale skoro ma dodatkową funkcjonalność resetowania drzewa roboczego i indeksu dla całych zatwierdzeń oraz funkcję resetowania indeksu dla określonych plików, dlaczego nie posiada funkcję resetowania drzewa roboczego dla określonych plików? Uważam, że o to prosi PO.
Danilo Souza Morães
Może dlatego, że ta funkcjonalność (resetowanie drzewa roboczego dla określonych plików) jest już dostępna jako git checkoutpolecenie? Zresetowanie w celu zrobienia tego samego spowodowałoby dalsze zamieszanie użytkowników. Moja odpowiedź była taka, że --hardopcja nie ma zastosowania do określonych plików, ponieważ jest to tryb resetowania gałęzi, a nie resetowania indeksu. Resetowanie drzewa roboczego nazywa się checkout, jak możesz przeczytać w innych odpowiedziach. Wszystko to to tylko zły projekt interfejsu użytkownika Git, IMHO.
użytkownik
Porównanie pierwszej opcji z git checkout: git reset --ustawia tylko indeks, podczas gdy git checkout --ustawia tylko drzewo robocze?
seeker_of_bacon
4

Upewnij się, że umieściłeś ukośnik między początkiem lub górnym (source) a rzeczywistą gałęzią:

git reset --hard origin/branch

lub

git reset --hard upstream/branch`
Pascal Nitcheu
źródło
Przeczytaj ponownie pytanie.
Xerus
3

Jest za tym bardzo ważny powód: zasady checkoutireset .

W terminologii Git, checkout oznacza „przenieś do aktualnego drzewa roboczego”. Dzięki temu git checkoutmożemy wypełnić drzewo robocze danymi z dowolnego obszaru, czy to z zatwierdzenia w repozytorium, czy z pojedynczych plików z zatwierdzenia lub obszaru przemieszczania (który jest nawet domyślny).

Z kolei git reset nie ma tej roli. Jak nazwa sugeruje, zresetuje aktualny odnośnik, ale zawsze mając repozytorium jako źródło, niezależnie od „zasięgu” (--soft, --mixed lub --hard).

Podsumować:

  • checkout : Z dowolnego miejsca (zatwierdzenie indeksu / repozytorium) -> drzewo robocze
  • reset : Repo commit -> Overwrite HEAD (i opcjonalnie indeks i drzewo robocze)

Dlatego to, co może być nieco zagmatwane, to fakt, git reset COMMIT -- filesże „nadpisywanie HEAD” tylko niektórymi plikami nie ma sensu!

Wobec braku oficjalnego wyjaśnienia mogę tylko spekulować, że programiści git stwierdzili, że resetnadal jest to najlepsza nazwa polecenia odrzucania zmian wprowadzonych w obszarze przejściowym, a biorąc pod uwagę, że jedynym źródłem danych było repozytorium, „ rozszerzmy funkcjonalność ”zamiast tworzyć nowe polecenie.

Więc jakoś git reset -- <files>jest już trochę wyjątkowy: nie nadpisze HEAD. IMHO wszystkie takie odmiany byłyby wyjątkami. Nawet jeśli potrafimy wymyślić --hardwersję, inne (na przykład --soft) nie miałyby sensu.

F Pereira
źródło
Podoba mi się ta odpowiedź. Naprawdę, git reset -- <files>wyglądało na to, że został dodany, ponieważ jest to przydatna funkcja, ale nikt nie był pewien, w którym poleceniu należy umieścić. Na szczęście mamy teraz znacznie bardziej rozsądne, git restorektóre mają funkcjonalność git checkout -- <path> git checkout <commit> -- <path>i git reset [<commit>] -- <path>znacznie rozsądniejsze ustawienia domyślne, a nawet więcej funkcji, których wcześniej nie mogłeś zrobić (w przeciwieństwie do tego, co mówi zaakceptowana odpowiedź. Teraz możesz wreszcie łatwo przywrócić tylko działające drzewo, bez dotykania indeksu).
Mariusz Pawelski
0

Wyjaśnienie

Do git resetpodręcznika wymienia 3 sposoby z wezwaniem:

  • 2 dotyczą plików: nie mają one wpływu na drzewo robocze , ale działają tylko na plikach w indeksie określonym przez <paths>:

    • git reset [-q] [<tree-ish>] [--] <paths>..
    • git reset (--patch | -p) [<tree-ish>] [--] [<paths>...]
  • 1 jest zgodny z zatwierdzeniem: działa na wszystkich plikach w odnośniku <commit>i może wpływać na drzewo robocze:

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

Nie ma trybu wywołania, który działa tylko na określonych plikach i wpływa na drzewo robocze.

Obejście problemu

Jeśli chcesz:

  • Zresetuj wersję indeksu / pamięci podręcznej pliku (ów)
  • Pobierz plik (i) (tj. Dopasuj drzewo robocze do indeksu i wersji zatwierdzenia)

Możesz użyć tego aliasu w swoim pliku konfiguracyjnym git:

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

Następnie możesz wykonać jedną z następujących czynności:

$ git reco <paths>

$ git reco <branch/commit> <paths>

$ git reco -- <paths>

(Mnenonic dla reco: reset && check out)

Tom Hale
źródło
-2

git reset - soft HEAD ~ 1 nazwa pliku cofa zatwierdzenie, ale zmiany pozostają w lokalnych. nazwa pliku może być - dla wszystkich zatwierdzonych plików

Peiti Li
źródło
6
fatalCannot do soft reset with paths.
alt