git: Menerapkan perubahan yang dilakukan oleh komit di satu repo ke repo lain

115

Saya memiliki repo1dan repo2di mesin lokal. Mereka sangat mirip, tetapi yang terakhir adalah semacam cabang lain ( repo1tidak dipertahankan lagi).

/path/to/repo1 $ git log HEAD~5..HEAD~4
<some_sha> Add: Introduce feature X

Bagaimana menerapkan perubahan yang dilakukan oleh berkomitmen <some_sha>dalam repo1ke repo2?

Apakah saya perlu menyiapkan beberapa tambalan, atau mungkinkah melakukan beberapa di cherry-pickantara repo?

Bagaimana jika melakukan hal yang sama tetapi untuk berbagai komitmen?

takeshin
sumber
2
Tidak bisakah Anda menarik dari repo1 ke repo2?
zwol
untuk kasus yang sedikit lebih spesifik di mana Anda ingin menerapkan perubahan ke file atau file yang dipindahkan di salah satu repositori, lihat di sini: stackoverflow.com/questions/3491270/…
Braham Snyder

Jawaban:

31

Sebagai retasan, Anda dapat mencoba mengubah resep untuk membandingkan komit di dua repositori berbeda di halaman GitTips , yaitu:

GIT_ALTERNATE_OBJECT_DIRECTORIES=../repo/.git/objects \
git cherry-pick $(git --git-dir=../repo/.git rev-parse --verify <commit>)

di mana ../repojalur ke repositori lain.

Dengan Git modern Anda dapat menggunakan beberapa revisi dan rentang revisi dengan cherry-pick .

Ada di $(git --git-dir=../repo/.git rev-parse --verify <commit>) sini untuk menerjemahkan <commit>(misalnya HEAD, atau v0.2, atau master~2, yang merupakan nilai dalam repositori kedua yang Anda salin) ke pengenal SHA-1 untuk komit. Jika Anda mengetahui SHA-1 dari perubahan yang ingin Anda pilih, itu tidak perlu.

CATATAN Namun, Git dapat melewati penyalinan objek dari repositori sumber, karena Git tidak tahu bahwa repositori objek alternatif hanya bersifat sementara, untuk satu operasi. Anda mungkin perlu menyalin objek dari repositori kedua dengan:

GIT_ALTERNATE_OBJECT_DIRECTORIES=../repo/.git/objects git repack -a -d -f

Ini menempatkan objek-objek yang dipinjam dari repositori kedua di penyimpanan repositori asli

Tidak diuji.


Solusi yang tidak terlalu hacky adalah mengikuti jawaban knittl :

  • Pergi ke repositori kedua yang ingin Anda salin komitnya, dan buat tambalan dari komit yang Anda inginkan git format-patch
  • Secara opsional, salin tambalan (0001- * dll.) Ke repositori Anda
  • Gunakan git am --3wayuntuk menerapkan tambalan
Jakub Narębski
sumber
1
Bekerja dengan baik. Jika Anda mengalami masalah dengan commit maka lakukan 'git reset HEAD; git add. '.
gumik
5
ini luar biasa - bagaimana Anda akan melakukan berbagai komitmen? hanya sha1 ... sha2?
hvgotcodes
Saya juga mendapatkan fatal: unable to read tree ...tetapi setelah git reset HEAD^semuanya berfungsi dengan baik
jmarceli
@hvgotcodes itu bekerja untuk saya hanya dengan meneruskan kisaran <commit>tetapi rev-parse --verifyperintah tidak menyukainya karena hanya menerima nilai komit tunggal. Tetapi karena cherry-pickmenerima nilai komit tunggal dan rentang, saya bertanya: mengapa rev-parsediperlukan?
Chuim
1
@Chuim: git rev-parsediperlukan jika Anda ingin merujuk ke komit dengan nama berbasis ref di repositori lain, misalnya master, HEAD^^atau sesuatu seperti itu; rev-parse mengubahnya menjadi pengenal SHA-1 universal.
Jakub Narębski
207

Anda mungkin ingin menggunakan git format-patchdan kemudian git ammenerapkan tambalan itu ke repositori Anda.

/path/to/1 $ git format-patch sha1^..sha1
/path/to/1 $ cd /path/to/2
/path/to/2 $ git am -3 /path/to/1/0001-…-….patch

Atau, dalam satu baris:

/path/to/2 $ git --git-dir=/path/to/1/.git format-patch --stdout sha1^..sha1 | git am -3
rajutan
sumber
9
Solusi ini terbukti lebih sederhana dan lebih aman daripada jawaban yang diterima dari penggunaan cherry-picking langsung GIT_ALTERNATE_OBJECT_DIRECTORIES(yang akan merusak repositori saya).
Chuim
2
Jika ada konflik, ini tidak akan berfungsi karena gagal menemukan komit di cabang lain.
Roger Far
2
Menambahkan --ignore-whitespaceke git amperintah dapat menyelesaikan konflik apa pun dan menghindari keharusan melakukan penggabungan 3 arah
Hugheth
98

Anda dapat melakukannya cherry-pickjika Anda menambahkan repo kedua sebagai remote ke yang pertama (dan kemudian fetch).

wRAR
sumber
11
Itu sebenarnya cara yang tepat untuk melakukannya.
Wilbert
5
Ini juga terasa seperti cara yang tepat bagi saya. Dan saya baru saja menggunakannya dan itu bekerja dengan baik untuk saya.
Ricky Nelson
11
Saya lebih suka mengatakan: lakukan git fetch [remote-name]di repo kedua dan kemudian git cherry-pick [sha1].
5
Pendekatan ini berhasil dengan baik bagi saya, terima kasih. Karena repo kedua juga lokal, cukup gunakan URI file saat menambahkannya sebagai remote.
palimpsestor
2
Dalam kasus saya, saya memiliki dua klon dari repositori git jarak jauh raksasa (untuk memungkinkan pekerjaan paralel), yang berarti semua riwayatnya sudah diunduh dan disimpan dua kali dalam HD saya. Jika saya juga harus menambahkan masing-masing sebagai remote dari yang lain, itu akan membuat dua salinan tambahan dari riwayat yang sama dan berpotensi memerlukan sinkronisasi di antara mereka sebelum saya dapat melakukannya cherry-pick. Jadi, meskipun mungkin terasa seperti cara yang "benar", cara ini tidak selalu paling praktis.
Chuim