後記:寫(xiě)一寫(xiě)覺(jué)得這個(gè)系列對初學(xué)者可能不太容易了解… XD 要寫(xiě)出簡(jiǎn)單易懂的說(shuō)明還真是需要花點(diǎn)功夫,想想拖稿太久還是作罷。
用 Git 就是要愛(ài)用 Branch 啊,Branch 很好用,開(kāi) Branch 不用錢(qián)。開(kāi) Branch的情境除了在上一篇中提到因應產(chǎn)品 release 需求的 stable/production branch 之外,其他開(kāi) branch 情況有:
這些事情都可以先在本地開(kāi) local branch 做,而不需要立即 Push 分享給別人。
git branch <new_branch_name> 建立本地 local branch
git branch -m <old_name> <new_name> 改名字 (如果有同名會(huì )失敗,改用 -M可以強制覆蓋)
git branch 列出目前有那些 branch 以及目前在那個(gè) branch
git checkout <branch_name> 切換 branch (注意到如果你有檔案修改了卻還沒(méi) commit,會(huì )不能切換branch,解法稍後會(huì )談)
git checkout -b <new_branch_name> (<from_branch_name>) 本地建立branch 並立即 checkout 切換過(guò)去
git branch -d <branch_name> 刪除 local branch
開(kāi) Branch 最大的好處除了可以不影響 stable 和其他分支版本的開(kāi)發(fā),另一個(gè)超棒的地方是”你可以決定 Merge的方式”。Git 的 Merge 方式可以分成四種:
其中 rebase 比較難理解會(huì )在下一篇再詳述:
git merge <branch_name> 合併另一個(gè) branch,若沒(méi)有 conflict 衝突會(huì )直接commit。若需要解決衝突則會(huì )再多一個(gè) commit。
git merge --squash <branch_name> 將另一個(gè) branch 的 commit合併為一筆,特別適合需要做實(shí)驗的 fixes bug 或 new feature,最後只留結果。合併完不會(huì )幫你先 commit。
git cherry-pick 321d76f 只合併特定其中一個(gè) commit。如果要合併多個(gè),可以加上 -n 指令就不會(huì )先幫你commit,這樣可以多 pick幾個(gè)要合併的 commit,最後再 git commit 即可。
使用 merge 可能會(huì )有部分程式碼會(huì ) conflict 衝突:簡(jiǎn)單的情況只要編輯檔案處理 <<<< =====>>>>> 即可,然後重新 add 到 staging area 並 commit (沒(méi)有像 SVN 的resolve 指令)。複雜一點(diǎn)的可以再用 git mergetool 選檔案合併的 GUI 工具 (OS X 下面可以用 opendiff,linux 可以用 kdiff3 ),處理好後 git commit。
一旦 merge 好了,git branch -d <branch_name> 可以刪除 branch。但如果要刪除的branch 還沒(méi)有合併,就會(huì )有錯誤訊息。如果真的要強制刪除可以用 -D
Git 的 working tree 是從 SVN 換過(guò)來(lái)一個(gè)不習慣的地方,因為它只是一個(gè)工作暫存區,在切換 Branch時(shí)就會(huì )整個(gè)換掉。也因為如此,如果有檔案有修改還沒(méi)有 commit 出去,切換 branch 時(shí)就會(huì )出現 error 不能切換(除非是新的 untracking 檔案),例如有修改還沒(méi) add 會(huì )出現 error: Entry ‘ooxx’ not uptodate.Cannot merge. 有修改且已經(jīng)add(還沒(méi)ci)會(huì )出現 error: Entry ‘ooxx’ would beoverwritten by merge. Cannot merge.
最理想的處理當然是事情剛好做到一個(gè)段落,把東西 commit 出去才切換 branch 做事。不過(guò)事情總有臨時(shí),如果要換 branch的暫時(shí)的解決方式是使用 git stash 會(huì )先把修改暫存下來(lái),要回復則執行 git stash pop。下一篇等你學(xué)會(huì ) git reset之後,你會(huì )發(fā)現就算把還沒(méi)完成的東西 commit 也不會(huì )怎麼樣,只要還沒(méi) push 出去一切 commit 紀錄都是可以改的。
首先要認識的是 Protocol,像在 Github 上面看自己的 Project,會(huì )有分 Public Clone URL 跟 YourClone URL,這有什麼差?
其中 Github 就是同時(shí)用 SSH + Git protocol,兼顧認證需求及速度。
git clone <remote_address>
git checkout --track -b foobar origin/foobar 將遠端的 branch checkout回來(lái)並建立一個(gè)新的 local branch,加上 --track 表示你之後還要pull、push回去,所以請 Git 記住對應關(guān)係。
git pull (<local_branch_name> origin/<remote_branch_name>)去遠端 fetch 新版並 merge 進(jìn) local branch
git push 將 local branch 的 commit 紀錄更新到遠端
git pull 要注意的是,如果別人在你上次 pull 之後有 push 新東西上去(也就是說(shuō)跟你的 branch產(chǎn)生分岔了),此時(shí)有兩種情況: 一是 Git 可以順利 auto merge 的話(huà),git 會(huì )自動(dòng)多一次 mergecommit,這也就為什麼常常 log 會(huì )跑出 Merge branch ‘master’ of git@foobar.com。二是如果有conflict,這時(shí)候就需要你手動(dòng)處理然後 commit。話(huà)說(shuō)如果覺(jué)得這種 local branch 和 remote branch 的merge commit log 很煩,建議可以改使用 git pull –rebase 指令來(lái)變成 fast-forward 形式(就會(huì )變得像 svn up,而不會(huì )有 merge commit log)。rebase的意思可能要下一篇才會(huì )詳細說(shuō)明的清楚,簡(jiǎn)單的說(shuō)(?),就是先砍掉 local branch 分岔點(diǎn)之後自己的 commit,然後把遠端的commit 先一個(gè)個(gè) apply 進(jìn)來(lái),最後再把自己的 commit 再 apply 進(jìn)去 (如果有 conflict會(huì )中途停下來(lái),等你修好才會(huì )繼續 apply),如此一來(lái)看線(xiàn)圖就會(huì )變成一條線(xiàn)而已,也就沒(méi)有所謂 merge 這個(gè)動(dòng)作了。
git push 預設的遠端是 origin,並且會(huì )將所有有和 remote 有對應的 local branch 都 push上去。如果要把新的 local branch push 上去,需要下 git push origin<local_vranch_name> 指令。
git push 也可能會(huì )失敗,例如出現 ! [rejected] master -> master (non-fastforward),這個(gè) non-fast forward 的意思是你的 parent commit 和遠端的不相同,也就是線(xiàn)圖有分岔,需要先pull 回來(lái)處理好 merge 才能 push 上去。
fast-forward 在 Git 是一種 merge 術(shù)語(yǔ),當 B branch (例如一個(gè) local branch) 是從 Abranch (例如一個(gè) remote branch) 的最新版(HEAD)分支出來(lái)的,那當 A 要把 B merge 進(jìn)來(lái)時(shí),因為 B 的parent commit 是 A 的 HEAD,所以這兩個(gè) branch 唯一的差異就是 B 後來(lái)的 commit 而已,而不會(huì )有任何conflict。所以實(shí)際上的動(dòng)作只要把 A 的 HEAD 改成 B 的 HEAD 就好了,線(xiàn)圖上這兩個(gè) branch 根本是同一條線(xiàn),此謂fast-forward。
其他操作還有:
git fetch 把遠端的 branch 更新下載回來(lái),但不會(huì ) merge 到 local branch
git branch -r 顯示 local 有追蹤的遠端 branch。注意到你不能直接修改這個(gè) remote branch,一定要用一個(gè)local branch 對應它。
git remote show origin 顯示遠端 server 的 branch
git remote add foobar git:// 可以新增別的 repo. 位置,於是 pull的時(shí)候就可以指定要從哪一個(gè)遠端更新回來(lái)。
git push origin :foobar 刪除遠端的 branch
因為遠端的操作指令比較雜,所以也有人寫(xiě)了 git_remote_branch來(lái)簡(jiǎn)化操作。
聯(lián)系客服