Pertanyaan Pindahkan komitmen terbaru ke cabang baru dengan Git


Saya ingin memindahkan beberapa commit terakhir yang telah saya lakukan untuk dikuasai ke cabang baru dan mengambil master kembali sebelum komit itu dibuat. Sayangnya, Git-fu saya belum cukup kuat, ada bantuan?

Yaitu. Bagaimana saya bisa pergi dari ini

master A - B - C - D - E

untuk ini?

newbranch     C - D - E
             /
master A - B 

3753
2017-10-27 03:07


asal


Jawaban:


Pindah ke cabang baru

PERINGATAN: Metode ini berfungsi karena Anda membuat cabang baru dengan perintah pertama: git branch newbranch. Jika Anda ingin memindahkan commit ke cabang yang ada Anda perlu menggabungkan perubahan Anda ke dalam cabang yang ada sebelum mengeksekusi git reset --hard HEAD~3 (Lihat Pindah ke cabang yang ada di bawah). Jika Anda tidak menggabungkan perubahan Anda terlebih dahulu, mereka akan hilang.

Kecuali ada keadaan lain yang terlibat, ini dapat dengan mudah dilakukan dengan bercabang dan berguling kembali.

# Note: Any changes not committed will be lost.
git branch newbranch      # Create a new branch, saving the desired commits
git reset --hard HEAD~3   # Move master back by 3 commits (GONE from master)
git checkout newbranch    # Go to the new branch that still has the desired commits

Tetapi pastikan berapa banyak komit untuk kembali. Sebagai alternatif, Anda dapat memilih HEAD~3, sediakan hanya hash dari commit (atau referensi seperti asal / master) Anda ingin "kembali ke" pada menguasai (/ saat ini) cabang, misalnya:

git reset --hard a1b2c3d4

* 1 Anda akan melakukannya hanya menjadi "kehilangan" komitmen dari cabang master, tetapi jangan khawatir, Anda akan memiliki komitmen tersebut di cabang baru!

PERINGATAN: Dengan Git versi 2.0 dan lebih baru, jika nanti git rebase cabang baru di atas yang asli (master) cabang, Anda mungkin memerlukan eksplisit --no-fork-point pilihan selama rebase untuk menghindari kehilangan carry-over commit. Memiliki branch.autosetuprebase always set membuat ini lebih mungkin. Lihat Jawaban John Mellor untuk detailnya.

Pindah ke cabang yang ada

Jika Anda ingin memindahkan commit Anda ke cabang yang ada, akan terlihat seperti ini:

git checkout existingbranch
git merge master
git checkout master
git reset --hard HEAD~3 # Go back 3 commits. You *will* lose uncommitted work.
git checkout existingbranch

4778
2017-07-22 22:37



Bagi mereka yang bertanya-tanya mengapa itu berhasil (seperti saya pada awalnya):

Anda ingin kembali ke C, dan memindahkan D dan E ke cabang baru. Inilah yang terlihat seperti pada awalnya:

A-B-C-D-E (HEAD)
        ↑
      master

Setelah git branch newBranch:

    newBranch
        ↓
A-B-C-D-E (HEAD)
        ↑
      master

Setelah git reset --hard HEAD~2:

    newBranch
        ↓
A-B-C-D-E (HEAD)
    ↑
  master

Karena cabang hanyalah penunjuk, menguasai menunjuk ke komit terakhir. Ketika kamu membuat cabang baru, Anda cukup membuat pointer baru ke commit terakhir. Kemudian menggunakan git reset Anda pindah menguasai penunjuk kembali dua commit. Tapi karena kamu tidak bergerak cabang baru, masih menunjuk pada komitmen yang semula dilakukan.


846
2018-02-07 16:58



Secara umum...

Metode yang diekspos oleh sykora adalah opsi terbaik dalam kasus ini. Namun terkadang tidak mudah dan ini bukan metode umum. Untuk penggunaan metode umum git cherry-pick:

Untuk mencapai apa yang diinginkan OP, prosesnya adalah 2 langkah:

Langkah 1 - Perhatikan mana yang dikomit dari master yang Anda inginkan pada a newbranch

Menjalankan

git checkout master
git log

Perhatikan hash (katakanlah 3) commit yang Anda inginkan newbranch. Di sini saya akan menggunakan:
C commit: 9aa1233
D commit: 453ac3d
E commit: 612ecb3 

catatan: Anda dapat menggunakan tujuh karakter pertama atau   seluruh hash komit

Langkah 2 - Taruh mereka di newbranch

git checkout newbranch
git cherry-pick 612ecb3
git cherry-pick 453ac3d
git cherry-pick 9aa1233

ATAU (pada Git 1.7.2+, gunakan rentang)

git checkout newbranch
git cherry-pick 612ecb3~1..9aa1233

git cherry-pick menerapkan ketiga komitmen tersebut ke cabang baru.


342
2018-03-26 08:13



Namun cara lain untuk melakukan ini, hanya menggunakan 2 perintah. Juga membuat pohon kerja Anda saat ini tetap utuh.

git checkout -b newbranch # switch to a new branch
git branch -f master HEAD~3 # make master point to some older commit

Versi lama - sebelum saya belajar git branch -f

git checkout -b newbranch # switch to a new branch
git push . +HEAD~3:master # make master point to some older commit 

Dapat push untuk . adalah trik yang bagus untuk diketahui.


251
2018-04-06 22:38



Sebagian besar jawaban sebelumnya benar-benar salah!

Jangan lakukan ini:

git branch -t newbranch
git reset --hard HEAD~3
git checkout newbranch

Saat lain kali Anda berlari git rebase (atau git pull --rebase) 3 komit itu akan dibuang secara diam-diam newbranch! (lihat penjelasan di bawah)

Sebaliknya lakukan ini:

git reset --keep HEAD~3
git checkout -t -b newbranch
git cherry-pick ..HEAD@{2}
  • Pertama membuang 3 komit terbaru (--keep seperti --hard, tetapi lebih aman, karena gagal daripada membuang perubahan yang tidak terikat).
  • Lalu garpu berhenti newbranch.
  • Kemudian cherry-picks 3 kembali ke newbranch. Karena mereka tidak lagi direferensikan oleh cabang, ia melakukannya dengan menggunakan git reflog: HEAD@{2} adalah komitmen itu HEAD digunakan untuk merujuk ke 2 operasi yang lalu, yaitu sebelum kami 1. memeriksa newbranch dan 2. digunakan git reset untuk membuang 3 commit.

Peringatan: reflog diaktifkan secara default, tetapi jika Anda telah menonaktifkannya secara manual (mis. Dengan menggunakan "git repositori" kosong), Anda tidak akan bisa mendapatkan 3 commit kembali setelah menjalankan git reset --keep HEAD~3.

Alternatif yang tidak bergantung pada reflog adalah:

# newbranch will omit the 3 most recent commits.
git checkout -b newbranch HEAD~3
git branch --set-upstream-to=oldbranch
# Cherry-picks the extra commits from oldbranch.
git cherry-pick ..oldbranch
# Discards the 3 most recent commits from oldbranch.
git branch --force oldbranch oldbranch~3

(jika Anda lebih suka Anda bisa menulis @{-1} - Cabang yang sebelumnya diperiksa - bukan oldbranch).


Penjelasan teknis

Kenapa harus git rebase membuang 3 komit setelah contoh pertama? Ini karena git rebase tanpa argumen memungkinkan --fork-point opsi secara default, yang menggunakan reflog lokal untuk mencoba menjadi kuat terhadap cabang hulu yang didorong paksa.

Misalkan Anda mencabang asal / master ketika berisi komit M1, M2, M3, kemudian membuat tiga commit sendiri:

M1--M2--M3  <-- origin/master
         \
          T1--T2--T3  <-- topic

tetapi kemudian seseorang menulis ulang sejarah dengan memaksa-mendorong asal / master untuk menghapus M2:

M1--M3'  <-- origin/master
 \
  M2--M3--T1--T2--T3  <-- topic

Menggunakan reflog lokal Anda, git rebase dapat melihat bahwa Anda bercabang dari inkarnasi awal dari cabang asal / induk, dan karenanya bahwa M2 dan M3 berkomitmen tidak benar-benar menjadi bagian dari cabang topik Anda. Oleh karena itu cukup beralasan bahwa karena M2 telah dihapus dari cabang hulu, Anda tidak lagi menginginkannya di cabang topik Anda baik setelah cabang topik direstart:

M1--M3'  <-- origin/master
     \
      T1'--T2'--T3'  <-- topic (rebased)

Perilaku ini masuk akal, dan umumnya adalah hal yang benar untuk dilakukan saat melakukan rebase.

Jadi alasan mengapa perintah berikut gagal:

git branch -t newbranch
git reset --hard HEAD~3
git checkout newbranch

adalah karena mereka meninggalkan reflog dalam keadaan yang salah. Git melihat newbranch sebagai telah bercabang cabang hulu pada revisi yang mencakup 3 komit, maka reset --hard menulis ulang histori hulu untuk menghapus komit, dan lain kali saat Anda menjalankannya git rebase membuang mereka seperti komitmen lain yang telah dihapus dari hulu.

Namun dalam kasus khusus ini kami ingin 3 komit tersebut dianggap sebagai bagian dari cabang topik. Untuk mencapai hal itu, kita perlu melakukan fork off upstream pada revisi sebelumnya yang tidak termasuk 3 commit. Itulah solusi yang saya sarankan, maka mereka berdua meninggalkan reflog dalam keadaan yang benar.

Untuk lebih jelasnya, lihat definisi dari --fork-point dalam git rebase dan git menggabungkan-basisdokumen.


209
2017-10-19 14:12



Ini tidak "memindahkan" mereka dalam arti teknis tetapi memiliki efek yang sama:

A--B--C  (branch-foo)
 \    ^-- I wanted them here!
  \
   D--E--F--G  (branch-bar)
      ^--^--^-- Opps wrong branch!

While on branch-bar:
$ git reset --hard D # remember the SHAs for E, F, G (or E and G for a range)

A--B--C  (branch-foo)
 \
  \
   D-(E--F--G) detached
   ^-- (branch-bar)

Switch to branch-foo
$ git cherry-pick E..G

A--B--C--E'--F'--G' (branch-foo)
 \   E--F--G detached (This can be ignored)
  \ /
   D--H--I (branch-bar)

Now you won't need to worry about the detached branch because it is basically
like they are in the trash can waiting for the day it gets garbage collected.
Eventually some time in the far future it will look like:

A--B--C--E'--F'--G'--L--M--N--... (branch-foo)
 \
  \
   D--H--I--J--K--.... (branch-bar)

27
2018-01-21 16:10



Untuk melakukan ini tanpa menulis ulang sejarah (yaitu jika Anda sudah menekan commit):

git checkout master
git revert <commitID(s)>
git checkout -b new-branch
git cherry-pick <commitID(s)>

Kedua cabang dapat didorong tanpa paksaan!


19
2017-09-20 10:17



Hanya memiliki situasi seperti ini:

Branch one: A B C D E F     J   L M  
                       \ (Merge)
Branch two:             G I   K     N

Saya melakukan:

git branch newbranch 
git reset --hard HEAD~8 
git checkout newbranch

Saya berharap bahwa saya akan menjadi KEPALA, tetapi melakukan L sekarang ...

Untuk memastikan mendarat di tempat yang tepat dalam sejarah, lebih mudah untuk bekerja dengan hash komit

git branch newbranch 
git reset --hard #########
git checkout newbranch

12
2018-05-01 07:50



Solusi yang jauh lebih sederhana

Jika:

  1. Tujuan utama Anda adalah untuk memutar kembali master, dan
  2. Anda ingin menyimpan perubahan tetapi tidak terlalu peduli dengan komitmen individu, dan
  3. Anda belum mendorong,

Maka berikut ini jauh lebih sederhana:

git reset HEAD~3
git stash
git checkout otherbranch
git stash pop

Apa ini:

  1. Membatalkan tiga komit terakhir (dan pesannya), tetapi biarkan semua file yang berfungsi tetap utuh
  2. Stashes jauh semua file yang bekerja berubah, membuat master pohon kerja sama dengan HEAD ~ 3 state.
  3. Beralih ke cabang yang ada otherbranch
  4. Menarik file yang diubah dari simpanan dan masuk ke direktori kerja Anda.

Anda sekarang dapat menggunakan git add dan git commit seperti biasa. Semua perubahan akan dilakukan di otherbranch.

Ini tidak mempertahankan kesalahan komit dan mengkomit pesan. Anda harus menambahkan pesan komit baru ke commit baru ini, menciptakan kembali pesan commit sebelumnya. Namun, OP menyatakan bahwa tujuannya adalah untuk "mengambil kembali master sebelum komit dibuat" tanpa kehilangan perubahan, dan solusi ini melakukannya.

Saya melakukan ini setidaknya sekali seminggu ketika saya secara tidak sengaja membuat komitmen baru master dari pada develop. Biasanya saya hanya memiliki satu komitmen untuk melakukan rollback dalam hal ini git reset HEAD^ bekerja untuk mengembalikan hanya satu komit.


6
2018-05-25 14:14



Anda dapat melakukan ini hanya 3 langkah sederhana yang saya gunakan.

1) buat cabang baru di mana Anda ingin melakukan pembaruan terkini.

git branch <branch name> 

2) Temukan ID Komitmen Terakhir untuk melakukan commit pada cabang baru.

git log

3) Salin yang melakukan catatan id bahwa daftar komit Terkini terjadi di atas. sehingga Anda dapat menemukan komitmen Anda. Anda juga menemukan ini melalui pesan.

git cherry-pick d34bcef232f6c... 

Anda juga dapat memberikan beberapa berdering dari id komit.

git cherry-pick d34bcef...86d2aec

Sekarang pekerjaanmu selesai. Jika Anda memilih id yang benar dan cabang yang benar maka Anda akan sukses. Jadi sebelum melakukan ini, berhati-hatilah. lain masalah lain bisa terjadi.

Sekarang Anda bisa memasukkan kode Anda

git push


0
2018-06-01 05:40



1) Buat cabang baru, yang memindahkan semua perubahan Anda ke new_branch.

git checkout -b new_branch

2) Kemudian kembali ke cabang lama.

git checkout master

3) Lakukan git rebase

git rebase -i <short-hash-of-B-commit>

4) Kemudian editor yang dibuka berisi 3 informasi commit terakhir.

...
pick <C's hash> C
pick <D's hash> D
pick <E's hash> E
...

5) Ubah pick untuk drop di semua 3 komit tersebut. Kemudian simpan dan tutup editor.

...
drop <C's hash> C
drop <D's hash> D
drop <E's hash> E
...

6) Sekarang 3 komit terakhir dikeluarkan dari cabang saat ini (master). Sekarang dorong cabang dengan paksa, dengan + tanda tangan sebelum nama cabang.

git push origin +master

0