Git: utwórz gałąź na podstawie niestabilnych / niezaangażowanych zmian w systemie głównym

991

Kontekst: Pracuję nad mistrzem dodając prostą funkcję. Po kilku minutach zdaję sobie sprawę, że to nie było takie proste i powinno być lepiej pracować w nowym oddziale.

To zawsze mi się zdarza i nie mam pojęcia, jak przejść do innej gałęzi i zabrać ze sobą wszystkie te niezaangażowane zmiany, pozostawiając gałąź główną czystą. Miałem git stash && git stash branch new_branchpo prostu to osiągnąć, ale oto co otrzymuję:

~/test $ git status
# On branch master
nothing to commit (working directory clean)

~/test $ echo "hello!" > testing 

~/test $ git status
# On branch master
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   testing
#
no changes added to commit (use "git add" and/or "git commit -a")

~/test $ git stash
Saved working directory and index state WIP on master: 4402b8c testing
HEAD is now at 4402b8c testing

~/test $ git status
# On branch master
nothing to commit (working directory clean)

~/test $ git stash branch new_branch
Switched to a new branch 'new_branch'
# On branch new_branch
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   testing
#
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (db1b9a3391a82d86c9fdd26dab095ba9b820e35b)

~/test $ git s
# On branch new_branch
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   testing
#
no changes added to commit (use "git add" and/or "git commit -a")

~/test $ git checkout master
M   testing
Switched to branch 'master'

~/test $ git status
# On branch master
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   testing
#
no changes added to commit (use "git add" and/or "git commit -a")

Czy wiesz, czy jest jakiś sposób na osiągnięcie tego?

znopx
źródło
1
Chociaż istnieje prostsze rozwiązanie problemu, czy możesz określić, w jaki sposób otrzymany wynik różni się od tego, co chciałeś?
Gauthier
2
wykonując powyższe czynności lub odpowiedzi na dole, niezaangażowane zmiany dotyczą zarówno głównego, jak i nowego oddziału. Chcę je tylko w nowej gałęzi, więc mogę sprawdzić kasę i pracować nad inną rzeczą, nie zmieniając tych zmian
znopx
1
zobacz moją zredagowaną odpowiedź. Jeśli chcesz wykupić czystego wzorca, musisz zatwierdzić lokalne zmiany w nowym oddziale. Lokalne zmiany to tylko różnice między bieżącym HEAD a plikami na dysku. Te zmiany w plikach lokalnych nie są wersjonowane, musisz powiedzieć git, aby je gdzieś zapisał, jeśli chcesz je później odzyskać.
Gauthier

Odpowiedzi:

1207

Nie musisz ukrywać.

git checkout -b new_branch_name

nie zmienia twoich lokalnych zmian. Po prostu tworzy gałąź z bieżącego HEAD i ustawia HEAD tam. Myślę, że tego właśnie chcesz.

--- Edytuj, aby objaśnić wynik kontroli nad kasą ---

Czy jesteś zdezorientowany, ponieważ checkout masternie odrzuca twoich zmian?

Ponieważ zmiany są tylko lokalne, git nie chce, abyś je zbyt łatwo stracił. Po zmianie oddziału git nie zastępuje lokalnych zmian. Wynikiem twojego checkout masterjest:

M   testing

, co oznacza, że ​​twoje pliki robocze nie są czyste. git zmienił HEAD, ale nie zastąpił plików lokalnych. Dlatego twój ostatni status nadal pokazuje lokalne zmiany, mimo że jesteś włączony master.

Jeśli naprawdę chcesz odrzucić lokalne zmiany, musisz wymusić kasę za pomocą -f.

git checkout master -f

Ponieważ zmiany nigdy nie zostały zatwierdzone, stracisz je.

Spróbuj wrócić do swojego oddziału, zatwierdzić zmiany, a następnie ponownie dokonać transakcji.

git checkout new_branch
git commit -a -m"edited"
git checkout master
git status

Powinieneś otrzymać Mwiadomość po pierwszym kasie, ale już nie po checkout master, i nie git statuspowinien pokazywać żadnych zmodyfikowanych plików.

--- Edytuj, aby usunąć nieporozumienia dotyczące katalogu roboczego (plików lokalnych) ---

W odpowiedzi na twój pierwszy komentarz lokalne zmiany są po prostu ... cóż, lokalne. Git nie zapisuje ich automatycznie, musisz powiedzieć, aby je zapisać na później. Jeśli dokonasz zmian i nie zatwierdzisz ich wyraźnie ani nie ukryjesz, git ich nie zaktualizuje. Jeśli zmienisz HEAD ( checkout master), lokalne zmiany nie zostaną nadpisane od momentu niezapisania.

Gauthier
źródło
32
Mylące jest tutaj to, że strona man git stwierdza, że git checkout„Aktualizuje pliki w drzewie roboczym, aby pasowały do ​​wersji w indeksie lub w określonym drzewie”. Zakłada, że zmiany w systemie plików zostanie GONE później. Bez szansy na ich odzyskanie. Nawet jeśli powiesz, że nie zrobią tego, nadal będzie to bardzo złe uczucie. Nie ufam tym w ogóle . Albo dokumentacja jest naprawdę zła, albo domyślne zachowanie gita jest naprawdę niebezpieczne. Nie należy ufać jakiejś „automagicznej” heurystyce, aby wykryć, że w tym przypadku nie chcesz stracić swoich zmian.
Evi1M4chine
16
Jeśli sprawdzasz zatwierdzenie, które zastąpiłoby twoje lokalne zmiany (jeśli historia między bieżącym zatwierdzeniem a docelowym zatwierdzeniem dotyka twoich lokalnie zmodyfikowanych plików), git odmawia. Tylko jeśli checkoutnie powoduje konfliktu z lokalnymi zmianami, kasa działa i pozostawia lokalne zmiany w spokoju. Rozumiem jednak złe przeczucie, strona podręcznika powinna powiedzieć „Aktualizuje niezmodyfikowane pliki w działającym drzewie”. Z drugiej strony Git nie sprawia, że ​​zbyt łatwo tracić lokalne zmiany. git checkoutpozwala samemu na lokalne zmiany lub odmawia, jeśli występuje konflikt.
Gauthier
1
cóż, jak miałbym dokonać płatności w innym oddziale, nie wprowadzając tam lokalnych zmian?
ア レ ッ ク ス
5
@Alex git checkout <other_branch> -f. Utracisz lokalne zmiany bez ostrzeżenia.
Gauthier
2
@ Evi1M4chine Pierwszy. Dokumentacja jest naprawdę zła.
Qwertie 17.04.16
62

Próbować:

git stash
git checkout -b new-branch
git stash apply
Grant Limberg
źródło
6
Czy różni się to od samego zrobienia „git checkout -b new-branch”?
Adrian Mouat,
Nie sądzę, żeby było tak, kiedy pierwotnie napisano odpowiedź, ale mogłem się mylić. Niestety ze względu na moją okoliczność roboczą od kilku lat stosuję perforację, więc nie mogę teraz potwierdzić jej dokładności.
Grant Limberg,
6
Lub zamiast dwóch ostatnich kroków: git stash branch new-branch
rethab
1
skrytka
Kiedy masz już istniejącą gałąź, w której chcesz umieścić wszystkie swoje rzeczy, ukrywanie ma dla mnie sens: (w końcu git fetch --all; aby uzyskać zdalną gałąź w miejscu pochodzenia) git stash; git checkout <istniejąca gałąź>; zastosowanie git stash;
Paolof76
24

Dwie rzeczy, które możesz zrobić:

git checkout -b sillyname
git commit -am "silly message"
git checkout - 

lub

git stash -u
git branch sillyname stash@{0}

( git checkout -<- myślnik to skrót do poprzedniej gałęzi, w której byłeś)

( git stash -u<- -uoznacza, że ​​przyjmuje również zmiany nieetapowane)

Pylinux
źródło
7

Jeśli używasz klienta GitHub dla systemu Windows (tak jak ja) i jesteś w sytuacji, gdy dokonałeś niezatwierdzonych zmian, które chcesz przenieść do nowego oddziału, możesz po prostu „utworzyć nową gałąź” za pomocą klienta GitHub. Przejdzie do nowo utworzonego oddziału i zachowa twoje zmiany.

wprowadź opis zdjęcia tutaj

Tod Birdsall
źródło
który ukrywa zmiany przed utworzeniem nowego oddziału, więc go nie utrzymuje (wersja 223 na Mac OS)
Fernando Gallego
2

Jeśli chcesz, aby bieżące niezatwierdzone zmiany w bieżącej gałęzi zostały przeniesione do nowej gałęzi, użyj następującego polecenia, aby utworzyć nową gałąź i skopiować automatycznie niezatwierdzone zmiany.

git checkout -b branch_name

Spowoduje to utworzenie nowej gałęzi z bieżącej gałęzi (zakładając, że jest ona główną), skopiowanie nieprzewidzianych zmian i przejście do nowej gałęzi.

Zatwierdź zmiany w nowym oddziale.

git commit -m "First commit"

Ponieważ tworzony jest nowy oddział, przed wypchnięciem go do zdalnego, musisz ustawić upstream. Użyj poniższego polecenia, aby ustawić wysyłanie i wypchnij go na zdalne.

git push --set-upstream origin feature/feature/NEWBRANCH

Po naciśnięciu tego polecenia na oddziale zostanie utworzona nowa gałąź, a nowa gałąź lokalna zostanie przekazana na odległość.

Teraz, jeśli chcesz wyrzucić swoje niezaangażowane zmiany z gałęzi master, użyj:

git checkout master -f

Spowoduje to odrzucenie wszelkich niezatwierdzonych lokalnych zmian przy kasie.

Politycznie niezależny
źródło
Czym różni się ta odpowiedź od przyjętej?
kometen
Chociaż w pewnym stopniu pokrywają się z przyjętą odpowiedzią, zapewnia to prosty przewodnik krok po kroku, a także obejmuje operacje wymagane do zdalnego wypchnięcia nowego oddziału. Prosty, przejrzysty i użyteczny.
Kjartan
Ta odpowiedź jest jasna i bardzo mi pomogła.
Vadim
0

W najnowszym kliencie GitHub dla systemu Windows , jeśli dokonałeś niezatwierdzonych zmian i zdecydowałeś się utworzyć nowy oddział.
Podpowiedzi, jak poradzić sobie z tym dokładnie scenariuszem:

wprowadź opis zdjęcia tutaj

To samo dotyczy, jeśli po prostu zmienisz także gałąź.

Jerry Dodge
źródło