Czy „git pull” może automatycznie ukrywać i wstawiać oczekujące zmiany?


122

Wiem, jak to rozwiązać:

user@host$ git pull
Updating 9386059..6e3ffde
error: Your local changes to the following files would be overwritten by merge:
    foo.bar
Please, commit your changes or stash them before you can merge.
Aborting

Ale czy nie ma sposobu, by pozwolić git pullmi tańczyć stashi poptańczyć?

Jeśli to polecenie ma inną nazwę, jest w porządku.

Utworzenie aliasu powłoki dla git stash; git pull; git stash popjest rozwiązaniem, ale szukam lepszego rozwiązania.


a co z aliasem git ?
Яois

20
Uruchamianie git stash; git pull; git stash popprogramowe jest niebezpieczne, ponieważ jeśli nie ma nic do ukrycia, git stashnie będzie to możliwe, ale git stash popwyrzuci ostatnią skrytkę (jeśli w ogóle), co prawie na pewno nie jest tym, czego chcesz. Użytkownik torek ma świetny post na ten temat w Stack Overflow, ale nie mogę go znaleźć ...
jub0bs


1
@guettli Nie sugerowałem, że twoje pytanie jest duplikatem, właśnie odpowiadałem na komentarz Jubobsa.
VonC

2
Jako krok dalej, operacja powinna zakończyć się sukcesem tylko wtedy, gdy schowek może być czysto nałożony po pociągnięciu. Jeśli występują konflikty, cała operacja kończy się niepowodzeniem, więc drzewo nie jest zmieniane. Oto, co chciałbym zrobić: albo ściągnij zmiany z połączonymi lokalnymi, albo nie powiedzie się z błędem i pozwól mi ręcznie zdecydować, co robić dalej. Czy taka „transakcja” jest możliwa?
Ed Avis

Odpowiedzi:


185

Git 2.6+ (wydany 28 września 2015 r.)

Plik tylko git config ustawienie, które mogłoby być interesujące, to:

rebase.autoStash

(z Git 2.27, Q2 2020, masz teraz również merge.autostash, patrz poniżej)

Gdy ma wartość true, automatycznie tworzy tymczasowy magazyn przed rozpoczęciem operacji i stosuje go po zakończeniu operacji.
Oznacza to, że możesz uruchomić rebase na brudnym drzewie roboczym.

Należy jednak zachować ostrożność: ostatnia aplikacja skrytki po pomyślnym ponownym uruchomieniu może spowodować nietrywialne konflikty. Domyślnie false.

połącz to z:

pull.rebase

Gdy prawda, rebase rozgałęzia się na górze pobranej gałęzi, zamiast scalać domyślną gałąź z domyślnego pilota po uruchomieniu „git pull”.

git config pull.rebase true
git config rebase.autoStash true

To wystarczyłoby, aby prosty git pulldo pracy nawet na brudnym drzewie.
W takim przypadku alias nie jest potrzebny.


Zobacz commit 53c76dc (04 lipca 2015) autorstwa Kevina Daudta ( Ikke) .
(Scalone przez Junio ​​C Hamano - gitster- w zatwierdzeniu e69b408 , 17 sierpnia 2015)

pull: zezwala na brudne drzewo, gdy jest rebase.autostashwłączone

rebase nauczył się ukrywać zmiany, gdy napotka brudne drzewo pracy, ale git pull --rebasetego nie robi.

Sprawdź tylko, czy drzewo robocze jest brudne, gdy rebase.autostashnie jest włączone.


Uwaga: jeśli chcesz pobierać bez autostashu (nawet jeśli rebase.autoStash truejest ustawiony), masz od wersji 2.9 (czerwiec 2016):

 pull --rebase --no-autostash

Zobacz commit 450dd1d , commit 1662297 , commit 44a59ff , commit 5c82bcd , commit 6ddc97c , commit eff960b , commit efa195d (02 kwietnia 2016) i commit f66398e , commit c48d73b (21 marca 2016) przez Mehul Jain ( mehul2029) .
(Scalone przez Junio ​​C Hamano - gitster- w zatwierdzeniu 7c137bb , 13 kwietnia 2016 r.)

Commit f66398e obejmuje w szczególności:

pull --rebase: dodaj --[no-]autostashflagę

Jeśli rebase.autoStashzmienna konfiguracyjna jest ustawiona, nie ma możliwości zastąpienia jej dla " git pull --rebase" z wiersza poleceń.

Naucz " git pull --rebase" --[no-]autostashflagi linii poleceń, która zastępuje bieżącą wartość rebase.autoStash, jeśli jest ustawiona. Ponieważ " git rebase" rozumie tę --[no-]autostashopcję, chodzi tylko o przekazanie opcji do bazowego " git rebase" when " git pull --rebase" wywołania.


Ostrzeżenie: przed Git 2.14 (Q3 2017), " git pull --rebase --autostash" nie był automatycznie ukrywany, gdy lokalna historia jest szybko przesyłana do nadawcy.

Zobacz commit f15e7cf (01 czerwca 2017) autorstwa Tyler Brazier ( tylerbrazier) .
(Scalone przez Junio ​​C Hamano - gitster- w zobowiązaniu 35898ea , 05 czerwca 2017 r.)

pull: ff --rebase --autostashdziała w brudnym repozytorium

Kiedy git pull --rebase --autostashw brudnym repozytorium nastąpiło szybkie przewijanie do przodu, nic nie było automatycznie zapisywane, a ściąganie nie powiodło się.
Wynikało to ze skrótu, aby uniknąć uruchamiania rebase, gdy możemy przewinąć do przodu, ale autostash jest ignorowany w tej ścieżce kodu.


Aktualizacja: Mariusz Pawelski zadaje w komentarzach ciekawe pytanie:

Więc wszyscy piszą o tym, autostashkiedy dokonujesz rebase (lub pull --rebase).

Ale nikt nie zajmuje się autostashingiem, gdy wykonujesz normalne ciągnięcie z połączeniami .
Więc nie ma do tego automatycznego przełącznika? Albo coś mi brakuje? Wolę to robić, git pull --rebaseale OP zapytał o „ standardowe ” git pull

Odpowiedź:

Oryginalne nici omówieniem tej autostash funkcji był realizowany zarówno początkowo git pull(scalanie) i git pull --rebase.

Ale ... Junio ​​C Hamano (opiekun Git) zauważył, że:

Gdyby pull-mergebyło coś, co wywołałoby "irytację", która wywołała ten temat, z definicji lokalna zmiana nakłada się na scalanie, a to wewnętrzne "wyskakujące okienko" dotknie ścieżek dotkniętych przez scalanie i prawdopodobnie nie spowoduje to "Porzucono „ale pozostawić dalsze konflikty do rozwiązania.

Podejrzewam, że pull.autostashkonfiguracja nie jest dobrym dodatkiem, ponieważ zachęca do złego, powodującego ból przepływu pracy.
W prostych przypadkach może to nie zaszkodzić, ale gdy lokalne zmiany są złożone, byłoby to bardziej szkodliwe niż ich brak, a konfiguracja pozbawia motywację do wyboru.

Równanie jest nieco inne dla „pull-rebase”, ponieważ „rebase” nalega na rozpoczęcie od czystego drzewa roboczego, więc irytacja „pobierz i zatrzymaj” wydaje się większa. Podejrzewam, że poluzowanie może być bardziej produktywnym rozwiązaniem prawdziwego problemu.

Tak więc, jeśli chodzi o klasyczne łączenie pull-merge, lepiej:

zachęć użytkownika do przemyślenia natury WIP w drzewie roboczym przed uruchomieniem " git pull" .
Czy jest to zbyt złożona bestia, która może przeszkadzać innym, czy też jest to trywialna zmiana, którą może schować i odłożyć z powrotem?

Jeśli to pierwsze, dużo lepiej będzie dla niego " checkout -b", kontynuuj pracę, aż lokalna zmiana przyjmie nieco lepszy kształt i "zatwierdź", zanim przejdzie do oryginalnej gałęzi.

Jeśli to drugie, lepiej zrobić:

  • git pull”,
  • po znalezieniu konfliktu, biegnij
    • git stash,
    • git merge FETCH_HEAD i
    • git stash pop

To powiedziawszy, z Git 2.27 (Q2 2020), " git pull" nauczył się ostrzegać, gdy żadna pull.rebasekonfiguracja nie istnieje i ani --[no-]rebasenie --ff-onlyjest podana (co spowodowałoby scalenie).

Zobacz commit d18c950 (10 marca 2020) autorstwa Alexa Henrie ( alexhenrie) .
(Scalone przez Junio ​​C Hamano - gitster- w zatwierdzeniu 1c56d6f , 27 marca 2020 r.)

pull: ostrzeż, jeśli użytkownik nie powiedział, czy zmienić bazę, czy scalić

Podpisał: Alex Henrie

Często początkujący użytkownicy Gita zapominają powiedzieć „ pull --rebase” i kończą się niepotrzebnym łączeniem ze źródłami.

Zwykle chcą " pull --rebase" albo " " w prostszych przypadkach, albo " pull --ff-only" zaktualizować kopię głównych gałęzi integracji i oddzielnie odtworzyć ich pracę. Zmienna konfiguracja istnieje, aby pomóc im w prostszych przypadkach, ale nie ma mechanizmu, aby ci użytkownicy świadomi.
pull.rebase

Wyświetla komunikat ostrzegawczy, gdy nie ma --[no-]rebaseopcji z wiersza poleceń i nie pull.rebasepodano zmiennej konfiguracyjnej.
Będzie to niewygodne dla tych, którzy nigdy nie chcą " pull --rebase" robić nic specjalnego, ale koszt niedogodności jest płacony tylko raz na użytkownika, co powinno być rozsądnym kosztem, aby pomóc wielu nowym użytkownikom.


W Git 2.27 (Q2 2020) " git merge" uczy się --autostashopcji " " i nowych merge.autostashustawień.

Zobacz popełnić d9f15d3 , popełnić f8a1785 , popełnić a03b555 , popełnić 804fe31 , popełnić 12b6e13 , popełnić 0dd562e , popełnić 0816f1d , popełnić 9bb3dea , popełnić 4d4bc15 , popełnić b309a97 , popełnić f213f06 , popełnić 86ed00a , popełnić facca7f , popełnić be1bb60 , popełnić efcf6cf , popełnić c20de8b , zobowiązać bfa50c2 , commit 3442c3d , commit 5b2f6d9 (07 kwietnia 2020), commit 65c425a(04 kwietnia 2020) i commit fd6852c , commit 805d9ea (21 Mar 2020) by Denton Liu ( Denton-L) .
(Scalone przez Junio ​​C Hamano - gitster- w zobowiązaniu bf10200 , 29 kwietnia 2020 r.)

pull: pass --autostash do scalenia

Podpisał: Denton Liu

Wcześniej --autostashpracował tylko z git pull --rebase.

Jednak w ostatnim patchu nauczyliśmy się --autostashrównież scalania, więc nie ma powodu, dla którego mielibyśmy już mieć to ograniczenie.
Naucz pociągnij, aby przejść, --autostashaby scalić, tak jak w przypadku rebase.

I:

rebase: użyj apply_autostash()z sequencer.c

Podpisał: Denton Liu

apply_autostash()Funkcjonują w builtin/rebase.cpodobny tyle do apply_autostash()funkcji w sequencer.cktóre są one niemal wymienne, z wyjątkiem rodzaju arg akceptują. Utwórz sequencer.cwersję extern i użyj jej w rebase.

Wersja rebase została wprowadzona w 6defce2b02 ("wbudowana rebase: --autostashopcja wsparcia ", 2018-09-04, Git v2.20.0-rc0 - scalanie wymienione w partii nr 8 ) jako część konwersji powłoki na C.
Zdecydował się zduplikować tę funkcję, ponieważ w tamtym czasie istniał inny projekt konwertujący interaktywny rebase z powłoki na C i nie chcieli się z nimi kolidować poprzez refaktoryzację sequencer.cwersji apply_autostash().
Ponieważ oba wysiłki są wykonywane od dawna, możemy je teraz dowolnie łączyć.


W wersji 2.4.2 nie zostało to jeszcze zaimplementowane. Może kiedyś. rebase.autoStashma zastosowanie tylko w przypadku korzystania z rebase. pull.rebasema zastosowanie tylko przy użyciu pull.
Randal Schwartz

„To wystarczy, by zwykłe git pull działało nawet na brudnym drzewie”. Jak zauważył Randal, to jeszcze nie jest prawda. Obecny master's pull.c nadal decyduje die_on_unclean_work_tree.
Pradhan

1
@Pradhan Zgadzam się. Implementacja właśnie dotarła do mastera dziś rano i powinna być gotowa na git 2.6. Zredagowałem odpowiedź, aby to wyjaśnić.
VonC

Potwierdziłem, że autostash działa z git 2.5.5.
Joshua Hoblitt

1
Więc wszyscy piszą o autostashu, kiedy to robisz rebase(lub pull --rebase). Ale nikt nie zajmuje się autostashingiem, gdy robisz coś normalnego pullz połączeniami. Więc nie ma do tego automatycznego przełącznika? Albo coś mi brakuje? Wolę to robić, git pull --rebaseale OP zapytał o "standard"git pull
Mariusz Pawelski

41

Aby zaoszczędzić kilka sekund nadciągającym odkrywcom, oto podsumowanie (dzięki @VonC):

git pull --rebase --autostash

6
Chodzi o to: po git config pull.rebase truei git config rebase.autoStash true, wszystko, czego kiedykolwiek będziesz potrzebować, to git pull. Po prostu git pull. Żadne inne opcje nie są wymagane.
VonC

3
Wygląda na to, że do tej --autostashopcji potrzebujesz co najmniej Git 2.9 . -c rebase.autoStash=truePracuje w dalszej Git 2.6.
ntc2

15

Jak stwierdzono w powyższym komentarzu, ustawienie dwóch wartości konfiguracyjnych obecnie nie działa git pull, ponieważ konfiguracja autostash dotyczy tylko rzeczywistych ponownych baz. Te polecenia git robią, co chcesz:

git fetch
git rebase --autostash FETCH_HEAD

Lub ustaw jako alias:

git config alias.pullr '!git fetch; git rebase --autostash FETCH_HEAD'

Następnie wykonaj:

git pullr

Oczywiście ten alias można dowolnie zmienić.


7

Z Git 2.6+ możesz korzystać z:

alias gup='git -c rebase.autoStash=true pull --rebase'

To --rebasepowoduje użycie git-pull rebasezamiast merge, więc ustawienia / opcje takie jak --ff-onlynie będą miały zastosowania.

--ff-onlyDomyślnie używam aliasu do ściągania ( git pull --ff-only), a następnie mogę użyć gup(od góry) w przypadku, gdy szybkie scalanie do przodu nie jest możliwe lub są zachowane zmiany.


Jaka jest główna różnica między git pull --ff-onlyigit pull pull --rebase --autostash
alper

0

Jak już wspomniałeś, jest to sposób na zrobienie tego. Możesz go używać w aliasie, aby zaoszczędzić na pisaniu i używać skrótu lub możesz użyć go w jednej linii (może to być również alias)

git stash && git pull --rebase && git stash pop

Zrobi to samo, co zrobiłeś, ale w jednej linii (&&), a jeśli ustawisz jako alias, będzie nawet krótszy.

W następnych wierszach zostaną wyświetlone zmiany przychodzące / wychodzące przed pociągnięciem / pchnięciem

git log ^master origin/master
git log master ^origin/master

8
To podejście jest niebezpieczne: jeśli nie ma nic do ukrycia, pierwsze polecenie nic nie da, a następnie stash popusunie kilka losowych rzeczy z wcześniejszych.
John Zwinck

Dla jasności: nawet jeśli git stashnic nie przechowuje, nadal „zwraca” brak kodu błędu, więc && będzie nadal kontynuował git pulli git stash popi pobierze poprzedni plik. Więc lepiej tego nie używaj, chyba że jesteś pewien, że coś skryje!
MoonLite
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.