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.