bagaimana Anda mendorong hanya beberapa komit git lokal Anda?

160

Misalkan saya punya 5 commit lokal. Saya ingin mendorong hanya 2 dari mereka ke repo terpusat (menggunakan alur kerja gaya SVN). Bagaimana saya melakukan ini?

Ini tidak berhasil:

git checkout HEAD~3  #set head to three commits ago
git push #attempt push from that head

Itu akhirnya mendorong semua 5 komitmen lokal.

Saya kira saya bisa melakukan git reset untuk benar-benar membatalkan komit saya, diikuti oleh git simpanan dan kemudian git push - tapi saya sudah mendapat pesan komit tertulis dan file terorganisir dan saya tidak ingin mengulanginya.

Perasaan saya adalah bahwa beberapa bendera yang dilewati untuk mendorong atau mengatur ulang akan berfungsi.

Jika itu membantu, inilah konfigurasi git saya

[ramanujan:~/myrepo/.git]$cat config 
[core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true
[remote "origin"]
        url = ssh://server/git/myrepo.git
        fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
        remote = origin
        merge = refs/heads/master
ramanujan
sumber

Jawaban:

192

Anggap komit Anda ada di cabang master dan Anda ingin mendorongnya ke cabang master jarak jauh:

$ git push origin master~3:master

Jika Anda menggunakan git-svn:

$ git svn dcommit master~3

Dalam kasus git-svn, Anda juga bisa menggunakan HEAD ~ 3, karena mengharapkan komit. Dalam kasus straight git, Anda perlu menggunakan nama cabang karena HEAD tidak dievaluasi dengan benar di refspec.

Anda juga bisa mengambil pendekatan yang lebih panjang dari:

$ git checkout -b tocommit HEAD~3
$ git push origin tocommit:master

Jika Anda terbiasa dengan aliran kerja jenis ini, Anda harus mempertimbangkan untuk melakukan pekerjaan Anda di cabang terpisah. Maka Anda dapat melakukan sesuatu seperti:

$ git checkout master
$ git merge working~3
$ git push origin master:master

Perhatikan bahwa bagian "master asal: master" mungkin opsional untuk pengaturan Anda.

Ryan Graham
sumber
14
Catatan: Anda tidak harus menggunakan master~3. Referensi apa pun untuk komit "hingga" yang diinginkan sama-sama valid, seperti HEAD~3atau HEAD~~~, atau SHA tertentu, atau tag yang label komit itu.
Kaz
2
Barang bagus. Peringatan: contoh-contoh ini mendorong ke master asal. Jika Anda menyalin dan menempel solusi ini, Anda mungkin akhirnya secara tidak sengaja memperbarui cabang master. (Tentu saja, Anda harus selalu berhati-hati dan memeriksa ulang perintah Anda sebelum mengeluarkan git push...)
nofinator
Tampaknya ini mendorong komit, tetapi tidak menambah cabang dari jarak jauh.
Nateowami
@Nateowami untuk itu Anda harus menentukan sesuatu selain masteruntuk sisi remote dari refspec, sepertigit push origin tocommit:newbramch
Ryan Graham
Saya melihat. Nama cabang sudah ada secara lokal; Saya kira itu tidak seperti itu. Remote belum memiliki nama cabang.
Nateowami
16

Apa yang saya lakukan adalah bekerja di cabang lokal yang disebut "bekerja". Cabang ini berisi semua komit sementara (seperti workarounds atau opsi build pribadi atau apa pun) yang saya tidak bermaksud untuk mendorong ke repositori hulu. Saya bekerja jauh di cabang itu, kemudian ketika saya ingin berkomitmen saya beralih ke cabang master, cherry-memilih komit sesuai yang saya lakukan ingin berkomitmen, kemudian mendorong guru.

Setelah menarik perubahan dari hulu ke cabang master saya, saya git checkout workdan git rebase master. Itu menulis ulang semua perubahan lokal saya di akhir sejarah.

Saya sebenarnya menggunakan git svnalur kerja ini, jadi operasi "push" saya melibatkan git svn dcommit. Saya juga menggunakan tigyang merupakan penampil repositori gui mode teks yang bagus, untuk memilih komit yang sesuai untuk dikuasai.

Greg Hewgill
sumber
dengan git svn dcommit, Anda dapat menentukan komit untuk dcommit hingga, sehingga efek yang diinginkan cukup sepele dengan git-svn.
Ryan Graham
Ada beberapa kelemahan dari pendekatan ini (dirangkum di sini stackoverflow.com/a/881014/1116674 ). Alternatif yang baik adalah membuat cabang untuk setiap fitur yang Anda kerjakan, dan workcabang. Kemudian, Anda menggabungkan cabang tertentu ke dalam mastersehingga Anda tidak kehilangan sejarah pada mereka. Saat bekerja dengan work, Anda menggabungkan semua cabang Anda ke dalamnya. Ini lebih mahal, tetapi mungkin layak dalam beberapa kasus.
Hudon
16

Secara default, git-push mendorong semua cabang. Ketika Anda melakukan ini:

 git checkout HEAD~3  #set head to three commits ago
 git push #attempt push from that head

Anda pindah ke KEPALA terlepas (Anda tidak berada di cabang apa pun) dan kemudian Anda mendorong semua cabang, termasuk master lokal (yang masih di tempat itu) ke master jarak jauh.

Solusi manual adalah:

 git push origin HEAD:master

Jika Anda menemukan perilaku default mendorong semua cabang membingungkan (dan berbahaya!), Tambahkan ini ke ~ / .gitconfig Anda:

 [remote.origin]
    push = HEAD

Maka hanya cabang Anda berada di didorong. Dalam contoh Anda (kepala terpisah), Anda akan mendapatkan pesan kesalahan ini, alih-alih secara tidak sengaja memaksakan komitmen yang salah:

 error: unable to push to unqualified destination: HEAD
Thomas Leonard
sumber
10

Jawaban singkat:

git push <latest commit SHA1 until you want commits to be pushed>

Contoh:

git push fc47b2

git push HEAD~2

Jawaban panjang:

Komit dihubungkan bersama sebagai rantai dengan mekanisme orang tua / anak. Dengan demikian, mendorong komit sebenarnya juga mendorong semua orangtua berkomitmen untuk komit ini yang mana tidak diketahui oleh remote. Ini secara implisit dilakukan ketika Anda git pushkomit saat ini: semua komit sebelumnya juga didorong karena perintah ini setara dengan git push HEAD.

Jadi pertanyaannya mungkin ditulis ulang menjadi Bagaimana mendorong komit tertentu dan komit spesifik ini mungkin HEAD ~ 2, misalnya.

Jika komit yang ingin Anda tekan tidak berurutan, cukup pesan ulang dengan yang git rebase -isebelum dorongan tertentu .

Tim
sumber
5

1) Gunakan "git rebase" untuk menyusun ulang komit Anda, jika Anda mau.

git rebase -i

Perintah ini akan menampilkan sesuatu seperti ini di editor Anda (saya menggunakan vim)

pick 4791291 commitA
pick a2bdfbd commitB
pick c3d4961 commitC
pick aa1cefc commitD
pick 9781434 commitE

# Rebase ..............
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#  x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out




^G Get Help         ^O WriteOut         ^R Read File        ^Y Prev Page                ^K Cut Text         ^C Cur Pos
^X Exit             ^J Justify          ^W Where Is         ^V Next Page            ^U UnCut Text       ^T To Spell

2) Susun ulang komit Anda sesuai pilihan Anda dengan tempel sederhana. Misalkan orde baru itu

pilih 9781434 komit

pilih c3d4961 commitC

pilih 4791291 koma

pilih aa1cefc commitD

pilih komit a2bdfbdB

Buat perubahan ini di editor Anda dan tekan ctrl + O (writeOut)

Atau bisa juga Anda gunakan

git rebase -i HEAD~<commitNumber>

Anda dapat memeriksa urutan baru dengan

git log

3) Sekarang gunakan

git push <remoteName> <commit SHA>:<remoteBranchName>

Jika hanya satu cabang di remote (asal) dan satu cabang di lokal (master), gunakan saja

git push <commit SHA>
git push aa1cefc

Ini akan mendorong commitB dan commitD.

Yogesh Yadav
sumber