Paghahambing

git fetch at git pull: ano ang pagkakaiba at alin ang piliin

Na-update: · Skillaria.Top

Dinadownload lang ng git fetch ang mga bagong commit mula sa server at ina-update ang remote branch gaya ng origin/main, nang hindi ginagalaw ang inyong kasalukuyang branch o mga file. Ginagawa ng git pull ang parehong bagay at agad na pinagsasama ang na-download sa kasalukuyang branch, gamit ang merge o rebase. Laging ligtas ang fetch; kapaki-pakinabang ang pull kapag handa na kayong tanggapin agad ang pagbabago ng iba.

Maikling sagot

Dinadownload ng git fetch ang mga bagong commit mula sa server at ina-update ang mga reference ng remote branch (origin/main, origin/feature-x), pero hindi nito ginagalaw ang kasalukuyang branch ninyo o ang mga file sa working directory. Ang git pull ay git fetch kasama ang agarang pagsasama ng na-download sa kasalukuyang branch: sa pamamagitan ng merge (default) o rebase.

Kaya ang praktikal na tuntunin: puwedeng patakbuhin ang fetch anumang oras, hindi ito nakakasira ng anuman. Binabago ng pull ang branch ninyo at puwedeng magtapos sa conflict, kaya patakbuhin ito kapag malinis ang working directory at alam ninyong may darating.

Saan nakatira ang remote branch

Para malinaw ang pagkakaiba, kailangang maintindihan na may dalawang uri ng branch sa lokal na repository. Ang mga lokal na branch, gaya ng main at feature-x, ay inililipat ninyo sa pamamagitan ng sarili ninyong commit. Ang mga remote-tracking branch, gaya ng origin/main, ay mga bookmark na nagsasabing "ganito ang itsura ng server noong huling sinabay". Hindi ito maaaring galawin nang manwal; ina-update lang ang mga ito sa pakikipag-ugnayan sa server: fetch, pull, at push.

git branch -a
* main
  remotes/origin/HEAD -> origin/main
  remotes/origin/main
  remotes/origin/feature-x

Ang git status ay naghahambing ng branch ninyo sa bookmark na origin/main, hindi sa aktwal na server. Kaya maaaring mali ang mensaheng "Your branch is up to date with 'origin/main'": kung matagal na ninyong hindi ginagawa ang fetch, hindi pa alam ng Git ang mga bagong commit ng katrabaho.

Ano ang ginagawa ng git fetch

$ git fetch
remote: Enumerating objects: 7, done.
remote: Counting objects: 100% (7/7), done.
Unpacking objects: 100% (4/4), done.
From github.com:team/project
   3f2a1c9..8b7d4e2  main       -> origin/main

Ang huling linya ang pinakamahalaga: lumipat ang reference na origin/main mula 3f2a1c9 papuntang 8b7d4e2. Nanatili sa puwesto ang inyong main. Ngayon, maaari ninyong tingnan nang mahinahon kung ano ang dumating:

git status                       # Your branch is behind 'origin/main' by 2 commits
git log main..origin/main --oneline   # mga commit na wala sa inyo
git diff main origin/main        # ano ang magbabago sa mga file

Mga kapaki-pakinabang na variant ng fetch:

  • git fetch --all: kunin ang pagbabago mula sa lahat ng remote (kapaki-pakinabang kung may origin at upstream ang fork);
  • git fetch --prune (-p): burahin ang mga lokal na bookmark ng branch na wala na sa server;
  • git fetch origin main: kunin lang ang isang branch;
  • git fetch --tags: kunin din ang lahat ng tag.

Para laging gumana ang pruning, i-enable ito nang isang beses: git config --global fetch.prune true.

Ano ang ginagawa ng git pull

Dalawang hakbang ang ginagawa ng git pull, sunod-sunod. Una, fetch para sa upstream ng kasalukuyang branch; pagkatapos, pagsasama ng origin/<branch> sa inyong branch. Sa literal na kahulugan, katumbas ito ng:

git fetch origin
git merge origin/main      # o git rebase origin/main kapag pull --rebase

Nakadepende ang resulta ng pagsasama sa kung paano nagkahiwalay ang mga history:

  • walang bagong commit sa inyo: nangyayari ang fast-forward, ililipat lang pasulong ang branch;
  • may bagong commit kayo at sa server: sa merge, gagawa ng merge commit; sa rebase, ilalagay ang inyong mga commit sa ibabaw ng mga commit ng server;
  • parehong linya ang nabago sa dalawang panig: conflict na kailangang ayusin nang manwal.

Paghahambing ng git fetch at git pull

git fetchgit pull
Dinadownload ang mga commitOoOo
Ina-update ang origin/*OoOo
Binabago ang kasalukuyang branchHindiOo
Binabago ang mga file sa working directoryHindiOo
Puwedeng magdulot ng conflictHindiOo
Kailangan ng malinis na working directoryHindiMas mainam
Naaapektuhan ang ibang branchIna-update ang lahat ng sinusubaybayang bookmarkSa kasalukuyang branch lang pumapasok
Kailan gamitinPara tingnan ang pagbabago; bago ang rebase; sa mga scriptPara mabilis na maabot ang server sa sarili ninyong branch

git pull: merge o rebase

Simula sa Git 2.27, kapag nagkahiwalay ang history at walang tahasang setting, nagbibigay ng babala ang pull, at sa mas bagong bersyon, huminto na ito na may error na "Need to specify how to reconcile divergent branches" sa halip na tahimik na mag-merge. Hinihingi ng Git na pumili ka ng estratehiya nang isang beses:

git config --global pull.rebase false   # merge (dating default)
git config --global pull.rebase true    # rebase
git config --global pull.ff only        # fast-forward lang, kung hindi, tatanggi

Merge ay pinapanatili ang history gaya ng dati at nagdaragdag ng commit na "Merge branch 'main' of github.com:...". Kung araw-araw kayong nagpa-pull sa branch na may lokal na commit, dadami ang ganitong teknikal na merge sa history.

Rebase ay inililipat ang inyong mga hindi pa naipadalang commit sa ibabaw ng mga bagong commit sa server. Nananatiling tuwid ang history, at isa-isang inaayos ang conflict. Para sa hindi pa nai-publish na lokal na commit, kadalasang ito ang mas magandang pagpipilian. Delikado lang ang rebase sa mga commit na naipadala na at pinagbabasehan na ng iba.

ff only ay ang pinakamahigpit na mode: gagana lang ang pull kapag walang sarili kayong commit. Kapag nagkahiwalay ang history, kayo mismo ang magpapasya kung ano ang gagawin. Maraming beteranong developer ang nagtatakda nito para sa mga pangunahing branch.

Kung may hindi pa naka-commit na edit sa working directory at kailangan agad ang pull, kapaki-pakinabang ang git pull --rebase --autostash: itatago ng Git ang mga pagbabago, gagawin ang rebase, at ibabalik ang mga ito.

Karaniwang sitwasyon: fetch, tingnan, pagkatapos pagsamahin

Ang paraang "fetch muna" ay nagbibigay ng kontrol sa kung ano ang papasok sa inyong branch. Lalo itong kapaki-pakinabang bago mag-pull request at pagkatapos ng mahabang pahinga.

git fetch
git log --oneline --graph HEAD origin/main   # paano nagkahiwalay ang mga branch
git rebase origin/main                       # o git merge origin/main
git push

Isa pang madalas na kaso: i-update ang sarili ninyong feature branch gamit ang bagong main, nang hindi lumilipat dito:

git switch feature-x
git fetch
git rebase origin/main

Hindi angkop dito ang pull: ang git pull sa feature branch ay kukuha ng pagbabago mula sa sarili nitong upstream (origin/feature-x), hindi mula sa pangunahing branch. Puwede ring isulat ang git pull --rebase origin main, pero mas malinaw ang paraang may fetch.

Pag-sync sa server: paano panatilihing bago ang branch

Kapag sinabing "git sync", karaniwang ang ibig sabihin ay ang siklong "kunin ang sa iba, ipadala ang sa akin". Sa purong Git, walang hiwalay na sync command (may button na Sync sa mga IDE at GUI client, at sa loob nito, pull at pagkatapos push ang ginagawa). Ang maaasahang manwal na siklo ay ganito:

  1. git status: siguraduhing naka-commit na ang lahat o naitabi gamit ang git stash;
  2. git pull --rebase: kunin ang mga pagbabago at ilagay ang sarili ninyong commit sa ibabaw;
  3. ayusin ang conflict kung mayroon: itama ang mga file, git add, git rebase --continue;
  4. patakbuhin ang mga test;
  5. git push.

Ganito i-sync ang fork sa orihinal na repository:

git remote add upstream https://github.com/original/project.git
git fetch upstream
git switch main
git merge --ff-only upstream/main
git push origin main

Karaniwang problema sa git pull

Your local changes would be overwritten by merge

Gustong baguhin ng pull ang mga file na inyong ine-edit at hindi pa naka-commit. Ang mga opsyon: mag-commit, itabi (git stash, tapos pull at git stash pop), o gamitin ang --autostash. Hindi kailangang burahin ang mga pagbabago para lang sa pull.

Conflict pagkatapos ng pull

Hihinto ang Git at ipapakita sa git status ang mga file na may conflict. Buksan ang mga ito, piliin ang tamang bersyon sa pagitan ng mga marker na <<<<<<< at >>>>>>>, tapos git add at git commit (sa merge), o git rebase --continue (sa rebase). Kung nagbago ang isip, ibabalik ng git merge --abort o git rebase --abort ang lahat sa estado bago ang pull.

There is no tracking information for the current branch

Walang nakatakdang upstream ang branch, kaya hindi alam ng Git kung saan kukuha. Tukuyin nang tahasan: git pull origin main, o itakda ang koneksyon nang isang beses: git branch --set-upstream-to=origin/main.

refusing to merge unrelated histories

Nilikha nang hiwalay ang lokal at remote na repository, halimbawa, nagdagdag ng README sa server nang likhain ito. Kung sigurado kayong dapat itong pagsamahin: git pull origin main --allow-unrelated-histories.

Hindi magandang resulta ng pull: paano ibalik

Kung tapos na ang merge pagkatapos ng pull at hindi ninyo gusto ang resulta, ibalik ang branch sa estado bago ito: git reset --hard ORIG_HEAD. Binubura ng command ang mga hindi pa naka-commit na pagbabago, kaya tingnan muna ang git status. Sa pinakamasamang kaso, makikita ang dating posisyon ng branch sa git reflog.

Alin ang piliin

  • Gusto ninyong malaman ang bago nang hindi nagbabago ng kahit ano: git fetch.
  • Nagtatrabaho kayo sa sarili ninyong branch at gusto lang maabot ang server: git pull --rebase (o pull na may nakatakdang pull.rebase true).
  • In-update ang pangunahing branch na walang sarili ninyong commit: git pull --ff-only.
  • Kailangang ilagay ang main sa feature branch: git fetch, tapos git rebase origin/main o git merge origin/main.
  • Sumusulat kayo ng script o CI: fetch at tahasang command, hindi pull.

Paano ito lumalabas sa graph ng commit

Isipin na kayo at ang katrabaho ay nagsimula sa commit na C. Sa lokal, gumawa kayo ng commit na D, at ipinadala ng katrabaho sa server ang E. Pagkatapos ng git fetch, alam ng repository ninyo ang parehong linya: tumuturo ang main sa D, ang origin/main sa E, at pareho silang may karaniwang ninuno na C.

          D   <- main (HEAD)
         /
A---B---C
         \
          E   <- origin/main

Pagkatapos nito, ang paraan ng pagsasama ang nagpapasya. Ang git merge origin/main ay gagawa ng commit na M na may dalawang parent, D at E. Ang git rebase origin/main ay kokopyahin ang D sa ibabaw ng E bilang bagong commit na D' na may ibang hash, kaya tuwid na linya ang history. Ginagawa lang ng git pull ang mga hakbang na ito nang awtomatiko, nang walang paghinto sa gitna. Ang paghintong ito, ang pagkakataong tingnan ang graph bago pagsamahin, ang pangunahing halaga ng hiwalay na fetch.

Fetch at pull sa IDE

Sa VS Code, IntelliJ IDEA, at iba pang editor, magkakaiba ang pangalan ng mga button, pero iisang command ang nasa ilalim. Ang "Fetch" ay git fetch; ang "Pull" o "Update Project" ay pull gamit ang estratehiyang nakatakda sa settings (merge o rebase); ang "Sync Changes" ay pull at pagkatapos push. Bago pindutin ang Sync sa shared branch, alamin muna kung aling estratehiya ang nakatakda, dahil kung hindi, biglang lalabas ang mga merge commit sa history. Maraming IDE din ang nagsasagawa ng fetch sa background, kaya karaniwang tama ang bilang ng papasok na commit sa status bar.

Buod

Ina-update ng git fetch ang alam ninyo tungkol sa server, at ina-apply naman ng git pull ang alam na iyon sa kasalukuyang branch. Ligtas ang fetch anumang oras; kapaki-pakinabang ang pull, pero binabago nito ang branch at puwedeng magdala ng conflict, kaya itakda nang isang beses ang estratehiya at panatilihing malinis ang working directory. Ang pagkakaiba ng push, pull, at fetch, at ang pakikitungo sa remote at GitHub, ay itinuturo nang praktikal sa kursong Git namin.

Mga madalas itanong

Kailangan bang mag-fetch muna bago mag-pull?

Hindi, ginagawa na ng pull ang fetch bilang unang hakbang. Kailangan ang hiwalay na fetch kapag gusto ninyong tingnan muna ang mga pagbabago bago magdesisyon kung paano ito isasama.

Puwede bang burahin ng git fetch ang mga pagbabago ko?

Hindi. Binabago lang ng fetch ang mga remote reference gaya ng origin/main, at hindi nito ginagalaw ang mga lokal na branch, index, o working directory.

Ina-update ba ng git pull ang lahat ng branch?

Hindi, sa kasalukuyang branch lang pumapasok ang pull. Ang mga bookmark na origin/* para sa ibang branch ay na-update ng fetch, pero hindi nagbabago ang mga lokal na branch.

Gaano kadalas dapat mag-fetch?

Bago magsimulang magtrabaho, bago gumawa ng pull request, at bago mag-push. Maraming IDE ang awtomatikong nagsa-fetch sa background, at ligtas ito.

Ano ang FETCH_HEAD?

Pansamantalang reference kung saan isinusulat ng fetch ang huling na-download. Halimbawa, pagkatapos ng git fetch origin main, puwede ninyong patakbuhin ang git merge FETCH_HEAD.

Pag-aralan ito sa video

Detalyadong tinatalakay ang paksang ito, may praktis, sa kursong “Git с нуля до уверенного разработчика”.

Pumunta sa kurso