Ukrywanie tylko niestopionych zmian w Git


229

Chciałbym wykonać następujący przepływ pracy:

  1. Dodaj zmiany do stołu montażowego.
  2. Ukryj wszystkie inne zmiany, które nie zostały wprowadzone.
  3. Wykonuj niektóre czynności na etapach (np. Buduj, uruchamiaj testy itp.)
  4. Zastosuj skrytkę.

Czy istnieje sposób na wykonanie kroku 2?

Przykład

 echo "123" > foo
 git add foo # Assumes this is a git directory
 echo "456" >> foo
 git stash
 cat foo # Should yield 123

Dlaczego nie zatwierdzić zmian po ich wystawieniu?
Shizzmo,

3
IIRC --keepindex robi dokładnie to
patrz

4
Ponieważ, powiedzmy, kompilacja nie powiedzie się, nie chcę tego zatwierdzać. Wiem, że mogę usunąć zatwierdzenie, ale chciałbym to zrobić bez zatwierdzenia, jeśli to możliwe.
Unapiedra

Dziękuję. Mogę potwierdzić, że to działa. Ojej, spojrzałem na instrukcję linux.die.net/man/1/git-stash, która jest nieaktualna. man git stashjest znacznie lepszy.
Unapiedra

to --keep-index, fwiw.
jaf0

Odpowiedzi:


288

git stash savema opcję, --keep-indexktóra robi dokładnie to, czego potrzebujesz.

Więc biegnij git stash save --keep-index.


9
Prawdziwe. I nadal korzystać savez git stash. Być może to programista we mnie nalega na uhonorowanie symetrii aplikacją / popem. :)
vhallac

104
Uwaga: nadal skrywa wszystkie twoje zmiany; jedyną różnicą w porównaniu ze zwykłymi git stash savejest to, że pozostawia już wprowadzone zmiany również w kopii roboczej. W powyższym przepływie pracy działałoby to dobrze, ponieważ po prostu nakładasz ukrytą kopię na lokalną kopię, która ma już połowę zmian ukrytych (który git jest wystarczająco inteligentny, aby zignorować). Ale jeśli edytujesz kod przed ponownym zastosowaniem skrytki, możesz potencjalnie zobaczyć konflikty scalania po przejściu do zastosowania. Fyi.
peterflynn

2
@ytpete That ugryzł mnie tyle razy. Naprawdę żałuję, że nie było sposobu, aby git ukrywał tylko to, czego nie przechowujesz ... Często popełniam różne rzeczy, a potem robię pełny zapas git, wiedząc, że mogę, git commit --ammendjeśli są problemy z tym, co popełniłem.
rjmunro

1
--amend(raczej niż --ammend)
Rhubbarb

19
To rozwiązanie nie działa dla mnie z powodu problemów opisanych przez peterflynn. To nie jest dobra odpowiedź na pytanie, ponieważ wciąż ukrywa zmiany etapowe. Czy ktoś ma lepsze rozwiązanie?
user643011,

43

Można to zrobić w 3 krokach: zapisz zmiany etapowe, ukryj wszystko inne, przywróć indeks ze zmianami stopniowymi. Co jest w zasadzie:

git commit -m 'Save index'
git stash push -u -m 'Unstaged changes and untracked files'
git reset --soft HEAD^

To zrobi dokładnie to, co chcesz.


3
Uwaga: -uukrywa także nieśledzone pliki.
ma11hew28,

To podejście w zasadzie powiela to, co git stash save --keep-indexprzy znacznie większej ilości pracy. Nie widzę żadnych korzyści.
Inigo

1
@vas Nie, podejście tego nie powiela. Zobacz komentarz peterflynn do zaakceptowanej odpowiedzi.
Alexander Klauer

28
git stash save --keep-index

Ponadto Re:

Dlaczego nie zatwierdzić zmian po ich wystawieniu? - Piszczel

Odp .: Ponieważ zawsze powinieneś sprawdzać testowany kod :) Oznacza to, że musisz uruchamiać testy tylko ze zmianami, które zamierzasz zatwierdzić

Wszystko to poza tym, że jako doświadczony programista masz wrodzoną potrzebę testowania i przeglądu tylko tych zmian - tylko częściowo żartuje


14

Z git version 2.7.4tobą możesz zrobić:

git stash save --patch

gitPoprosi, aby dodać lub nie zmiany w zapasach.
I wtedy po prostu odpowiadasz ylubn

Możesz przywrócić katalog roboczy, jak zawsze to robisz:

git stash pop

lub, jeśli chcesz zachować zapisane zmiany w skrytce:

git stash apply

To jest niesamowite. Jest to trochę pracochłonne, ale przynajmniej możesz pominąć i dodać całe pliki.
Dustin Oprea

5

Rozszerzając poprzednie odpowiedzi, czasami mam złożony zestaw zmian, ale najpierw chcę wprowadzić osobną zmianę. Na przykład mogłem zauważyć błąd lub inny niepoprawny kod, który chciałbym naprawić przed wprowadzonymi zmianami. Jedną z możliwych tras jest:

najpierw przechowuj wszystko, ale pozostaw zmiany bez zmian

$ git stash save --keep-index [--include-untracked]

teraz osobno przechowuj zmiany etapowe

$ git stash save

wprowadź zmiany w celu naprawy; i test; popełnij je:

$ git add [--interactive] [--patch]

$ git commit -m „fix ...”

teraz przywróć wcześniej wprowadzone zmiany:

$ git stash pop

rozwiąż wszelkie konflikty i zwróć uwagę, że jeśli wystąpiły konflikty, git zastosuje, ale nie upuści tego górnego wpisu.

(... Następnie zatwierdź zmiany etapowe, przywróć skrytkę wszystkich pozostałych zmian i kontynuuj ...)


4

Aby dodać nieoznaczone (nie dodane do zatwierdzenia) pliki do ukrycia, uruchom następującą komendę:

git stash -k

Następnie możesz zatwierdzić pliki etapowe. Następnie możesz odzyskać ostatnio przechowywane pliki za pomocą polecenia:

git stash pop

4

Przechowywanie tylko działającego drzewa (zmiany nieetapowane) w Git jest trudniejsze niż powinno. Zaakceptowana odpowiedź ukrywa zmiany etapowe , ale także ukrywa zmiany etapowe (i pozostawia je również etapowe), co rzadko jest tym, czego chcesz.

Ten alias działa dobrze:

stash-working = "!f() { \
  git commit --quiet -m \"temp for stash-working\" && \
  git stash push \"$@\" && \
  git reset --quiet --soft HEAD~1; }; f"

To dopuszcza się tymczasowo wystawił zmian, tworzy zapas z pozostałych zmian (i pozwala na dodatkowe argumenty jak --include-untrackedi --messagebyć przekazywane jako argumenty alias), a następnie resetuje tymczasowy popełnić odzyskać wystawił zmian.

Jest ona podobna do @Simon Knapp za odpowiedź , ale z kilkoma różnicami drobne - korzysta --quietna tymczasowych podjętych działań i przyjmuje dowolną liczbę parametrów na zapas push, zamiast ciężko kodowania -m, a nie dodawać --softdo finału zresetować, aby indeks pozostał na początku.

W przypadku odwrotnego problemu ukrywania tylko zmian etapowych (alias stash-index) zobacz tę odpowiedź .


2

Kolejna wskazówka związana z pytaniem:

Kiedy skutecznie ukrywasz swoje nieetapowane zmiany za pomocą

$ git stash save --keep-index

możesz chcieć przekazać skrytce wiadomość, aby kiedy zrobiłaś git stash list, bardziej oczywiste jest to, co ukryłeś wcześniej, szczególnie jeśli wykonasz tę operację skrytki przez kolejne zapisy. Na przykład

$ git stash save --keep-index „zmiany jeszcze nie zostały wprowadzone”

(chociaż tak naprawdę zawiera wszystkie zmiany, jak wspomniano w innych odpowiedziach).

Na przykład po powyższym można natychmiast wprowadzić:

$ git stash zapisz „zmiany etapowe dla funkcji X”

Uważaj jednak, że nie możesz wtedy użyć

$ git stash Apply „stash @ {1}” ### ✘ nie robi dokładnie tego, co chcesz

aby przywrócić tylko niestabilne zmiany.


2

Git nie ma polecenia, które skrywa tylko twoje niesceniczne zmiany.

Git pozwala jednak określić, które pliki chcesz ukryć.

git stash push --message 'Unstaged changes' -- app/controllers/products_controller.rb test/controllers/products_controller_test.rb

Jeśli chcesz ukryć tylko określone zmiany w tych plikach, dodaj --patchopcję.

git stash push --patch --message 'Unstaged changes' -- app/controllers/products_controller.rb test/controllers/products_controller_test.rb

Ta --include-untrackedopcja umożliwia przechowywanie nieśledzonych plików.

git stash push --include-untracked --message 'Untracked files' -- app/controllers/widgets_controller.rb test/controllers/widgets_controller_test.rb

Uruchom git help stash(lub man git-stash), aby uzyskać więcej informacji.

Uwaga: jeśli twoje zmiany niestacjonarne są raczej zdezoganizowane, odpowiedź @ alesguzik jest prawdopodobnie łatwiejsza.


0

Współczesna forma tego polecenia jest git stash push [--] [<pathspec>...], ponieważ Git 2.16+ ( git stash savejest przestarzały )

Możesz to połączyć z formularzem wieloznacznym, na przykład:

git stash push --all --keep-index ':(glob)**/*.testextension' 

Ale to nie działa dobrze z Git dla Windows, dopóki Git 2.22 (Q2 2019), patrz problem 2037 , biorąc pod uwagę, że git stashzostał ponownie zaimplementowany w C (zamiast skryptu powłoki)

Zobacz commit 7db9302 (11 marca 2019 r.) Autor: Thomas Gummerer ( tgummerer) .
Zobacz zatwierdzenie 1366c78 , zatwierdzenie 7b556aa (07 marca 2019) przez Johannes Schindelin ( dscho) .
(Połączone przez Junio ​​C Hamano - gitster- w commit 0ba1ba4 , 22 kwietnia 2019)

wbudowany stash: :(glob)ponownie obsługuje specyfikacje ścieżek

Przekazując listę parametrów ścieżki, powiedzmy, git addmusimy zachować ostrożność, używając oryginalnego formularza, a nie parsowanej formy parametrów ścieżki.

To robi różnicę, np. Podczas połączenia

git stash -- ':(glob)**/*.txt'

gdzie oryginalny formularz zawiera :(glob)prefiks, a parsowany formularz nie.

Jednak we wbudowanym git stashformularzu przekazaliśmy przeanalizowany (tj. Niepoprawny) formularz i git addnie powiedzie się komunikat o błędzie:

fatal: pathspec '**/*.txt' did not match any files

na etapie, w którym git stashupuszcza zmiany z drzewa roboczego, nawet jeśli refs/stashfaktycznie zostało pomyślnie zaktualizowane.


0

Używam aliasu, który akceptuje ciąg znaków jako wiadomość do wpisu ukrytego.

mystash = "!f() { git commit -m hold && git stash push -m \"$1\" && git reset HEAD^; }; f"

Który:

  • zatwierdza wszystko w indeksie,
  • ukrywa to, co zostało zmienione w działającym drzewie (można oczywiście dodać -ulub -a),
  • resetuje ostatnie zatwierdzenie z powrotem do działającej próby (może chcieć użyć, --softaby zachować go w indeksie).
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.