Mengapa Git mengatakan cabang master saya "sudah up to date" padahal belum?

118

Masalah Dasar

Saya baru saja menghapus SEMUA kode dari sebuah file di proyek saya dan melakukan perubahan ke git lokal saya (sengaja). aku melakukannya

git pull upstream master

untuk mengambil dan menggabungkan dari upstream (sehingga secara teori kode yang dihapus harus kembali).

Git memberi tahu saya bahwa semuanya mutakhir.

Semuanya pasti TIDAK mutakhir - semua kode yang dihapus itu masih dihapus.

Info Relevan Lainnya

Saya hanya memiliki satu cabang yang disebut "master".

Saya baru-baru ini menyiapkan "master" untuk melacak upstream seperti ini:

Master cabang disiapkan untuk melacak master cabang jarak jauh dari hulu.

Perintah tersebut git branch -vvmenghasilkan:

* master 7cfcb29 [upstream/master: ahead 9] deletion test

Mengapa mengapa mengapa ini terjadi? Saya hampir saja mengirim email ke manajer proyek saya setiap perubahan yang saya buat pada kode kami.

Memperbarui

Saya pikir itu sudah jelas, tetapi bagaimanapun ini adalah tujuan saya:

Dapatkan kode terbaru di sistem saya.

Maafkan amarah saya di sini, tetapi mengapa tugas sesederhana itu harus begitu sulit?

pengguna1971506
sumber
1
Jelas bahwa jika Anda menghapus sumber Anda kemudian mencoba menarik dengan "tarikan" langsung yang git tidak akan menimpa perubahan lokal Anda (dalam hal ini penghapusan Anda) tanpa memastikan Anda benar-benar ingin menimpa perubahan lokal Anda. Jawaban pertama sepertinya menjelaskan dengan tepat bagaimana Anda bisa melakukannya.
CashCow

Jawaban:

209

Saya pikir masalah dasar Anda di sini adalah bahwa Anda salah menafsirkan dan / atau salah memahami apa yang dilakukan git dan mengapa git melakukannya.

Saat Anda mengkloning beberapa repositori lain, git membuat salinan apa pun yang ada "di sana". Ia juga mengambil label cabang "mereka", seperti master, dan membuat salinan dari label itu yang "nama lengkapnya" di pohon git Anda adalah (biasanya) remotes/origin/master(tetapi dalam kasus Anda, remotes/upstream/master). Seringkali Anda juga bisa menghilangkan remotes/bagian tersebut, jadi Anda bisa merujuk ke salinan aslinya sebagai upstream/master.

Jika sekarang Anda membuat dan melakukan beberapa perubahan ke beberapa file, Anda adalah satu-satunya yang memiliki perubahan tersebut. Sementara itu, orang lain dapat menggunakan repositori asli (tempat Anda membuat klon) untuk membuat klon lain dan mengubah klon tersebut. Mereka adalah satu-satunya yang memiliki perubahan, tentunya. Namun pada akhirnya, seseorang mungkin memiliki perubahan yang mereka kirim kembali ke pemilik aslinya (melalui "push" atau tambalan atau apa pun).

The git pullperintah kebanyakan hanya singkatan untuk git fetchdiikuti oleh git merge. Ini penting karena artinya Anda perlu memahami apa yang sebenarnya dilakukan oleh kedua operasi tersebut.

The git fetchperintah mengatakan untuk kembali ke mana pun Anda kloning dari (atau telah ditetapkan sebagai tempat untuk mengambil dari) dan menemukan "baru barang-barang orang lain ditambahkan atau diubah atau dihapus". Perubahan tersebut disalin dan diterapkan ke salinan Anda dari apa yang Anda dapatkan dari mereka sebelumnya . Mereka tidak diterapkan pada pekerjaan Anda sendiri, hanya pada pekerjaan mereka.

The git mergeperintah lebih rumit dan adalah di mana Anda akan kacau. Apa yang dilakukannya, sedikit disederhanakan, adalah membandingkan "apa yang Anda ubah dalam salinan Anda" dengan "perubahan yang Anda ambil dari orang lain dan dengan demikian ditambahkan ke salinan-karya-karya-orang lain". Jika perubahan Anda dan perubahannya tidak menimbulkan konflik, mergeoperasi menggabungkannya dan memberi Anda "komit gabungan" yang mengikat pengembangan Anda dan perkembangannya bersama-sama (meskipun ada kasus "mudah" yang sangat umum di mana Anda tidak memiliki berubah dan Anda mendapatkan "maju cepat").

Situasi yang Anda hadapi sekarang adalah situasi di mana Anda telah membuat perubahan dan melakukannya — sembilan kali, pada kenyataannya, karena itu "9 di depan" —dan mereka tidak membuat perubahan. Jadi, dengan fetchpatuh tidak mengambil apa-apa, dan kemudian mergemengambil kekurangan-perubahan mereka dan juga tidak melakukan apa-apa.

Yang Anda inginkan adalah melihat, atau mungkin bahkan "menyetel ulang" ke, versi kode "mereka".

Jika Anda hanya ingin melihatnya, Anda dapat melihat versi itu:

git checkout upstream/master

Itu memberitahu git bahwa Anda ingin memindahkan direktori saat ini ke cabang yang nama lengkapnya sebenarnya remotes/upstream/master. Anda akan melihat kode mereka sejak terakhir kali Anda menjalankan git fetchdan mendapatkan kode terbaru mereka.

Jika Anda ingin mengabaikan semua perubahan Anda sendiri, yang perlu Anda lakukan adalah mengubah gagasan git tentang revisi label mana master, yang harus diberi nama. Saat ini, ini memberi nama komit terbaru Anda. Jika Anda kembali ke cabang itu:

git checkout master

maka git resetperintah tersebut akan memungkinkan Anda untuk "memindahkan label", sebagaimana mestinya. Satu-satunya masalah yang tersisa (dengan asumsi Anda benar-benar siap untuk meninggalkan semua yang telah Anda lakukan) adalah menemukan di mana label harus menunjuk.

git logakan membiarkan Anda menemukan nama numerik — hal-hal seperti 7cfcb29—yang merupakan nama permanen (tidak pernah berubah), dan ada banyak cara lain untuk menamainya, tetapi dalam hal ini Anda hanya menginginkan namanya upstream/master.

Untuk memindahkan label, memusnahkan perubahan Anda sendiri (apapun yang Anda telah berkomitmen sebenarnya dipulihkan untuk cukup lama tapi itu jauh lebih sulit setelah ini jadi sangat yakin):

git reset --hard upstream/master

Perintah itu --hardmemberitahu git untuk menghapus apa yang telah Anda lakukan, memindahkan label cabang saat ini, dan kemudian memeriksa komit yang diberikan.

Tidak terlalu umum untuk benar - benar ingin git reset --harddan menghapus banyak pekerjaan. Metode yang lebih aman (membuatnya jauh lebih mudah untuk memulihkan pekerjaan itu jika Anda memutuskan beberapa di antaranya bermanfaat) adalah dengan mengganti nama cabang Anda yang ada:

git branch -m master bunchofhacks

dan kemudian buat cabang lokal baru bernama master"trek" (Saya tidak terlalu suka istilah ini karena menurut saya ini membingungkan orang, tetapi itu istilah git :-)) master asal (atau upstream):

git branch -t master upstream/master

yang kemudian dapat Anda lakukan sendiri:

git checkout master

Apa yang dilakukan tiga perintah terakhir (ada pintasan untuk menjadikannya hanya dua perintah) adalah mengubah nama yang ditempelkan pada label yang ada, lalu membuat label baru, lalu beralih ke label itu:

sebelum melakukan apapun:

C0 -    "remotes/upstream/master"
    \
     \- C1 --- C2 --- C3 --- C4 --- C5 --- C6 --- C7 --- C8 --- C9    "master"

setelah git branch -m:

C0 -    "remotes/upstream/master"
    \
     \- C1 --- C2 --- C3 --- C4 --- C5 --- C6 --- C7 --- C8 --- C9    "bunchofhacks"

setelah git branch -t master upstream/master:

C0 -    "remotes/upstream/master", "master"
    \
     \- C1 --- C2 --- C3 --- C4 --- C5 --- C6 --- C7 --- C8 --- C9    "bunchofhacks"

Berikut C0adalah komit terbaru (pohon sumber lengkap) yang Anda dapatkan saat pertama kali melakukan git clone. C1 hingga C9 adalah komitmen Anda.

Perhatikan bahwa jika Anda menjadi git checkout bunchofhacksdan kemudian git reset --hard HEAD^^, ini akan mengubah gambar terakhir menjadi:

C0 -    "remotes/upstream/master", "master"
    \
     \- C1 --- C2 --- C3 --- C4 --- C5 --- C6 --- C7 -    "bunchofhacks"
                                                      \
                                                       \- C8 --- C9

Alasannya adalah HEAD^^menamai revisi dua dari kepala cabang saat ini (yang tepat sebelum reset akan dilakukan bunchofhacks), dan reset --hardkemudian memindahkan label. Commits C8 dan C9 sekarang sebagian besar tidak terlihat (Anda dapat menggunakan hal-hal seperti reflog dan git fsckmenemukannya tetapi tidak lagi sepele). Label Anda adalah milik Anda untuk dipindahkan sesuka Anda. The fetchperintah mengurus orang-orang yang memulai dengan remotes/. Adalah konvensional untuk mencocokkan "milik Anda" dengan "milik mereka" (jadi jika mereka memiliki remotes/origin/mauveAnda akan menamai Anda mauvejuga), tetapi Anda dapat mengetikkan "milik mereka" kapan pun Anda ingin memberi nama / melihat komitmen yang Anda dapatkan "dari mereka". (Ingatlah bahwa "satu komit" adalah keseluruhan pohon sumber. Anda dapat memilih satu file tertentu dari satu komit, dengan git showmisalnya,

torek
sumber
12
Saya belajar banyak dari jawaban Anda yang luar biasa. Tapi saya masih bingung mengapa saya mendapatkan pesan status git: "Cabang Anda up-to-date dengan 'origin / master'" ketika repo upstream beberapa komit sebelum repo saya saat ini. Saya bisa mendapatkan informasi terbaru tentang git pull, tetapi bagaimana saya tahu bahwa saya harus menarik jika pesan mengatakan saya sudah terbaru?
Christopher Werby
@ChristopherWerby: sepertinya Anda menjalankan git mergeperintah baris perintah (yang saya lakukan sendiri, ini metode yang masuk akal). Namun, perhatikan bahwa itu git pulldimulai dengan menjalankannya terlebih dahulu git fetch, kemudian menjalankannya git merge(atau git rebasejika Anda menyuruhnya untuk melakukannya). Ini adalah langkah pengambilan yang benar-benar membawa komitmen baru untuk digabungkan (atau hanya didasarkan pada basis).
torek
@torek Apakah ada beberapa perintah, selain git status, yang dapat saya gunakan untuk melihat apakah repo upstream berada di depan repo saya saat ini? Pesan yang saya dapatkan dengan git statusmengatakan "Cabang Anda up-to-date dengan 'origin / master'" membingungkan saya sehingga berpikir saya telah mendapatkan perubahan terbaru, padahal tidak. Kadang-kadang, saya mendapatkan pesan yang mengatakan sesuatu seperti "origin / master adalah 5 komit sebelum cabang Anda" (parafrase). Tapi itu tidak konsisten.
Christopher Werby
1
Ini masih belum benar-benar menjawab mengapa git statusmengatakan "Cabang Anda up to date" ketika segera git fetchkemudian menarik lebih dari seratus objek dan menyelesaikan hampir seratus delta, menyebutkan beberapa cabang baru dan beberapa tag baru dan mengubah utama (jarak jauh tracking) branch head commit - lalu status git lainnya dengan riang, dan tidak jujur, masih menyatakan "Cabang Anda sudah diperbarui". Jelas banyak yang turun dari asalnya tapi cabangnya "up to date with origin" baik sebelum maupun sesudah?
NeilG
1
git pulldijalankan git fetchterlebih dahulu, lalu git merge(atau perintah kedua pilihan Anda). The git fetchlangkah update Anda memori Git untuk mereka statusnya Git ini, dengan memanggil mereka Git dan mendapatkan sesuatu yang baru dari mereka. Anda git statushanya memeriksa memori Git Anda tentang Git mereka.
Torek
18

Saya memiliki masalah yang sama dengan Anda.

Ya git status git fetch git pull, tapi cabang saya masih tertinggal. Saya memiliki folder dan file yang didorong ke jarak jauh dan saya melihat file di web, tetapi di lokal saya mereka hilang.

Akhirnya, perintah ini memperbarui semua file dan folder di lokal saya:

git fetch --all
git reset --hard origin/master 

atau jika Anda menginginkan cabang

git checkout your_branch_name_here
git reset --hard origin/your_branch_name_here
jturi
sumber
1
Terima kasih! ini benar-benar berhasil. Ingatlah bahwa nama cabang peka huruf besar kecil!
André Ramon
4

Setiap perubahan yang Anda lakukan, seperti menghapus semua file proyek Anda, akan tetap ada setelah penarikan. Semua yang dilakukan oleh penarikan adalah menggabungkan perubahan terbaru dari tempat lain ke dalam cabang Anda sendiri, dan jika cabang Anda telah menghapus semuanya, maka paling baik Anda akan mendapatkan konflik penggabungan ketika perubahan upstream memengaruhi file yang telah Anda hapus. Jadi, singkatnya, ya semuanya sudah up to date.

Jika Anda mendeskripsikan hasil yang Anda inginkan daripada "semua file dihapus", mungkin seseorang dapat menyarankan tindakan yang sesuai.

Memperbarui:

DAPATKAN KODE TERBARU DI SISTEM SAYA

Apa yang tampaknya tidak Anda pahami adalah bahwa Anda sudah memiliki kode terbaru, yang menjadi milik Anda. Jika Anda benar-benar ingin melihat karya terbaru orang lain yang ada di cabang master, lakukan saja:

git fetch upstream
git checkout upstream/master

Perhatikan bahwa ini tidak akan membuat Anda berada dalam posisi untuk segera (kembali) memulai pekerjaan Anda sendiri. Jika Anda perlu mengetahui cara membatalkan sesuatu yang telah Anda lakukan atau mengembalikan perubahan yang Anda atau orang lain buat, berikan detailnya. Juga, pertimbangkan untuk membaca tentang untuk apa kontrol versi itu, karena Anda tampaknya salah memahami tujuan dasarnya.

Ryan Stewart
sumber
Saya sebenarnya menginginkan versi terbaru dari kode orang lain di sistem saya. Namun, kedua perintah tersebut tidak melakukan itu. Yang saya dapatkan hanyalah "sudah di master cabang". Kode di file saya tidak mencerminkan kode orang lain.
pengguna1971506
Maaf, seharusnya upstream/master. Memperbarui jawaban saya.
Ryan Stewart
3

Seperti yang dikatakan poster lain, tarik menggabungkan perubahan dari hulu ke repositori Anda. Jika Anda ingin mengganti apa yang ada di repositori Anda dengan yang ada di hulu, Anda memiliki beberapa opsi. Langsung saja, saya akan pergi dengan

git checkout HEAD^1  # Get off your repo's master.. doesn't matter where you go, so just go back one commit
git branch -d master  # Delete your repo's master branch
git checkout -t upstream/master  # Check out upstream's master into a local tracking branch of the same name
Paul
sumber
1

Jawaban teratas jauh lebih baik dalam hal luas dan kedalaman informasi yang diberikan, tetapi sepertinya jika Anda ingin masalah Anda segera diperbaiki, dan tidak keberatan menginjak beberapa prinsip dasar kontrol versi, Anda dapat ...

  1. Beralih ke master

    $ git checkout upstream master
    
  2. Hapus cabang yang tidak Anda inginkan. (Catatan: harus memiliki -D, bukan flag -d normal karena cabang Anda memiliki banyak komit sebelum master.)

    $ git branch -d <branch_name>
    
  3. Buat cabang baru

    $ git checkout -b <new_branch_name>
    
BrotherDonkey
sumber
1

Meskipun tidak ada dari jawaban ini yang berhasil untuk saya, saya dapat memperbaiki masalah tersebut menggunakan perintah berikut.

git fetch origin

Ini menipu saya.

Doctiger
sumber
0

Hanya pengingat yang ramah jika Anda memiliki file secara lokal yang tidak ada di github namun Anda git statusberkata

Cabang Anda sudah diperbarui dengan 'origin / master'. tidak ada yang harus dilakukan, pohon kerja bersih

Itu bisa terjadi jika file ada di .gitignore

Coba lari

cat .gitignore 

dan melihat apakah file-file ini muncul di sana. Itu akan menjelaskan mengapa git tidak ingin memindahkannya ke remote.

stevec
sumber