Czy możliwe jest wypchnięcie skrytki git do zdalnego repozytorium?


205

Czy w git można utworzyć skrytkę, przepchnąć skrytkę do zdalnego repozytorium, pobrać skrytkę na innym komputerze i zastosować skrytkę?

Lub są moje opcje:

  • Utwórz poprawkę i skopiuj ją na inny komputer lub
  • Utworzyć mniejszy oddział i przekazać niepełną pracę do tego oddziału?

Odpowiedzi:


68

Nie jest możliwe uzyskanie go za pomocą pobierania, tak więc lustrzany refspec jest fetch = +refs/*:refs/*, i chociaż ukryty refs/stashnie jest wysyłany. Wyraźne też refs/stash:refs/stashnie ma wpływu!

Byłoby to i tak mylące, ponieważ nie przyniosłoby to wszystkich skrytek, tylko najnowszego; lista skrytek jest dziennikiem ref refs/stashes.


4
Możesz pobrać najnowszą skrytkę z pilota git, ale nie do skrytki, tylko do innego ref. Coś jak . Ale nie możesz dostać starszych skrytek, ponieważ są one przechowywane w rejestrze, którego nie można pobrać. Zobacz stackoverflow.com/questions/2248680/…git fetch some-remote +refs/stash:refs/remotes/some-remote/stashgit stash apply some-remote/stash
sj26,

75

Uwaga: Właśnie przepisałem tę odpowiedź z 24 godzinami więcej git-fu pod moim pasem :) W mojej historii muszli cały shebang ma teraz trzy jednoliniowe. Jednak dla waszej wygody odłączyłem je.

W ten sposób mam nadzieję, że będziesz mógł zobaczyć, jak to zrobiłem, zamiast po prostu ślepo kopiować / wklejać rzeczy.


Oto krok po kroku.

Załóżmy, że jest źródłem w ~ / OLDREPO zawierającym skrytki. Utwórz klon TESTOWY bez żadnych skrytek:

cd ~/OLDREPO
git clone . /tmp/TEST

Wciśnij wszystkie skrytki jako gałęzie tymczasowe:

git send-pack /tmp/TEST $(for sha in $(git rev-list -g stash); \
    do echo $sha:refs/heads/stash_$sha; done)

Pętla na końcu odbiorczym przekształca się z powrotem w skrytki:

cd /tmp/TEST/
for a in $(git rev-list --no-walk --glob='refs/heads/stash_*'); 
do 
    git checkout $a && 
    git reset HEAD^ && 
    git stash save "$(git log --format='%s' -1 HEAD@{1})"
done

Oczyść swoje tymczasowe oddziały, jeśli chcesz

git branch -D $(git branch|cut -c3-|grep ^stash_)

Zrób listę skrytek git, a będziesz coś takiego:

stash@{0}: On (no branch): On testing: openmp import
stash@{1}: On (no branch): On testing: zfsrc
stash@{2}: On (no branch): WIP on sehe: 7006283 fixed wrong path to binary in debianized init script (reported as part of issue
stash@{3}: On (no branch): WIP on debian-collab: c5c8037 zfs_pool_alert should be installed by default
stash@{4}: On (no branch): WIP on xattrs: 3972694 removed braindead leftover -O0 flag
stash@{5}: On (no branch): WIP on testing: 3972694 removed braindead leftover -O0 flag
stash@{6}: On (no branch): WIP on testing: db9f77e fuse_unmount_all could be starved for the mtx lock
stash@{7}: On (no branch): WIP on xattrs: db9f77e fuse_unmount_all could be starved for the mtx lock
stash@{8}: On (no branch): WIP on testing: 28716d4 fixed implicit declaration of stat64
stash@{9}: On (no branch): WIP on emmanuel: bee6660 avoid unrelated changes

W oryginalnym repozytorium wyglądało to samo

stash@{0}: WIP on emmanuel: bee6660 avoid unrelated changes
stash@{1}: WIP on testing: 28716d4 fixed implicit declaration of stat64
stash@{2}: WIP on xattrs: db9f77e fuse_unmount_all could be starved for the mtx lock
stash@{3}: WIP on testing: db9f77e fuse_unmount_all could be starved for the mtx lock
stash@{4}: WIP on testing: 3972694 removed braindead leftover -O0 flag
stash@{5}: WIP on xattrs: 3972694 removed braindead leftover -O0 flag
stash@{6}: WIP on debian-collab: c5c8037 zfs_pool_alert should be installed by default
stash@{7}: WIP on sehe: 7006283 fixed wrong path to binary in debianized init script (reported as part of issue #57)
stash@{8}: On testing: zfsrc
stash@{9}: On testing: openmp import

1
Dużo się uczę w krótkim czasie i wydaje mi się, że prawdopodobnie powinienem po prostu użyć wielu poleceń w moim wcześniejszym podejściu, co postaram się zrobić później.
dniu

9
Działa to dla mnie dobrze, z wyjątkiem tego, że potrzebowałem git add .wcześniej, git stash save ...ponieważ git stashodmawia przechowywania nowych plików, chyba że zostały one ustawione. Ponadto, przesyłanie wyników git rev-list ...przez tacprzelot odwraca kolejność skrytek, aby wychodziły w tej samej kolejności.
Alan Krueger,

1
@sehe Excellent script !! Dwie sugestie: 1) - odwróć ostatnią listę referencyjną, aby składy były w tej samej kolejności w repozytorium docelowym jak w oryginale. 2) Zakończ ostatnią forpętlę za pomocą git branch -D stash_$a(posprzątaj, gdy tworzone są skrytki), aby jeśli coś poszło nie tak i spróbujemy ponownie, nie przetwarzamy ponownie zatwierdzeń, które zostały pomyślnie zablokowane.
Keith Robertson,

1
Dziękuję bardzo za poświęcenie czasu na wyjaśnienie tego, co zrobiłeś, zamiast „tylko opublikowania rozwiązania”.
Marjan Venema

1
Rozwiązanie można jeszcze ulepszyć: jeśli zastąpisz git stash save "$(git log --format='%s' -1 HEAD@{1})"go git update-ref --create-reflog -m "$(git show -s --format=%B $rev)" refs/stash $rev, otrzymasz oryginalną wiadomość skrytki ( update-refjest to git stash saveza kulisami).
Sebastian Schrader

31

Jestem trochę spóźniony na imprezę, ale wydaje mi się, że znalazłem coś, co dla mnie działa w tej sprawie i może również dla ciebie, jeśli twoje okoliczności są takie same lub podobne.

Pracuję nad funkcją w jej własnym oddziale. Oddział nie jest połączony w master i nie jest wysyłany, dopóki nie zostanie ukończony lub nie wykonam zobowiązań, które czuję się komfortowo, pokazując je publicznie. Tak więc, co robię, gdy chcę przenieść zmiany niestacjonarne na inny komputer:

  • Dokonaj zatwierdzenia za pomocą komunikatu zatwierdzenia, takiego jak „ [non-commit] FOR TRANSFER ONLY”, zawierającego treść, którą chcesz przenieść.
  • Zaloguj się do innego komputera.
  • Następnie wykonaj:

    git pull ssh+git://<username>@<domain>/path/to/project/ rb:lb

    Adres URL może się dla Ciebie różnić, jeśli uzyskasz dostęp do swojego repozytorium w inny sposób. Spowoduje to pobranie zmian z tego adresu URL ze zdalnej gałęzi „rb” do lokalnej gałęzi „lb”. Zauważ, że mam serwer ssh działający na moim komputerze i mogę w ten sposób uzyskać dostęp do repozytorium.

  • git reset HEAD^(implikuje --mixed)

    Spowoduje to zresetowanie HEAD, aby wskazywał stan przed zatwierdzeniem „[brak zatwierdzenia]”.

Z git-reset (1): „ --mixed: Resetuje indeks, ale nie działające drzewo (tzn. Zmienione pliki są zachowane, ale nie są oznaczone do zatwierdzenia) [...]”

Więc na końcu będziesz mieć zmiany w plikach, ale żadne masteringi nie zostaną zatwierdzone i nie będziesz potrzebował skrytki.

Będzie to jednak wymagać od ciebie git reset --hard HEAD^w repozytorium, w którym dokonałeś „[non-commit]”, ponieważ to zatwierdzenie jest śmieciem.


Jest to o wiele bardziej brudne niż tworzenie nowej gałęzi funkcji, a następnie usuwanie jej później ...
Taegost

@Taegost zależy od twojego środowiska. Może to być niektóre elementy CI / CD, które uniemożliwiają po prostu pchanie gałęzi wcześniej willy nie chcąc. Ale tak, w zależności od tego, co wolisz, możesz po prostu utworzyć gałąź, aby osiągnąć to samo.
Victor Zamanian

22

Jest trochę późno, ale ta odpowiedź może komuś pomóc. Chciałem to wiedzieć, ponieważ chciałem móc przesyłać trwającą funkcję / błąd / cokolwiek i pracować z tego samego miejsca na innym komputerze.

To, co działa dla mnie, to zatwierdzenie mojego kodu w toku (w gałęzi, nad którą pracuję sam). Kiedy dojdę do drugiego komputera, pociągnij, a następnie cofnij zatwierdzenie za pomocą:

git reset --soft HEAD^

Kontynuuj pracę tak, jak byłeś, ze wszystkimi wprowadzanymi zmianami, niezaangażowanymi i nieopartymi na scenach.

Mam nadzieję, że to pomoże.


Kiedy próbuję to zrobić, Origin nadal utrzymuje Commit, co nie zostało zatwierdzone. Blisko, ale dla mnie nie cygaro.
rezwits

@rezwits Tak, pilot go zachowuje, ale wystarczy łatwo usunąć tymczasową gałąź z początku.
Sir Robert,

w rzeczywistości to właśnie robiłem!
rezwits

19

Wydaje się, że istnieje bardzo fajna sztuczka, aby rozwiązać ten problem. możesz użyć git diff > file.diff(i zatwierdzić plik), a następnie przywrócić zmiany za pomocą git apply file.diff(z dowolnego miejsca), aby osiągnąć ten sam wynik.

Wyjaśniono to również tutaj .


5
jeśli masz nieśledzone pliki: 1. git add. 2. git diff HEAD> file.diff
trickpatty 13.09.17

Przesłanie do siebie diff nie pozwala na żadne zatwierdzenia / ślad na repo! (np .: Note-to-self za pośrednictwem aplikacji komputerowej Signal) lub e-mailem.
John Mee

9

Postawiłbym na drugie podejście, chociaż nie mam pojęcia, dlaczego nie można przypisać go do gałęzi master / featured. Można również zbierać wiśnie.


27
Nie ma technicznego powodu, aby nie zatwierdzać master / featured, po prostu chcę powiedzieć: „To nie jest prawdziwe zatwierdzenie, to po prostu zapisywanie mojej pracy, dzięki czemu mogę dostać ją na inną maszynę”.
Andrew Grimm,

4

AFAIK cała idea skrytki polega na ukryciu czegoś nie tak ważnego pod lokalnym dywanem. Nikt nie powinien wiedzieć o twoim ulubionym gównie ;-) Jedyne „ale” to: Ale czy rozwijam się na kilku stacjach roboczych? To scpjest o wiele lepsze.


9
Coś tak zabawnego powinno być komentarzem. ;-)
Andrew Grimm,

2
Całkowity git-ssh-newbie tutaj, ale czy możesz używać scp z github?
Koen,

Nie, interfejs git-ssh github jest zaprogramowany, więc nigdy nie masz powłoki / konsoli ssh. Może uruchamiać tylko proces git po stronie serwera.
argent_smith

1
Więc scp nie jest tak naprawdę opcją dla tego scenariusza, jeśli twoja główna gałąź znajduje się na github? Czy są jeszcze jakieś sugestie dotyczące przeniesienia skrytki?
Koen,

1
Próbowałem podkreślić, że przeniesienie skrytki wcale nie jest możliwe, AFAIK.
argent_smith

2

Obecnie akceptowane odpowiedź jest technicznie poprawne, nie można bezpośrednio powiedzieć Git naciskać wszystkie stashes na pilocie, a następnie wyciągnąć wszystko do lokalnych stashes na innym komputerze.

I chociaż aktualnie głosowana odpowiedź powinna działać, nie podobało mi się, że tworzy ona kilka tymczasowych gałęzi i że wymaga ręcznego sprawdzenia zatwierdzenia skrytki i zapisania jej jako skrytki, co może prowadzić do problemów takich jak ten komentarz wspomniane i prowadzi do duplikatu On (no branch): On testing:. Z pewnością musi być lepszy sposób!

Tak więc, chociaż nie możesz bezpośrednio wypychać skrytek, skrytka jest tylko zatwierdzeniem (w rzeczywistości dwa zatwierdzenia), a na git pushstronie podręcznika możesz wypychać zatwierdzenia:

<src>Jest często nazwa oddziału, co chcesz do pchania, ale może to być dowolny arbitralny „SHA-1 wyrażenie” ...

Zdecydowałem się popchnąć skrytki, aby refs/stashes/*nie zaśmiecać pilota dodatkowymi gałęziami. Więc mogę to zrobić za pomocą:

git push origin stash@{0}:refs/stashes/$(git rev-parse --short stash@{0})

( rev-parsePolecenie pobiera krótki skrót skrytki, który będzie unikalny dla repozytorium).

Następnie muszę pobrać skrytkę z drugiego komputera. Git domyślnie pobiera tylko gałęzie, więc muszę pobrać skrytki konkretnie:

git fetch origin refs/stashes/*:refs/stashes/*

Teraz, aby przekonwertować zatwierdzenie skrytki z powrotem na rzeczywistą skrytkę. Jak już wspomniano, chociaż mógłbym po prostu sprawdzić, jak zwykle zatwierdzić, zresetować i ukryć skrytkę, nie podoba mi się, że wymaga dodatkowych kroków lub że może nie utrzymywać stanu indeksu dla skrytki. Szukałem w Internecie sposobu na zrobienie tego automatycznie, ale zawiodło mnie moje wyszukiwanie. W końcu przejrzałem stronę man git stash, gdzie znalazłem to:

utwórz
Utwórz skrytkę (która jest zwykłym obiektem zatwierdzania) i zwróć nazwę tego obiektu, bez przechowywania go w dowolnym miejscu w przestrzeni nazw ref. Ma to być przydatne w skryptach. Prawdopodobnie nie jest to polecenie, którego chcesz użyć; patrz „zapisz” powyżej.

store
Przechowuj dane skrytki utworzone za pomocą git stash create (czyli wiszące zatwierdzenie scalania) w skrytce, aktualizując dziennik skrytki. Ma to być przydatne w skryptach. Prawdopodobnie nie jest to polecenie, którego chcesz użyć; patrz „zapisz” powyżej.

Ponieważ mam już zatwierdzenie, storebrzmi jak to, czego chcę. Więc mogę zrobić:

git stash store --message "$(git show --no-patch --format=format:%s <SHA>)" <SHA>

Zastąpienie <SHA>skrytką, która właśnie została pobrana.

( git showPolecenie pobiera komunikat zatwierdzenia z zatwierdzenia ukrytego, aby użyć go jako komunikatu do dziennika ukrytego.)

Skrytka pokazuje się teraz normalnie w moim lokalnym repozytorium:

$ git stash list
stash@{0}: On master: temp
...

Aby wyczyścić pilota, skrytki można usunąć z pilota w następujący sposób:

git push origin :refs/stashes/<SHA>

Ta metoda ma tę zaletę, że jest idempotentna: jeśli pushponownie uruchomisz polecenie, zgłosi to Everything up-to-date. fetchKomenda może być również bezpiecznie uruchamiać wielokrotnie. Chociaż stash storepominie przechowywanie skrytki, jeśli jest taka sama jak najnowsza skrytka, nie zapobiega duplikatom starszych skrytek. Można to obejść, tak jak w moim git-rstashskrypcie, patrz poniżej.


Aby zakończyć, możesz również z łatwością wepchnąć wszystkie skrytki (za pomocą ):

for i in $(seq 0 $(expr $(git rev-list --walk-reflogs --count stash) - 1))
do
  git push origin stash@{$i}:refs/stashes/$(git rev-parse --short stash@{$i})
done

lub zaimportuj wszystkie pobrane skrytki:

for stash in $(ls .git/refs/stashes)
do
  git stash store --message "$(git show --no-patch --format=format:%s $stash)" $stash
done

Stworzyłem skrypt, który można wywołać jako podkomendę (np. git rstash push 0), więc nie muszę pamiętać tego wszystkiego. git-rstashmożna znaleźć tutaj.


1

Poniższe nie działa z ukrytą skrzynką, ale z niezatwierdzonymi zmianami w reż. Tworzy gałąź, automatycznie zatwierdza wszystkie bieżące zmiany i przesyła do pilota:

commit_and_push_ ( ) {
    # This will:
    #  1. checkout a new branch stash-XXX
    #  2. commit the current changes in that branch
    #  3. push the branch to the remote
    local locbr=${1:-autostash-XXX}
    git checkout -b $locbr
    git add .
    git commit -a -m "Automatically created commit"
    git push origin $locbr
    echo "Autocommitted changes in branch $locbr ..."
}

Użyj jak:

commit_and_push_ my-temp-branch
commit_and_push_

0

Chciałbym po prostu utworzyć nową gałąź ukryć i usunąć, gdy gałąź ta nie jest wymagana.

git add . // Add work-in-progress job
git checkout -b stash-branch // Create and checkout to stash-branch
git commit -m 'WIP: job description' // Commit message
git push origin stash-branch // Push to remote
git pull origin stash-branch // Pull the stash-branch
git checkout master // Checkout to working branch
git rebase stash-branch // Rebase the stash-branch
git reset --soft // Equivalent to stash!!
git branch -d stash-branch // Delete when not needed from local
git push -d origin stash-branch // Delete when not needed from remote

-9

Po prostu użyj Dropboksa tak jak ten facet. W ten sposób nie musisz się martwić o wypychanie skrytek, ponieważ utworzono kopię zapasową całego kodu.

http://blog.sapegin.me/all/github-vs-dropbox


2
Zanim ktokolwiek zareaguje gwałtownie, nie mówię, aby używać Dropbox zamiast Github, ale przechowywać kod, który nie jest gotowy na zatwierdzenie w Dropbox, który nadal byłby pod kontrolą wersji lokalnie.
Inżynier NYC Tech,

4
skopiowanie całego projektu do zdalnej chmury zajmie zbyt wiele czasu.
Stav Alfi,
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.