Apakah mungkin untuk memilih komit dari repositori git lain?

726

Saya bekerja dengan repositori git yang membutuhkan komit dari repositori git lain yang tidak tahu apa-apa tentang yang pertama.

Biasanya saya akan menggunakan sakura HEAD@{x}di reflog, tetapi karena ini .gittidak tahu apa-apa tentang entri reflog ini (direktori fisik yang berbeda), bagaimana saya bisa memilih sakura ini, atau bisakah saya?

Saya menggunakan git-svn. Cabang pertama saya adalah menggunakan git-svnsatu trunkdari repo Subversion, dan cabang berikutnya adalah menggunakan git-svnpada cabang Subversion.

gitcoder182
sumber
2
Inilah alasan yang diberikan oleh Ben Lee untuk membuka hadiah pada pertanyaan ini: "Saya akan memberikan hadiah itu untuk jawaban yang benar, bukan jawaban yang diterima. Saya hanya harus menunggu 24 [jam] untuk melakukannya." Namun, saya tidak mengerti yang mana dari yang seharusnya menjadi "jawaban yang tepat", dan mengapa jawaban yang diterima tidak "benar".
1
Tidak jelas apa sifat masalahnya. Bagaimana ini terkait repo berbeda, jika sama sekali? Apakah satu garpu dari yang lain? Atau apakah mereka sebenarnya dua proyek yang sepenuhnya terpisah dan tidak terkait?
@Cupcake, jawaban yang diterima baik, dan jelas membantu OP, jadi itu harus diterima. Dengan "benar", saya benar-benar hanya berarti "tepat untuk saya" (dan menilai komentar, tepat untuk beberapa orang lain juga). Saya hanya berpikir salah satu yang saya berikan hadiah untuk layak sebanyak perwakilan sebagai jawaban yang diterima.
Ben Lee

Jawaban:

557

Anda harus menambahkan repositori lain sebagai remote, lalu mengambil perubahannya. Dari sana Anda melihat komit dan Anda dapat mengambilnya.

Seperti itu:

git remote add other https://example.link/repository.git
git fetch other

Sekarang Anda memiliki semua informasi untuk dilakukan git cherry-pick.

Info lebih lanjut tentang bekerja dengan remote di sini: https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes

CharlesB
sumber
1
Bagaimana jika saya menggunakan git-svn? cabang pertama saya menggunakan git-svn dari trunk dan yang berikutnya menggunakan git-svn pada cabang (terima kasih atas jawaban cepatnya)
gitcoder182
1
ketika Anda pertama kali mengkloning repositori Subversion pastikan Anda mengkloning seluruh repositori, bukan hanya trunk. Pastikan juga Anda menggunakan --stdlayoutopsi git-svn jika Anda menggunakan tata letak trunk / branch / tag standar di Subversion. Maka cabang Subversion akan menjadi cabang git jarak jauh belaka.
wilhelmtell
33
Jika Anda menggunakan Github, Anda dapat menarik tambalan dengan menambahkan .patch ke URL komit, dan kemudian menerapkannya git am < d821j8djd2dj812.patch. Di luar GH, konsep serupa dapat dilakukan sebagaimana dirujuk dalam jawaban alternatif di bawah ini.
Radicand
2
@radicand jawaban mana di bawah ini yang merupakan "alternatif"? Tolong tautkan ke sana.
7
Langkah-langkah terperinci untuk memilih cherry dari repo lain: coderwall.com/p/sgpksw/git-cherry-pick-from-another-repository
T. Kim Nguyen
854

Jawabannya, seperti yang diberikan, adalah menggunakan format-patch tetapi karena pertanyaannya adalah bagaimana cara memilih dari folder lain, berikut adalah bagian dari kode untuk melakukan hal itu:

$ git --git-dir=../<some_other_repo>/.git \
format-patch -k -1 --stdout <commit SHA> | \
git am -3 -k

(penjelasan dari @cong ma )

The git format-patchperintah membuat patch dari some_other_repo's komit ditentukan oleh SHA-nya ( -1untuk satu satu komit saja). Tambalan ini disalurkan ke git am, yang menerapkan tambalan secara lokal ( -3berarti mencoba penggabungan tiga arah jika tambalan gagal diterapkan secara bersih). Harapan itu menjelaskan.

Robert Wahler
sumber
18
Ini tepat, tetapi akan bagus jika ada yang bisa memperluas ini - rincian dari apa yang terjadi (terutama dengan bendera-bendera) akan sangat berguna.
Nick F
46
@NickF, git format-patchperintah tersebut membuat tambalan dari some_other_repokomit yang ditentukan oleh SHA-nya ( -1untuk satu komit saja). Tambalan ini disalurkan ke git am, yang menerapkan tambalan secara lokal ( -3berarti mencoba penggabungan tiga arah jika tambalan gagal diterapkan secara bersih). Harapan itu menjelaskan.
Cong Ma
3
error: patch gagal: somefile.cs: 85 error: somefile.cs: patch tidak berlaku Apakah Anda mengedit tambalan Anda? Itu tidak berlaku untuk gumpalan yang direkam dalam indeksnya. Tidak dapat kembali ke penggabungan tiga arah. Patch gagal pada 0001 Menambahkan bagian GUI. Salinan tambalan yang gagal ditemukan di: <some_other_repo> /.git/rebase-apply/patch Ketika Anda telah menyelesaikan masalah ini, jalankan "git am --continue". Jika Anda lebih suka melewatkan tambalan ini, jalankan "git am --skip". Untuk mengembalikan cabang asli dan berhenti menambal, jalankan "git am --abort".
Tom
8
@ Tom coba gunakan --ignore-whitespace. Perintah penuh: git --git-dir=../<some_other_repo>/.git format-patch -k -1 --stdout <commit SHA> | git am -3 -k --ignore-whitespace
Jake Graham Arnold
7
@ BoomShadow Karena lebih sederhana. Menambahkan remote dan mengambil membawa semua perubahan repo lainnya. Baris perintah ini adalah tindakan satu kali.
Jonathon Reinhart
152

Berikut adalah contoh dari remote-fetch-merge.

cd /home/you/projectA
git remote add projectB /home/you/projectB
git fetch projectB

Maka kamu bisa:

git cherry-pick <first_commit>..<last_commit>

atau Anda bahkan bisa menggabungkan seluruh cabang

git merge projectB/master
Brian
sumber
54
git merge projectB/master sangat, sangat salah , karena Anda tidak menerapkan perubahan dari satu komit (seperti cherry-pick akan), Anda benar-benar penggabungan dalam semua perubahan diprojectB/masteryang tidak terkandung dalam Anda sendirimastercabang.
4
Asumsi saya bahwa ini adalah maksud poster asli. Kalau tidak, ya, ini bukan pilihan yang tepat untuk mereka.
Brian
5
Ini bekerja dengan baik ketika dua repositori saling berhubungan.
Ronny Ager-Wick
1
Saya telah membuat salinan dari repositori git (hanya untuk "bermain-main" tanpa melanggar repo asli) dan untuk tetap memperbarui dengan sumbernya, jawaban dari Brian adalah persis apa yang saya butuhkan, jadi, Cupcake, saya harus mengatakan, itu bukan "salah", tetapi kasus penggunaan lain. Tapi itu baik dari Anda untuk menunjukkan potensi bencana: D
ferrari2k
6
IMO ini perlu menjadi solusi yang diterima. Selain itu, jika Anda ingin menghapus remote setelah Anda selesai memetik ceri, gunakan git remote rm projectB. Juga gunakan git tag -d tag-nameuntuk menghapus semua tag yang diambil dari repo jarak jauh. Komit jarak jauh tidak akan lagi ditampilkan dalam riwayat Anda, dan pemangkasan akan menghapusnya dari penyimpanan pada akhirnya.
ADTC
130

Anda dapat melakukannya, tetapi membutuhkan dua langkah. Begini caranya:

git fetch <remote-git-url> <branch> && git cherry-pick FETCH_HEAD

Ganti <remote-git-url>dengan url atau path ke repositori tempat Anda ingin memilih ceri.

Ganti <branch>dengan cabang atau nama tag yang ingin Anda pilih dari repositori jarak jauh.

Anda dapat mengganti FETCH_HEADdengan SHA git dari cabang.

Diperbarui: dimodifikasi berdasarkan umpan balik @ pkalinow.

docwhat
sumber
8
Ini bekerja dengan nama cabang, tetapi tidak dengan SHA. Jika Anda ingin ceri-memilih komit dilambangkan dengan hash-nya, menggunakan ini sebagai gantinya: git fetch <repo-url> <branch> && git cherry-pick <sha>.
pkalinow
Terima kasih. Inilah yang saya butuhkan untuk memasukkan sejumlah commit dari satu repositori ke repositori lain, yang saya buat untuk tujuan ini.
wojciii
Ini adalah persis apa yang saya butuhkan dengan implementasi kustom kode kami untuk klien yang berbeda (yang masing-masing memiliki repositori / garpu sendiri) kami membutuhkan cara untuk mendapatkan komitmen spesifik ke pangkalan / trunk kami. TERIMA KASIH!
RedSands
Ini harus menjadi jawaban yang diterima untuk pilihan satu kali ceri di seluruh repo. Saya menggunakannya sepanjang waktu ketika memilih antara repo yang sudah lokal, URL jarak jauh kemudian hanya jalur sistem file lokal.
Amedee Van Gasse
61

Berikut adalah langkah-langkah untuk menambahkan remote, mengambil cabang, dan memilih ceri komit

# Cloning our fork
$ git clone [email protected]:ifad/rest-client.git

# Adding (as "endel") the repo from we want to cherry-pick
$ git remote add endel git://github.com/endel/rest-client.git

# Fetch their branches
$ git fetch endel

# List their commits
$ git log endel/master

# Cherry-pick the commit we need
$ git cherry-pick 97fedac

Sumber: https://coderwall.com/p/sgpksw

jaredwilli
sumber
17

Lihat Cara membuat dan menerapkan tambalan dengan Git . (Dari kata-kata pertanyaan Anda, saya berasumsi bahwa repositori lain ini adalah untuk basis kode yang sama sekali berbeda. Jika repositori untuk basis kode yang sama, Anda harus menambahkannya sebagai remote seperti yang disarankan oleh @CharlesB. Bahkan jika itu untuk yang lain basis kode, saya kira Anda masih bisa menambahkannya sebagai remote, tetapi Anda mungkin tidak ingin memasukkan seluruh cabang ke dalam repositori Anda ...)

Aasmund Eldhuset
sumber
11

Anda dapat melakukannya dalam satu baris sebagai berikut. Harap Anda berada di repositori git yang membutuhkan perubahan yang dipilih cherry dan Anda telah memeriksa untuk memperbaiki cabang.

git fetch ssh://[email protected]:7999/repo_to_get_it_from.git branchToPickFrom && git cherry-pick 02a197e9533
# 

git fetch [URL cabang] [Cabang untuk dipilih dari] && git pilih-ceri [komit ID]

Mengenakan
sumber
1
Ceria, tidak perlu ssh://bagian, hanya untukhttps://
Leo
5

Iya. Ambil repositori, lalu pilih ceri dari cabang jarak jauh.

wilhelmtell
sumber
1

Dengan asumsi Aadalah repo Anda ingin ceri-memilih dari, dan Badalah salah satu yang ingin ceri-memilih, Anda dapat melakukan ini dengan menambahkan </path/to/repo/A/>/.git/objectske </path/to/repo/B>/.git/objects/info/alternates. Buat alternatesfile ini jika tidak ada.

Ini akan membuat repo B mengakses semua objek git dari repo A, dan akan membuat cherry-pick berfungsi untuk Anda.

pranavk
sumber
0

Situasi saya adalah saya memiliki repo telanjang yang didorong oleh tim, dan klon yang duduk tepat di sebelahnya. Kumpulan baris dalam Makefile ini berfungsi dengan baik untuk saya:

git reset --hard
git remote update --prune
git pull --rebase --all
git cherry-pick -n remotes/origin/$(BRANCH)

Dengan memperbarui master repo telanjang, kami dapat memilih perubahan yang diusulkan dipublikasikan ke repo telanjang. Kami juga memiliki cara (yang lebih rumit) untuk memilih banyak kesalahan untuk tinjauan dan pengujian konsolidasi.

Jika "tidak tahu apa-apa" berarti "tidak dapat digunakan sebagai remote", maka ini tidak membantu, tetapi pertanyaan SO ini muncul ketika saya mencari-cari alur kerja ini sehingga saya pikir saya akan berkontribusi kembali.

Paul Hulett
sumber
-n berarti no-commit menurut git docs dan saya sangat penting untuk melihat perubahan sebelum membuat commit
canbax
0

Jika Anda ingin memilih banyak komit untuk file yang diberikan sampai Anda mencapai komit yang diberikan, maka gunakan yang berikut ini.

# Directory from which to cherry-pick
GIT_DIR=...
# Pick changes only for this file
FILE_PATH=...
# Apply changes from this commit
FIST_COMMIT=master
# Apply changes until you reach this commit
LAST_COMMIT=...

for sha in $(git --git-dir=$GIT_DIR log --reverse --topo-order --format=%H $LAST_COMMIT_SHA..master -- $FILE_PATH ) ; do 
  git --git-dir=$GIT_DIR  format-patch -k -1 --stdout $sha -- $FILE_PATH | 
    git am -3 -k
done
Diomidis Spinellis
sumber