'git pull origin mybranch' meninggalkan mybranch lokal N berkomitmen lebih dulu dari asal. Mengapa?

92

Saya baru saja mengamati sesuatu yang aneh git pull, yang saya tidak mengerti.

Pada hari Jumat, saya bekerja di cabang setempat. sebut saja mybranch. Sebelum meninggalkan kantor saya mendorongnya ke asal (yang saya github repo): git push origin mybranch.

Kemarin di rumah, pullsaya mengubah cabang saya ke laptop saya, melakukan beberapa pengkodean lagi, dan kemudian mendorong perubahan saya kembali ke github (asal).

Sekarang saya bekerja lagi, dan mencoba menarik perubahan dari kemarin ke mesin kerja saya (saya tidak mengubah apa pun di repo lokal tempat kerja saya selama akhir pekan):

git pull origin mybranch

yang menyebabkan penggabungan maju cepat, dan itu tidak masalah. Saya kemudian melakukan git status, dan dikatakan:

# On branch mybranch
# Your branch is ahead of 'origin/mybranch' by 6 commits.
#
nothing to commit (working directory clean)

Hah? Bagaimana bisa 6 komitmen di depan ketika saya bahkan tidak menyentuhnya selama akhir pekan, DAN baru saja menarik dari asalnya? Jadi saya menjalankan a git diff origin/mybranchdan perbedaannya persis dengan 6 perubahan yang baru saja saya tarik dari jarak jauh.

Saya hanya bisa "memperbaiki" ini dengan menjalankan git fetch origin:

From [email protected]:me/project
af8be00..88b0738  mybranch -> origin/mybranch

Rupanya, repo lokal saya kehilangan beberapa objek referensi, tapi bagaimana bisa? Maksud saya, tarikan sudah mengambil, dan saya tidak mengerjakan apa pun kecuali cabang itu, jadi a git fetch origindan git fetch origin mybranchharus memiliki hasil yang sama?

Haruskah saya selalu menggunakan git pull originbukan git pull origin branchname?

Saya bingung.

Matthias
sumber
Saya telah memperhatikan ini juga; a git pushjuga akan menyelesaikannya (melaporkan "semua terbaru").
Ben James
4
git config --get-regexp br.*dapat memberi tahu Anda jika konfigurasi Anda memiliki cabang lokal yang melacak cabang lain
VonC
3
Dapatkah Anda mengetik git config branch.master.remote yourGitHubRepo.gitdi workRepo Anda dan memeriksa (di berikutnya git pull origin) apakah status tetap dengan peringatan 'di depan'?
VonC
itu tidak disetel (keluaran kosong). tetapi git remote show originmenunjukkan kepada saya bahwa titik asal menunjuk ke repositori GitHub saya, jadi itu tidak masalah, saya kira?
Matthias
1
git remote saja (menampilkan alamat yang benar untuk repo GitHub) tidak cukup . Untuk menghindari memiliki " Your branch is ahead" pesan peringatan setelah git pull, Anda perlu pertama yang juga menentukan nama remote untuk cabang . Karenanya saran saya: ketik git config branch.master.remote yourGitHubRepo.git, lalu coba a git pulldan a git statusdan lihat apakah masalahnya tetap ada.
VonC

Jawaban:

115

git pullpanggilan git fetchdengan parameter yang sesuai sebelum menggabungkan head yang diambil secara eksplisit (atau jika tidak ada cabang jarak jauh yang dikonfigurasi untuk digabungkan) ke dalam cabang saat ini.

Sintaks: di git fetch <repository> <ref>mana <ref>hanya nama cabang tanpa titik dua adalah pengambilan 'satu tembakan' yang tidak melakukan pengambilan standar dari semua cabang terlacak dari jarak jauh yang ditentukan tetapi hanya mengambil cabang bernama ke dalam FETCH_HEAD.

Pembaruan: untuk versi Git sejak 1.8.4, jika ada cabang pelacakan jarak jauh yang melacak referensi yang Anda minta untuk diambil, maka cabang pelacakan sekarang akan diperbarui oleh fetch. Perubahan ini telah dibuat secara khusus untuk menghindari kebingungan yang disebabkan oleh perilaku sebelumnya.

Ketika Anda melakukan git pull <repository> <ref>, FETCH_HEADdiperbarui seperti di atas, kemudian digabungkan ke dalam check out Anda HEADtetapi tidak ada cabang pelacakan standar untuk repositori jarak jauh yang akan diperbarui (Git <1.8.4). Ini berarti bahwa secara lokal sepertinya Anda lebih unggul dari cabang jarak jauh, padahal sebenarnya Anda sudah memperbaruinya.

Secara pribadi saya selalu git fetchmengikuti git merge <remote>/<branch>karena saya dapat melihat peringatan apa pun tentang pembaruan paksa sebelum saya menggabungkan, dan saya dapat melihat pratinjau apa yang saya gabungkan. Jika saya menggunakan git pullsedikit lebih banyak daripada yang saya lakukan, saya akan melakukan polos git pulltanpa parameter paling banyak pada waktu, mengandalkan branch.<branch>.remotedan branch.<branch>.merge'melakukan hal yang benar'.

CB Bailey
sumber
4
+1 Itu benar-benar penjelasan yang bagus! Saya tahu penjelasannya bersembunyi di suatu tempat di dalam 'git help fetch' tetapi tidak bisa mengeluarkannya ...
Stefan Näwe
1
+1. Pos yang bagus, dengan pendekatan yang mirip dengan gitster.livejournal.com/28309.html
VonC
1
Jadi, apakah git fetchsetelah git pull <repository> <ref>memperbaiki masalah karena pengambilan akan memperbarui cabang pelacakan standar? Juga, terima kasih atas jawaban ini, mulai masuk akal :)
Bart Jedrocha
1
Saya mengalami masalah ini juga dan Anda harus melakukan git fetchdiikuti oleh git merge origin/master master.
pengguna1027169
3

Apa git remote -v showpengembalian ketika datang ke asal?

Jika origin menunjuk ke github, statusnya harus up to date, dan tidak mendahului remote repo. Setidaknya, dengan Git1.6.5 yang saya gunakan untuk pengujian cepat.

Bagaimanapun, untuk menghindari ini, tentukan secara eksplisit repo jarak jauh dari cabang master:

$ git config branch.master.remote yourGitHubRepo.git

lalu a git pull origin master, diikuti dengan a git statusharus mengembalikan status bersih (tidak di depan).
Mengapa? karena master get fetch origin (termasuk dalam master git pull origin) tidak hanya akan memperbarui FETCH_HEAD(seperti yang dijelaskan Charles Bailey dalam jawabannya ), tetapi juga akan memperbarui "cabang master jarak jauh" dalam repositori Git lokal Anda.
Dalam hal ini, master lokal Anda tampaknya tidak lagi berada "di depan" dari master jarak jauh.


Saya bisa mengujinya, dengan git1.6.5:

Pertama saya membuat workrepo:

PS D:\git\tests> cd pullahead
PS D:\git\tests\pullahead> git init workrepo
Initialized empty Git repository in D:/git/tests/pullahead/workrepo/.git/
PS D:\git\tests\pullahead> cd workrepo
PS D:\git\tests\pullahead\workrepo> echo firstContent > afile.txt
PS D:\git\tests\pullahead\workrepo> git add -A 
PS D:\git\tests\pullahead\workrepo> git commit -m "first commit"

Saya mensimulasikan repo GitHub dengan membuat repo telanjang (yang dapat menerima push dari mana saja)

PS D:\git\tests\pullahead\workrepo> cd ..
PS D:\git\tests\pullahead> git clone --bare workrepo github

Saya menambahkan modif ke repo kerja saya, yang saya dorong ke repo github (ditambahkan sebagai remote)

PS D:\git\tests\pullahead> cd workrepo
PS D:\git\tests\pullahead\workrepo> echo aModif >> afile.txt
PS D:\git\tests\pullahead\workrepo> git ci -a -m "a modif to send to github"
PS D:\git\tests\pullahead\workrepo> git remote add github d:/git/tests/pullahead/github
PS D:\git\tests\pullahead\workrepo> git push github

Saya membuat repo rumah, kloning dari GitHub, di mana saya membuat beberapa modifikasi, didorong ke GitHub:

PS D:\git\tests\pullahead\workrepo> cd ..
PS D:\git\tests\pullahead> git clone github homerepo
PS D:\git\tests\pullahead> cd homerepo
PS D:\git\tests\pullahead\homerepo> type afile.txt
firstContent
aModif

PS D:\git\tests\pullahead\homerepo> echo aHomeModif1  >> afile.txt
PS D:\git\tests\pullahead\homerepo> git ci -a -m "a first home modif"
PS D:\git\tests\pullahead\homerepo> echo aHomeModif2  >> afile.txt
PS D:\git\tests\pullahead\homerepo> git ci -a -m "a second home modif"
PS D:\git\tests\pullahead\homerepo> git push github

Saya kemudian menggandakan workrepo untuk percobaan pertama

PS D:\git\tests\pullahead\workrepo4> cd ..
PS D:\git\tests\pullahead> git clone workrepo workrepo2
Initialized empty Git repository in D:/git/tests/pullahead/workrepo2/.git/
PS D:\git\tests\pullahead> cd workrepo2
PS D:\git\tests\pullahead\workrepo2> git remote add github d:/git/tests/pullahead/github
PS D:\git\tests\pullahead\workrepo2> git pull github master
remote: Counting objects: 8, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 6 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (6/6), done.
From d:/git/tests/pullahead/github
 * branch            master     -> FETCH_HEAD
Updating c2763f2..75ad279
Fast forward
 afile.txt |  Bin 46 -> 98 bytes
 1 files changed, 0 insertions(+), 0 deletions(-)

Dalam repo itu, status git menyebutkan master geing sebelum ' origin':

PS D:\git\tests\pullahead\workrepo5> git status
# On branch master
# Your branch is ahead of 'origin/master' by 2 commits.
#
nothing to commit (working directory clean)

Tapi itu originbukan github:

PS D:\git\tests\pullahead\workrepo2> git remote -v show
github  d:/git/tests/pullahead/github (fetch)
github  d:/git/tests/pullahead/github (push)
origin  D:/git/tests/pullahead/workrepo (fetch)
origin  D:/git/tests/pullahead/workrepo (push)

Tetapi jika saya mengulangi urutan dalam repo yang memiliki asal ke github (atau tidak ada asal sama sekali, hanya 'github' jarak jauh yang ditentukan), statusnya bersih:

PS D:\git\tests\pullahead\workrepo2> cd ..
PS D:\git\tests\pullahead> git clone workrepo workrepo4
PS D:\git\tests\pullahead> cd workrepo4
PS D:\git\tests\pullahead\workrepo4> git remote rm origin
PS D:\git\tests\pullahead\workrepo4> git remote add github d:/git/tests/pullahead/github
PS D:\git\tests\pullahead\workrepo4> git pull github master
remote: Counting objects: 8, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 6 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (6/6), done.
From d:/git/tests/pullahead/github
 * branch            master     -> FETCH_HEAD
Updating c2763f2..75ad279
Fast forward
 afile.txt |  Bin 46 -> 98 bytes
 1 files changed, 0 insertions(+), 0 deletions(-)
PS D:\git\tests\pullahead\workrepo4> git status
# On branch master
nothing to commit (working directory clean)

Jika saya hanya originmenunjuk github, statusakan bersih untuk git1.6.5.
Ini mungkin dengan peringatan 'di depan' untuk git sebelumnya, tetapi bagaimanapun, sebuah git config branch.master.remote yourGitHubRepo.gitdefinisi secara eksplisit harus dapat menangani itu, bahkan dengan versi awal Git.

VonC
sumber
Terima kasih telah meluangkan waktu untuk memeriksanya. Remote asal sudah menunjuk ke repo GitHub saya. Saya mengkloning proyek itu dari url GitHub dan cabang master lokal saya melacak asal / master. Sedangkan untuk mybranch, saya cukup yakin saya membuatnya dari origin / mybranch, yang akan melacaknya secara otomatis. Tapi tetap saja, mungkin ini masalahnya? Bahwa mybranch lokal tidak benar-benar melacak origin / mybranch? PS: Saya menggunakan git 1.6.1 (melalui MacPorts).
Matthias
Apakah ada perintah git yang memungkinkan saya melihat apakah cabang lokal melacak cabang lain? Saya tidak dapat menemukannya di halaman manual.
Matthias
Anda dapat melihat cabang jarak jauh mana yang dilacak git remote show origin.
Ted Percival
2

Apakah Anda berhati-hati untuk menambahkan semua remote Anda (kecuali originyang disertakan dengan klon asli Anda) menggunakan git remote add NAME URL? Saya telah melihat bug ini ketika mereka baru saja ditambahkan ke konfigurasi git.

Pat Notz
sumber
Saya melakukan ini saat mengkloning repo. Namun, saya tidak melakukan ini di setiap cabang. Untuk misalnya cabang saya, saya pertama-tama akan mengambil dari asalnya, lalu git checkout -b mybranch origin/mybranch. Menurut halaman manual git-branch, origin / mybranch adalah titik awal, dan selanjutnya, menyatakan untuk --track: "... Gunakan ini jika Anda selalu menarik dari cabang upstream yang sama ke cabang baru, dan jika Anda tidak ingin menggunakan "git pull <repository> <refspec>" secara eksplisit. Perilaku ini adalah default ketika titik awal adalah cabang jarak jauh. "
Matthias