Przełącz gałąź Git bez pobierania plików

100

Czy w Git można przejść do innej gałęzi bez wypisywania wszystkich plików?

Po zmianie gałęzi muszę usunąć wszystkie pliki, zregenerować je, zatwierdzić i przełączyć z powrotem. Więc wyewidencjonowywanie plików to tylko strata czasu (a jest ich około 14 000 - to długa operacja).

Aby wszystko było jasne:

Potrzebuję tego wszystkiego, aby przesłać dokumentację do GitHub.

Mam repozytorium z gałęzią gh-pages . Kiedy odbudowuję dokumentację lokalnie, kopiuję ją do katalogu repozytorium, zatwierdzam i wypycham do GitHub. Ale nie byłem zadowolony, bo miałem lokalnie dwie kopie dokumentacji. Postanowiłem stworzyć pustą gałąź i po zatwierdzeniu przełączyć się na opróżnianie i usuwanie plików. Ale powrót to długa operacja - więc zadałem to pytanie.

Wiem, że mogę po prostu zostawić gałąź gh-pages i usunąć pliki, ale nie lubię brudnych drzew roboczych.

tig
źródło
Jak długo jest dla Ciebie „długie”? Na jakiej platformie pracujesz? Czy pracujesz w sieci, takiej jak NFS lub inne udostępnianie plików?
Greg Hewgill
Jaki jest cel tego ćwiczenia? Czy chcesz mieć dwie gałęzie, jedną ze szczegółowymi zatwierdzeniami, drugą rejestrującą tylko większe zmiany (gruboziarniste)?
Jakub Narębski
Być może taniej jest utworzyć tymczasowy (lub stały?) Klon kopii roboczej. Moja powiązana odpowiedź i zapis pokazują, jak to działa, nawet jako podkatalog w głównym repozytorium.
krlmlr

Odpowiedzi:

106

Tak, możesz to zrobić.

git symbolic-ref HEAD refs/heads/otherbranch

Jeśli musisz zatwierdzić tę gałąź, będziesz chciał również zresetować indeks, w przeciwnym razie zatwierdzisz coś na podstawie ostatniej wyewidencjonowanej gałęzi.

git reset
CB Bailey
źródło
1
Użyj, echo "ebff34ffb665de0694872dceabe0edeaf50ec5a9" > .git/HEADa następnie, git resetaby wskazać ref zamiast gałęzi.
cadorn
1
Bezpośrednie zapisywanie do pliku HEAD jest mniej niezawodne. A co jeśli jesteś w podkatalogu? W przypadku odłączonej głowy (głowa skierowana bezpośrednio na SHA1) spróbuj tego: git update-ref HEAD refs/heads/otherbranch
Alexander Bird
2
Jeśli chcesz wyewidencjonować nową gałąź z bieżącej gałęzi, możesz to zrobić w inny sposób 1. git stash2. git checkout -b otherBranch3.git stash pop
Winny
@AlexanderBird: git update-refjest przydatny, ale przesuwa również końcówkę bieżącej gałęzi.
tomekwi
47

Używanie tylko podstawowych poleceń git:

Ta odpowiedź jest nieco dłuższa niż odpowiedź Charlesa, ale składa się wyłącznie z podstawowych poleceń git, które mogę zrozumieć i dzięki temu zapamiętać, eliminując potrzebę ciągłego wyszukiwania.

Zaznacz swoją aktualną lokalizację (jeśli to konieczne, zatwierdź najpierw):

git checkout -b temp

Zresetuj (przenosi) znacznik do innej gałęzi bez zmiany katalogu roboczego:

git reset <branch where you want to go>

teraz temp i inna gałąź wskazują na to samo zatwierdzenie, a twój katalog roboczy pozostaje nietknięty.

git checkout <branch where you want to go>

ponieważ twoja HEAD już wskazuje na ten sam commit, dir roboczy nie jest poruszony

git branch -d temp

Należy pamiętać, że te polecenia są również łatwo dostępne z dowolnego klienta graficznego.


źródło
7
Wolałbym git reset --soft <branch where you want to go>uniknąć aktualizacji indeksu
JoelFan
7
Zgadzam się z twoją strategią unikania poleceń dotyczących hydrauliki git i faworyzowania tych porcelanowych.
user64141
26

W wersji 2.24 git switchjest coś w rodzaju sejfu git checkout.
Dlatego zmieniłem nazwę poniższego aliasu git hopna
„wskocz do gałęzi bez zmiany drzewa roboczego”

Z korzyścią dla czytelnika:

Chociaż uważam, że rozwiązanie Charlesa Baileya jest poprawne, to rozwiązanie to wymaga poprawki przy przechodzeniu na coś, co nie jest lokalnym oddziałem. Powinien też istnieć sposób, jak to zrobić za pomocą zwykłych poleceń, które są łatwe do zrozumienia. Oto co wymyśliłem:

git checkout --detach
git reset --soft commitish
git checkout commitish

Wyjaśnione:

  • git checkout --detachjest tym samym, git checkout HEAD^{}co pozostawia bieżącą gałąź za sobą i przechodzi w „stan odłączonej głowy”. Więc następna modyfikacja HEADnie ma już wpływu na jakąkolwiek gałąź. Odłączenie HEADnie wpływa na drzewo robocze ani indeks.
  • git reset --soft commitishnastępnie przechodzi HEADdo SHA danego commitish. Jeśli chcesz również zaktualizować indeks, zostaw to --soft, ale nie polecam tego robić. To znowu nie dotyczy drzewa roboczego ani ( --soft) indeksu.
  • git checkout commitishnastępnie przyłącza HEADsię ponownie do danej commitish(gałęzi). (Jeśli commitishjest SHA, nic się nie dzieje.) To również nie wpływa na indeks ani na drzewo robocze.

To rozwiązanie akceptuje wszystko, co odnosi się do zatwierdzenia, więc jest to idealne rozwiązanie dla niektórych gitaliasów. rev-parsePoniżej to tylko test, aby upewnić się, przerwy nic w łańcuchu, tak że literówki nie przypadkowo przełączyć do głowy państwa jednorodzinnego (usuwanie błędów byłoby o wiele bardziej skomplikowane).

Prowadzi to do następującego git hop treeishaliasu:

git config --global alias.hop '!f() { git rev-parse --verify "$*" && git checkout "HEAD^{}" && git reset --soft "$*" && git checkout "$*"; }; f'

FYI, możesz go znaleźć na mojej liście gitaliasów .

Tino
źródło
Nie chcesz używać $@zamiast $*? Różnica polega na tym, że $ @ bez rozszerzonych cudzysłowów, które mają spacje wewnątrz.
kyb
1
@kyb Sztuczka funkcyjna została skradziona z innej SO odpowiedzi . I $@definitywnie nie ma tu na myśli. $*jest używane zamiast $1, takie, które git switch -f bstaje się tym samym, git switch '-f b'co powinno być błędem. W ten sposób mogę skrócić alias, rezygnując z obsługi błędów, takich jak!f() { [ 1 = $# ] || { echo 'WTF!'; return 1; }; ..
Tino
Bardzo dobre rozwiązanie. Zwłaszcza, że ​​można go używać do zdalnych oddziałów!
Nils-o-mat
14

Czy nie byłoby lepszym rozwiązaniem posiadanie dwóch katalogów roboczych (dwóch obszarów roboczych) z jednym repozytorium lub nawet dwoma repozytoriami?

W sekcji znajduje się narzędzie git-new-workdir , contrib/które może Ci w tym pomóc.

Jakub Narębski
źródło
Czy git-new-workdir to to samo, co własne polecenie workktree git? Używam workktree, gdy chcę pobrać gałąź do innego folderu (bez konieczności klonowania całego repozytorium).
Ryuu
W git-new-worktreepoprzedza skrypt git worktreekomendy; to polecenie nie było dostępne, kiedy pisano odpowiedź. Na przykład skrypt wymaga obsługi dowiązań symbolicznych; IMHO lepiej jest korzystać z natywnej obsługi.
Jakub Narębski
8

Myślę, że szukasz polecenia hydrauliki git read-tree. Spowoduje to zaktualizowanie indeksu, ale nie zaktualizuje żadnych plików w katalogu roboczym. Na przykład zakładając, że branchnależy przeczytać nazwę oddziału:

gałąź drzewa odczytu git

Jeśli chcesz następnie zaangażować się w gałąź, którą właśnie przeczytałeś, będziesz musiał również:

git symbolic-ref HEAD refs / heads / branch
Greg Hewgill
źródło
nie, muszę tylko zmienić gałąź, żadnych innych zmian - więc symboliczne odniesienie jest wystarczająco dobre
tig
read-treegeneruje błąd: fatal: Not a valid object name branchjeśli jeszcze go nie git switch branchbyło
Andry
7

Możesz nadpisać plik HEAD inną nazwą gałęzi:

echo "ref: refs / heads / MyOtherBranch"> .git / HEAD

user157005
źródło
13
Prawdopodobnie lepiej jest użyć polecenia symbolic-ref, aby zrobić to za Ciebie: git symbolic-ref HEAD refs/heads/MyOtherBranch kernel.org/pub/software/scm/git/docs/git-symbolic-ref.html
Greg Hewgill
@GregHewgill, to jedyny znany mi sposób, aby przenieść HEAD do skrótu zatwierdzenia. Czy możesz to zrobić z git symbolic-ref?
tomekwi
0

Przy tak wielu plikach najlepiej byłoby zachować tylko dwa repozytoria, po jednym dla każdej gałęzi. W razie potrzeby możesz przeciągać zmiany w tę iz powrotem. To będzie mniej zaskakujące niż próba oszukania gita.

Norman Ramsey
źródło
Możesz użyć git-new-worktreedo tego zamiast tego (w contrib/)
Jakub Narębski
Często robiłem coś podobnego, czyli kopiowanie mojego lokalnego katalogu przed zrobieniem „strasznych rzeczy git” jako nowicjusz (jak zmiana gałęzi itp.). Zachęcałbym ludzi do pójścia tą drogą, dopóki nie poczujesz się pewnie w swoim git-fu, ale odejdź od tego, kiedy to możliwe. Utrzymanie dwóch odrębnych repozytoriów jest w porządku, ale dodaje warstwę komplikacji i nie pozwala na wykorzystanie wielu przydatnych funkcji gita (scalanie, wybieranie wiśni itp.).
David
0

Jeśli po prostu próbujesz zmienić miejsce, w którym wskazuje zdalna gałąź, możesz to zrobić za pomocą „git push” bez dotykania lokalnej kopii.

http://kernel.org/pub/software/scm/git/docs/git-push.html

Format parametru <refspec> to opcjonalny plus +, po którym następuje źródłowy ref <src>, po którym następuje dwukropek:, po którym następuje docelowy ref <dst>. Służy do określenia, za pomocą którego obiektu <src> ma zostać zaktualizowany ref <dst> w zdalnym repozytorium.

Na przykład, aby zaktualizować foo do zatwierdzenia c5f7eba, wykonaj następujące czynności:

git push origin c5f7eba:foo

Nie jestem pewien, czy o to ci chodziło, czy nie.

Tim Abell
źródło
Pytanie już otrzymało odpowiedź: stackoverflow.com/questions/1282639/…
tig
0

możesz skorzystać

      1. git checkout -f <new-branch>
      2. git cherry-pick -x <previous-branch-commit-id>

previous-branch-commit-id to zatwierdzenie, z którego chcesz skopiować stare dane.

Haseena Parkar
źródło
0

Lub po prostu użyj pliku łatki, aby dokonać poprawki z innej gałęzi do swojego mastera

git diff otherbranch master > ~/tmp/otherbranch.diff
git checkout master
git apply ~/tmp/otherbranch.diff
Tomer Ben David
źródło
-1

powiedz, że chcesz być w gałęzi A, ale z plikami z gałęzi B

znajdź aktualną referencję zatwierdzenia gałęzi A z logiem git, np. "99ce9a2",

git checkout A
git reset --hard B
git reset 99ce9a2

powinieneś teraz znajdować się w gałęzi A, ze strukturą folderów odpowiadającą B, które pojawiają się jako zmiany niestacjonarne (historia nie uległa zmianie).

Dugas
źródło