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