Odpowiedzi:
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>
.
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.
reset --hard
ze ś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
.
git reset --hard -- <path>
. Istnieją dla niego uzasadnione przypadki użycia.
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 reset
działa dobrze w podkatalogach) i nie widzę powodu, dla którego git reset --hard
nie powinienem robić dokładnie tego, o co prosisz.
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 --soft
nic nie zrobi, ponieważ jest to polecenie przeniesienia głowy do HEAD (do jego obecnego stanu). git reset --hard
z 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ą.
git checkout
polecenie? Zresetowanie w celu zrobienia tego samego spowodowałoby dalsze zamieszanie użytkowników. Moja odpowiedź była taka, że --hard
opcja 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.
git checkout
: git reset --
ustawia tylko indeks, podczas gdy git checkout --
ustawia tylko drzewo robocze?
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`
Jest za tym bardzo ważny powód: zasady checkout
ireset
.
W terminologii Git, checkout oznacza „przenieś do aktualnego drzewa roboczego”. Dzięki temu git checkout
moż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ć:
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 reset
nadal 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ć --hard
wersję, inne (na przykład --soft
) nie miałyby sensu.
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 restore
któ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).
Do git reset
podrę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.
Jeśli chcesz:
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
: re
set && c
heck o
ut)
git checkout -- <path>
powinien zostać zastąpiony zgit reset --hard <path>
. To ma o wiele więcej sensu ...