Apakah mungkin untuk mendorong simpanan git ke repositori jarak jauh?

205

Dalam git, apakah mungkin untuk membuat simpanan, mendorong simpanan ke repositori jarak jauh, mengambil simpanan di komputer lain, dan menerapkan simpanan?

Atau apakah opsi saya:

  • Buat tambalan dan salin tambalan ke komputer lain, atau
  • Buat cabang kecil dan lakukan pekerjaan yang tidak lengkap ke cabang itu?
Andrew Grimm
sumber

Jawaban:

68

Tidak mungkin mendapatkannya melalui fetch atau lebih, mirror refspec adalah fetch = +refs/*:refs/*, dan meskipun simpanannya refs/stashtidak dikirim. Eksplisit refs/stash:refs/stashjuga tidak berpengaruh!

Lagi pula itu akan membingungkan karena itu tidak akan mengambil semua simpanan, hanya yang terbaru; daftar simpanan adalah reflog dari ref refs/stashes.

u0b34a0f6ae
sumber
4
Anda dapat mengambil simpanan terbaru dari git remote, tetapi tidak ke simpanan Anda, hanya ke ref lain. Sesuatu seperti git fetch some-remote +refs/stash:refs/remotes/some-remote/stashitu git stash apply some-remote/stash. Tetapi Anda tidak bisa mendapatkan simpanan lama karena disimpan dalam reflog yang tidak dapat diambil. Lihat stackoverflow.com/questions/2248680/…
sj26
75

Catatan: Saya baru saja menulis ulang jawaban ini dengan 24 jam lebih banyak git-fu di bawah ikat pinggang saya :) Dalam sejarah shell saya, seluruh shebang sekarang tiga baris satu. Namun, saya tidak memberikannya untuk kenyamanan Anda.

Dengan cara ini, saya harap Anda akan dapat melihat bagaimana saya melakukan sesuatu, alih-alih hanya perlu menyalin / menempelkan hal-hal secara membabi buta.


Ini langkah demi langkah.

Anggaplah sumber di ~ / OLDREPO mengandung simpanan. Buat klon TEST yang tidak mengandung simpanan:

cd ~/OLDREPO
git clone . /tmp/TEST

Dorong semua simpanan sebagai cabang temp:

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

Ulangi ujung penerima untuk mengubah kembali menjadi simpanan:

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

Bersihkan cabang sementara Anda jika Anda mau

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

Lakukan daftar simpanan git dan Anda akan melihat sesuatu seperti ini:

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

Pada repositori asli, yang sama tampak seperti

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
lihat
sumber
1
Saya belajar banyak dalam waktu singkat, dan saya merasa mungkin saya harus menggunakan banyak perintah dalam pendekatan saya sebelumnya, yang akan saya coba nanti.
lihat
9
Ini bekerja dengan baik bagi saya kecuali bahwa saya memerlukan langkah git add .sebelum git stash save ...karena git stashmenolak untuk menyimpan file baru kecuali mereka telah dipentaskan. Juga, menyalurkan hasil git rev-list ...melalui tacmembalikkan urutan simpanan sehingga mereka keluar dalam urutan yang sama.
Alan Krueger
1
@hehe script yang sangat baik !! Dua saran: 1) - balik daftar ref akhir sehingga simpanan berada dalam urutan yang sama dalam repo target seperti aslinya. 2) Akhiri forperulangan terakhir dengan git branch -D stash_$a(bersihkan saat simpanan dibuat) sehingga jika terjadi kesalahan dan kami coba lagi, kami tidak memproses ulang komitmen yang sudah berhasil disimpan.
Keith Robertson
1
Terima kasih banyak telah meluangkan waktu untuk menjelaskan apa yang Anda lakukan alih-alih "hanya memposting solusi".
Marjan Venema
1
Solusinya dapat ditingkatkan lebih lanjut: Jika Anda mengganti git stash save "$(git log --format='%s' -1 HEAD@{1})"dengan git update-ref --create-reflog -m "$(git show -s --format=%B $rev)" refs/stash $revAnda mendapatkan pesan simpanan asli ( update-refadalah apa di git stash savebalik layar).
Sebastian Schrader
31

Saya sedikit terlambat ke pesta, tetapi saya percaya saya menemukan sesuatu yang bekerja untuk saya mengenai hal ini dan mungkin juga bagi Anda jika keadaan Anda sama atau serupa.

Saya sedang mengerjakan fitur di cabangnya sendiri. Cabang tidak digabung menjadi master dan didorong sampai selesai atau saya sudah membuat komitmen yang saya rasa nyaman ditunjukkan kepada publik. Jadi yang saya lakukan ketika saya ingin mentransfer perubahan yang tidak dipentaskan ke komputer lain adalah:

  • Buat komit, dengan pesan komit seperti " [non-commit] FOR TRANSFER ONLY", menampilkan konten yang ingin Anda transfer.
  • Login ke komputer lain.
  • Kemudian lakukan:

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

    URL mungkin berbeda untuk Anda jika Anda mengakses repositori Anda dengan cara yang berbeda. Ini akan menarik perubahan dari URL itu dari cabang jauh "rb" ke cabang lokal "lb". Perhatikan bahwa saya memiliki server ssh yang berjalan di komputer saya sendiri, dan saya dapat mengakses repositori dengan cara itu.

  • git reset HEAD^(tersirat --mixed)

    Ini me-reset HEAD untuk menunjuk ke negara sebelum komit "[non-komit]".

Dari git-reset (1): " --mixed: Mengatur ulang indeks tetapi bukan pohon yang berfungsi (yaitu, file yang diubah disimpan tetapi tidak ditandai untuk komit) [...]"

Jadi Anda akan memiliki perubahan pada file pada akhirnya, tetapi tidak ada komitmen yang dibuat untuk dikuasai dan tidak perlu disimpan.

Namun ini akan mengharuskan Anda ke git reset --hard HEAD^dalam repositori tempat Anda membuat "[non-commit]", karena commit tersebut adalah sampah.

Victor Zamanian
sumber
Ini jauh lebih kotor daripada hanya membuat cabang fitur baru kemudian menghapusnya setelah itu ....
Taegost
@Taegost tergantung pada lingkungan Anda, saya kira. Mungkin ada beberapa hal CI / CD mencegah hanya mendorong cabang hulu mau tak mau. Tapi ya, tergantung pada apa yang Anda inginkan, Anda mungkin ingin membuat cabang saja untuk mencapai hal yang sama.
Victor Zamanian
22

Ini agak terlambat, tetapi jawaban ini mungkin bisa membantu seseorang. Saya ingin mengetahui hal ini karena saya ingin dapat mendorong fitur / bug / yang sedang dalam proses dan bekerja dari titik yang sama di komputer lain.

Apa yang berhasil bagi saya adalah melakukan kode sedang dalam proses (di cabang yang saya kerjakan sendiri). Ketika saya sampai di komputer saya yang lain, tarik, lalu batalkan komit dengan:

git reset --soft HEAD^

Terus bekerja seperti semula, dengan semua perubahan dalam proses di sana, tanpa komitmen, dan tidak dipentaskan.

Semoga ini bisa membantu.

Pak Robert
sumber
Ketika saya mencoba melakukan ini, Asal masih mempertahankan Komit, yang tidak berkomitmen. Tutup tapi tidak ada cerutu untukku.
rezwits
@rezwits Ya, remote menyimpannya, tetapi cukup mudah untuk hanya menghapus cabang sementara dari asalnya.
Sir Robert
sebenarnya itulah yang telah saya lakukan!
rezwits
19

Tampaknya ada trik yang sangat rapi untuk menyelesaikan ini. Anda dapat menggunakan git diff > file.diff(dan mengkomit file), lalu mengembalikan perubahan menggunakan git apply file.diff(dari mana saja) untuk mencapai hasil yang sama.

Ini dijelaskan di sini juga.

Daniel Dubovski
sumber
5
jika Anda memiliki file yang tidak dilacak: 1. git add. 2. git diff HEAD> file.diff
trickpatty
Pesan diff untuk diri sendiri memungkinkan untuk tidak ada komitmen / jejak sama sekali pada repo! (misalnya: Note-to-self melalui aplikasi Desktop sinyal), atau email.
John Mee
9

Saya akan menggunakan pendekatan kedua meskipun tidak tahu mengapa Anda tidak bisa mengkomitnya untuk menguasai / menampilkan cabang. Dimungkinkan untuk melakukan memetik ceri juga.

Eimantas
sumber
27
Tidak ada alasan teknis untuk tidak berkomitmen untuk menguasai / fitur, hanya saja saya ingin mengatakan "Ini bukan komitmen nyata, itu hanya menyelamatkan pekerjaan saya sehingga saya bisa mendapatkannya di komputer lain".
Andrew Grimm
4

AFAIK seluruh ide simpanan adalah untuk menyembunyikan sesuatu yang tidak begitu penting di bawah karpet lokal . Tidak ada yang harus tahu tentang omong kosong favorit Anda ;-) Satu-satunya "tapi" adalah: Tetapi jika saya mengembangkan beberapa workstation? Maka scpjauh lebih baik.

argent_smith
sumber
9
Sesuatu yang lucu ini seharusnya menjadi komentar. ;-)
Andrew Grimm
2
Total git-ssh-newbie di sini tetapi bisakah Anda menggunakan scp dengan github?
Koen
Tidak, git-ssh frontend github diprogram sehingga Anda tidak pernah memiliki ssh shell / konsol. Itu hanya dapat menjalankan proses git sisi-server.
argent_smith
1
Jadi scp bukan opsi untuk skenario ini jika cabang master Anda ada di github? Ada saran lain untuk mentransfer simpanan dalam kasus itu?
Koen
1
Saya sudah mencoba menekankan bahwa transfer simpanan tidak mungkin sama sekali, AFAIK.
argent_smith
2

Jawaban yang saat ini diterima secara teknis benar, Anda tidak bisa secara langsung memberitahu Git untuk mendorong semua simpanan Anda ke jarak jauh, dan kemudian menarik semuanya ke simpanan lokal Anda di komputer lain.

Dan sementara jawaban top-upvoted saat ini harus berfungsi, saya tidak suka itu menciptakan banyak cabang sementara, dan bahwa itu memerlukan manual memeriksa simpanan komit dan menyimpannya sebagai simpanan, yang dapat menyebabkan masalah seperti komentar ini disebutkan , dan mengarah ke duplikat On (no branch): On testing:. Tentunya harus ada cara yang lebih baik!

Jadi, sementara Anda tidak dapat secara langsung mendorong simpanan, simpanan hanyalah komit (sebenarnya dua komit), dan per git pushhalaman manual Anda dapat mendorong komit:

The <src>seringkali nama cabang yang Anda ingin mendorong, tetapi bisa sewenang-wenang "SHA-1 ekspresi" ...

Saya memilih untuk mendorong simpanan refs/stashes/*sehingga saya tidak akan mengacaukan remote saya dengan cabang tambahan. Jadi saya bisa melakukannya dengan:

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

( rev-parsePerintah mendapatkan hash pendek simpanan, yang akan unik untuk repo.)

Selanjutnya, saya perlu mengambil simpanan dari komputer lain. Git hanya mengambil cabang secara default, jadi saya perlu mengambil simpanan khusus:

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

Sekarang untuk mengubah simpanan komit kembali menjadi simpanan aktual. Seperti yang disebutkan, sementara saya hanya bisa memeriksa simpanan komit, reset, dan simpanan seperti biasa, saya tidak suka itu membutuhkan langkah-langkah tambahan, atau bahwa itu mungkin tidak mempertahankan status indeks untuk simpanan. Saya mencari secara online cara untuk melakukan itu secara otomatis, tetapi pencarian-fu saya gagal. Akhirnya saya mencari-cari di halaman manual git stash, di mana saya menemukan ini:

buat
Buat simpanan (yang merupakan objek komit biasa) dan kembalikan nama objeknya, tanpa menyimpannya di mana pun di ruang nama ref. Ini dimaksudkan untuk berguna bagi skrip. Ini mungkin bukan perintah yang ingin Anda gunakan; lihat "simpan" di atas.

store
Menyimpan simpanan tertentu yang dibuat melalui git stash create (yang merupakan komit gabungan yang menggantung) di simpanan ref, memperbarui reflog simpanan. Ini dimaksudkan untuk berguna bagi skrip. Ini mungkin bukan perintah yang ingin Anda gunakan; lihat "simpan" di atas.

Karena saya sudah memiliki komit, storeterdengar seperti apa yang saya inginkan. Jadi saya bisa melakukan:

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

Mengganti <SHA>dengan simpanan yang baru saja diambil.

( git showPerintah mendapat pesan komit dari simpanan komit, untuk digunakan sebagai pesan untuk simpanan log.)

Stash sekarang muncul seperti biasa di repo lokal saya:

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

Untuk membersihkan remote, simpanan dapat dihapus dari remote seperti:

git push origin :refs/stashes/<SHA>

Metode ini juga memiliki keuntungan menjadi idempoten: jika Anda menjalankan pushperintah lagi, itu akan dilaporkan Everything up-to-date. The fetchperintah juga dapat dengan aman menjalankan berulang kali. Meskipun stash storelewati menyimpan simpanan jika sama dengan simpanan terbaru, ia tidak mencegah duplikat simpanan lama. Ini bisa diselesaikan, seperti yang saya lakukan dalam git-rstashskrip saya , lihat di bawah.


Untuk penyelesaian, Anda juga dapat dengan mudah mendorong semua simpanan (dengan ):

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

atau impor semua simpanan yang diambil:

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

Saya telah membuat skrip yang dapat disebut sebagai sub-perintah (misalnya git rstash push 0) jadi saya tidak harus mengingat semua ini. git-rstashdapat ditemukan di sini.

Scott Weldon
sumber
1

Berikut ini tidak berfungsi dengan simpanan, tetapi dengan perubahan yang tidak dikomit di direktori kerja. Ini membuat cabang, otomatis melakukan semua perubahan saat ini, dan mendorong ke remote:

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 ..."
}

Gunakan seperti:

commit_and_push_ my-temp-branch
commit_and_push_
blueFast
sumber
0

Saya hanya akan membuat cabang simpanan baru dan menghapus setiap kali cabang itu tidak diperlukan.

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
Bhojendra Rauniyar
sumber
-9

Cukup gunakan Dropbox seperti yang dilakukan orang ini. Dengan begitu Anda tidak perlu khawatir tentang mendorong simpanan karena semua kode Anda akan dicadangkan.

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

Insinyur Teknologi NYC
sumber
2
Sebelum ada orang yang bereaksi keras, saya tidak mengatakan untuk menggunakan Dropbox alih-alih Github, tetapi untuk menyimpan kode yang tidak siap untuk komit di Dropbox yang masih akan berada di bawah kendali versi secara lokal.
NYC Tech Engineer
4
itu akan memakan waktu terlalu lama untuk menyalin semua proyek ke cloud jauh.
Stav Alfi