日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

Git 少用 Pull 多用 Fetch 和 Merge

 灬木木的花灬 2015-09-22

本文有點(diǎn)長(zhǎng)而且有點(diǎn)亂,但就像Mark Twain Blaise Pascal笑話里說(shuō)的那樣:我沒(méi)有時(shí)間讓它更短些。在Git的郵件列表里有很多關(guān)于本文的討論,我會(huì)盡量把其中相關(guān)的觀點(diǎn)列在下面。

我最常說(shuō)的關(guān)于git使用的一個(gè)經(jīng)驗(yàn)就是:

不要用git pull,用git fetch和git merge代替它。

git pull的問(wèn)題是它把過(guò)程的細(xì)節(jié)都隱藏了起來(lái),以至于你不用去了解git中各種類型分支的區(qū)別和使用方法。當(dāng)然,多數(shù)時(shí)候這是沒(méi)問(wèn)題的,但一旦代碼有問(wèn)題,你很難找到出錯(cuò)的地方??雌饋?lái)git pull的用法會(huì)使你吃驚,簡(jiǎn)單看一下git的使用文檔應(yīng)該就能說(shuō)服你。

將下載(fetch)和合并(merge)放到一個(gè)命令里的另外一個(gè)弊端是,你的本地工作目錄在未經(jīng)確認(rèn)的情況下就會(huì)被遠(yuǎn)程分支更新。當(dāng)然,除非你關(guān)閉所有的安全選項(xiàng),否則git pull在你本地工作目錄還不至于造成不可挽回的損失,但很多時(shí)候我們寧愿做的慢一些,也不愿意返工重來(lái)。

分支(Branches)

在說(shuō)git pull之前,我們需要先澄清分支的概念(branches)。很多人像寫(xiě)代碼似的用一行話來(lái)描述分支是什么,例如:

  • 準(zhǔn)確而言,分支的概念不是一條線,而類似于開(kāi)發(fā)中的有向無(wú)環(huán)圖
  • 分支類似于一個(gè)重量級(jí)的大對(duì)象集合。

我認(rèn)為你應(yīng)該這樣來(lái)理解分支的概念:它是用來(lái)標(biāo)記特定的代碼提交,每一個(gè)分支通過(guò)SHA1sum值來(lái)標(biāo)識(shí),所以對(duì)分支進(jìn)行的操作是輕量級(jí)的--你改變的僅僅是SHA1sum值。

這個(gè)定義或許會(huì)有意想不到的影響。比如,假設(shè)你有兩個(gè)分支,“stable” 和 “new-idea”, 它們的頂端在版本 E 和 F:

  A-----C----E ("stable")
       B-----D-----F ("new-idea")

所以提交(commits) A, C和 E 屬于“stable”,而 A, B, D 和 F 屬于 “new-idea”。如果之后你用下面的命令 將“new-idea” merge 到 “stable” :

    git checkout stable   # Change to work on the branch "stable"
    git merge new-idea    # Merge in "new-idea"

…那么你會(huì)得到這個(gè):

  A-----C----E----G ("stable")
   \             /
    B-----D-----F ("new-idea")

要是你繼續(xù)在“new idea” 和“stable”分支提交, 會(huì)得到:

  A-----C----E----G---H ("stable")
   \             /
    B-----D-----F----I ("new-idea")

因此現(xiàn)在A, B, C, D, E, F, G 和 H 屬于 “stable”,而A, B, D, F 和 I 屬于 “new-idea”。

當(dāng)然了,分支確實(shí)有些特殊的屬性——其中最重要的是,如果你在一個(gè)分支進(jìn)行作業(yè)并創(chuàng)建了一個(gè)新的提交(commits),該分支的頂端將前進(jìn)到那個(gè)提交(commits)。這正是你所希望的。當(dāng)用git merge 進(jìn)行合并(merge)的時(shí)候,你只是指定了要合并到當(dāng)前分支的那個(gè)并入分支,以及當(dāng)前分支的當(dāng)前進(jìn)展。

另一個(gè)表明使用分支會(huì)有很大幫助的觀點(diǎn)的常見(jiàn)情形是:假設(shè)你直接工作在一個(gè)項(xiàng)目的主要分支(稱為“主版本”),當(dāng)你意識(shí)到你所做的可能是一個(gè)壞主意時(shí)已經(jīng)晚了,這時(shí)你肯定寧愿自己是工作在一個(gè)主題分支上。如果提交圖看起來(lái)像這樣:

   last version from another repository
      |
      v
  M---N-----O----P---Q ("master")

那么你把你的工作用下面的一組命令分開(kāi)做(如圖顯示的是執(zhí)行它們之后所更改的狀態(tài)):

  git branch dubious-experiment

  M---N-----O----P---Q ("master" and "dubious-experiment")

  git checkout master

  # Be careful with this next command: make sure "git status" is
  # clean, you're definitely on "master" and the
  # "dubious-experiment" branch has the commits you were working
  # on first...

  git reset --hard <SHA1sum of commit N>

       ("master")
  M---N-------------O----P---Q ("dubious-experiment")

  git pull # Or something that updates "master" from
           # somewhere else...

  M--N----R---S ("master")
             O---P---Q ("dubious-experiment")

這是個(gè)看起來(lái)我最終做了很多的事情。

分支類型

分支這個(gè)術(shù)語(yǔ)不太容易理解,而且在git的開(kāi)發(fā)過(guò)程中發(fā)生了很多變化。但簡(jiǎn)單來(lái)說(shuō)git的分支只有兩種:

a)“本地分支(local branches)” ,當(dāng)你輸入“git branch”時(shí)顯示的。例如下面這個(gè)小例子:

       $ git branch
         debian
         server
       * master

b)“遠(yuǎn)程跟蹤分支(Remote-tracking branches)” ,當(dāng)你輸入“git branch -r”是顯示的,如:

 

       $ git branch -r
       cognac/master
       fruitfly/server
       origin/albert
       origin/ant
       origin/contrib
       origin/cross-compile

從上面的輸出可以看到,跟蹤分支的名稱前有一個(gè)“遠(yuǎn)程的”標(biāo)記名稱(如 :origin, cognac, fruitfly)后面跟一個(gè)“/”,然后遠(yuǎn)程倉(cāng)庫(kù)里分支的真正名稱。(“遠(yuǎn)程名稱”是一個(gè)代碼倉(cāng)庫(kù)別名,和本地目錄或URL是一個(gè)含義,你可以通過(guò)"git remote"命令自由定義額外的“遠(yuǎn)程名稱”。但“git clone”命令默認(rèn)使用的是“origin”這個(gè)名稱。)

如果你對(duì)分支在本地是如何存儲(chǔ)感興趣的話,看看下面文件: 

  •   .git/refs/head/[本地分支]
  •   .git/refs/remotes/[正在跟蹤的分支]

兩種類型的分支在某些方面十分相似-它們都只是在本地存儲(chǔ)一個(gè)表示提交的SHA1校驗(yàn)和。(我強(qiáng)調(diào)“本地”,因?yàn)樵S多人看到"origin/master" 就認(rèn)為這個(gè)分支在某種意義上說(shuō)是不完整的,沒(méi)有訪問(wèn)遠(yuǎn)端服務(wù)器的權(quán)限- 其實(shí)不是這種情況。) 
不管如何相似,它們還是有一個(gè)特別重大的區(qū)別: 

  •   更改遠(yuǎn)端跟蹤分支的安全方法是使用git fetch或者是作為git-push副產(chǎn)品,你不能直接對(duì)遠(yuǎn)端跟蹤分支這么操作。相反,你總得切換到本地分支,然后創(chuàng)建可移動(dòng)到分支頂端的新提交 。

因此,你對(duì)遠(yuǎn)端跟蹤分支最多能做的是下面事情中的一件: 

  •  使用git fetch 更新遠(yuǎn)端跟蹤分支
  •  合并遠(yuǎn)端跟蹤分支到當(dāng)前分支
  •  根據(jù)遠(yuǎn)端跟蹤分支創(chuàng)建本地分支

基于遠(yuǎn)程跟蹤分支創(chuàng)建本地分支

如果你想基于遠(yuǎn)程跟蹤分支創(chuàng)建本地分支(在本地分支上工作),你可以使用如下命令:git branch –trackgit checkout –track -b,兩個(gè)命令都可以讓你切換到新創(chuàng)建的本地分支。例如你用git branch -r命令看到一個(gè)遠(yuǎn)程跟蹤分支的名稱為“origin/refactored”是你所需要的,你可以使用下面的命令:

    git checkout --track -b refactored origin/refactored

在上面的命令里,“refactored”是這個(gè)新分支的名稱,“origin/refactored”則是現(xiàn)存遠(yuǎn)程跟蹤分支的名稱。(在git最新的版本里,例子中‘-track’選項(xiàng)已經(jīng)不需要了,如果最后一個(gè)參數(shù)是遠(yuǎn)程跟蹤分支,這個(gè)參數(shù)會(huì)被默認(rèn)加上。)

“–track”選項(xiàng)會(huì)設(shè)置一些變量,來(lái)保持本地分支和遠(yuǎn)程跟蹤分支的相關(guān)性。他們對(duì)下面的情況很有用:

  • git pull命令下載新的遠(yuǎn)程跟蹤分支之后,可以知道合并到哪個(gè)本地分支里
  • 使用git checkout檢查本地分支時(shí),可以輸出一些有用的信息:
    Your branch and the tracked remote branch 'origin/master'
    have diverged, and respectively have 3 and 384 different
    commit(s) each.

或者:

    Your branch is behind the tracked remote branch
    'origin/master' by 3 commits, and can be fast-forwarded.

允許使用的配置變量是:“branch.<local-branch-name>.merge”和“branch.<local-branch-name>.remote”,但通常情況下你不用考慮他們的設(shè)置。

當(dāng)從遠(yuǎn)程代碼倉(cāng)庫(kù)創(chuàng)建一個(gè)本地分支之后,你會(huì)注意到,“git branch -r”能列出很多遠(yuǎn)程跟蹤分支,但你的電腦上只有一個(gè)本地分支,你需要給上面的命令設(shè)置一個(gè)參數(shù),來(lái)指定本地分支和遠(yuǎn)程分支的對(duì)應(yīng)。

有一些術(shù)語(yǔ)上的說(shuō)法容易混淆需要注意一下:“track”在當(dāng)作參數(shù)"-track"使用時(shí),意思指通過(guò)本地分支對(duì)應(yīng)一個(gè)遠(yuǎn)程跟蹤分支。在遠(yuǎn)程跟蹤分支中則指遠(yuǎn)程代碼倉(cāng)庫(kù)中的跟蹤分支。有點(diǎn)繞口。。。

下面我們來(lái)看一個(gè)例子,如何從遠(yuǎn)程分支中更新本地代碼,以及如何把本地分支推送到一個(gè)新的遠(yuǎn)程倉(cāng)庫(kù)中。

從遠(yuǎn)端倉(cāng)庫(kù)進(jìn)行更新

如果我想從遠(yuǎn)端的源倉(cāng)庫(kù)更新到本地的代碼倉(cāng)庫(kù),可以輸入“git fetch origin”的命令,該命令的輸入類似如下格式:

  remote: Counting objects: 382, done.
  remote: Compressing objects: 100% (203/203), done.
  remote: Total 278 (delta 177), reused 103 (delta 59)
  Receiving objects: 100% (278/278), 4.89 MiB | 539 KiB/s, done.
  Resolving deltas: 100% (177/177), completed with 40 local objects.
  From ssh://longair@pacific.mpi-cbg.de/srv/git/fiji
     3036acc..9eb5e40  debian-release-20081030 -> origin/debian-release-20081030
   * [new branch]      debian-release-20081112 -> origin/debian-release-20081112
   * [new branch]      debian-release-20081112.1 -> origin/debian-release-20081112.1
     3d619e7..6260626  master     -> origin/master

最重要的是這兩行:

     3036acc..9eb5e40  debian-release-20081030 -> origin/debian-release-20081030
   * [new branch]      debian-release-20081112 -> origin/debian-release-20081112

第一行表明遠(yuǎn)端的origin/debian-release-20081030分支的提交(commit)ID已經(jīng)從3036acc更新為9eb5e40。箭頭前的部分是遠(yuǎn)端分支的名稱。第二行是我們采取的動(dòng)作,創(chuàng)建遠(yuǎn)程跟蹤分支(如果遠(yuǎn)程倉(cāng)庫(kù)有新的tags,git fetch也會(huì)一并下載到本地)。

前面那些行顯示出“git fetch”命令會(huì)將哪些文件下載到本地,這些文件一旦下載到本地之后,就可以在本地進(jìn)行任意操作了。

“git fetch”命令執(zhí)行完畢之后,還不會(huì)立即將下載的文件合并到你當(dāng)前工作目錄里,這就給你了一個(gè)選擇下一步操作的機(jī)會(huì),要是想將從遠(yuǎn)程分支下載的文件更新到你的工作目錄里,你需要執(zhí)行一個(gè)“合并(merge)”操作。例如,我當(dāng)前的本地分支為”master“(執(zhí)行g(shù)it checkout master后),這時(shí)我想執(zhí)行合并操作:

    git merge origin/master

( 幾句題外話:合并的時(shí)候有可能你還沒(méi)有對(duì)遠(yuǎn)程分支提交過(guò)任何的更改,或者可能是一個(gè)復(fù)雜的合并。)

如果你只是想看看本地分支和遠(yuǎn)程分支的差異,你可以使用下面的命令:

git diff master origin/master

單獨(dú)進(jìn)行下載和合并是一個(gè)好的做法,你可以先看看下載的是什么,然后再?zèng)Q定是否和本地代碼合并。而且分開(kāi)來(lái)做,可以清晰的區(qū)別開(kāi)本地分支和遠(yuǎn)程分支,方便選擇使用。

 

把你的變更推送到一個(gè)遠(yuǎn)程倉(cāng)庫(kù)

如何通過(guò)其他的方式呢? 假設(shè)你對(duì) “experimental”分支做了變更并且希望把他push到"origin"遠(yuǎn)程倉(cāng)庫(kù)中去. 你可以這樣做:

1 git push origin experimental

 

你可能將會(huì)收到:遠(yuǎn)程倉(cāng)庫(kù)無(wú)法fast-forward該分支的錯(cuò)誤信息, 這將意味著可能有別人push了不同的變更到了這個(gè)分支上.所以,你需要fetch和merge別人的變更并再次嘗試push操作.

擴(kuò)展閱讀: 如果這個(gè)分支在遠(yuǎn)程倉(cāng)庫(kù)里對(duì)應(yīng)不同的名稱(如:experiment-by-bob),你應(yīng)該這么做: 
git push origin experimental:experiment-by-bob

在舊版本的git里,如果“experiment-by-bob”不存在,命令應(yīng)該這么寫(xiě): 
      git push origin experimental:refs/heads/experiment-by-bob

這樣會(huì)首先創(chuàng)建遠(yuǎn)程分支。但git 1.6.1.2應(yīng)該就不用這么做了。參加下面Sitaram’s的評(píng)論。 
 如果本地分支和遠(yuǎn)程分支名稱相同,不需要特殊說(shuō)明系統(tǒng)將會(huì)自動(dòng)創(chuàng)建這個(gè)分支,就像常規(guī)的git push操作一樣。 

在實(shí)際應(yīng)用中,保持名稱相同可以減少混淆,因此“本地名稱和遠(yuǎn)程名稱”作為“refspec”參數(shù),我們不會(huì)進(jìn)行更多的討論。

git push的操作不會(huì)牽扯遠(yuǎn)程跟蹤分支(origin/experimental,只有在你下次進(jìn)行g(shù)it fetch時(shí)才會(huì)被更新。

上面這個(gè)說(shuō)法不對(duì),根據(jù)Deskin Miller的評(píng)論糾正:當(dāng)推送到對(duì)應(yīng)的遠(yuǎn)程分支后,你的遠(yuǎn)程跟蹤分支就會(huì)被更新。

為什么不用 git 的 pull?

雖然 git pull 大部分時(shí)候是好的,特別是如果你用CVS類型的方式使用Git時(shí),它可能正適合你。然而,如果你想用一個(gè)更地道的方式(建立很多主題分支,當(dāng)你需要時(shí)隨時(shí)改寫(xiě)本地歷史,等等)使用Git,那么習(xí)慣把 git fetch 和 git merge 分開(kāi)做會(huì)有很大幫助。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多