Git 初學者教程
一共分為三個部分,可挑選想看內容:
一、Git基礎
二、Git分支
三、Git遠程操作
一、Git基礎
1.1 記錄快照
Git 保存數據是對文件系統的一組快照。 每次你提交更新時,它主要對當時的全部文件製作一個快照。如果文件沒有修改,Git 只保留一個鏈接指向之前存儲的文件。
1.2 三個工作區域
Git 有三個區域:工作目錄(Working Directory),暫存目錄(Stage or Index),倉庫(Git directory)。 基本的 Git 工作流程如下:
- 在工作目錄中修改文件。
- 暫存文件,將文件的快照放入暫存區域。
- 提交更新,找到暫存區域的文件,將快照永久性存儲到 Git 倉庫目錄。
工作目錄就是你正在耕耘的項目文件夾,當你向暫存目錄提交時,會以快照的形式被存放其中。提交後若修改了工作目錄中的文件,再次提交會生成新的快照覆蓋到暫存目錄。
倉庫,是 Git 中最重要的部分,由圖中綠色塊組成,數據結構看起來像一個單向鏈表,但後面會提到其實是樹。每一個節點都是印有哈希值的快照組,也就是項目的一個版本。倉庫中有一個或多個指針,代表分支,指向某一個節點。只有一個 HEAD 指針指向正在工作的分支。當你從暫存目錄向倉庫提交時,Git 用暫存區域的文件創建一個新的提交,並把此時的節點設為父節點。然後把當前分支指向新的提交節點。下一圖中,當前分支是master。 在運行命令之前,master指向ed489,提交後,master指向新的節點f0cec並以ed489作為父節點。下二圖中,在master分支的祖父節點maint分支進行一次提交,生成了1800b。
1.3 基本用法
上面的四條命令在工作目錄、暫存目錄(也叫做索引)和倉庫之間複製文件。
git add files
把當前文件放入暫存區域。git commit
給暫存區域生成快照並提交。git reset -- files
用來撤銷最後一次git add files
,你也可以用git reset
撤銷所有暫存區域文件。git checkout -- files
把文件從暫存區域複製到工作目錄,用來丟棄本地修改。
你可以用 git reset -p
, git checkout -p
, or git add -p
進入交互模式。
也可以跳過暫存區域直接從倉庫取出文件或者直接提交代碼。
git commit -a
相當於運行git add
把所有當前目錄下的文件加入暫存區域再運行。git commit files
進行一次包含最後一次提交加上工作目錄中文件快照的提交。並且文件被添加到暫存區域。git checkout HEAD -- files
回滾到複製最後一次提交。
diff
checkout
checkout
命令用於從歷史提交(或者暫存區域)中拷貝文件到工作目錄,也可用於切換分支。
當給定某個文件名(或者打開-p選項,或者文件名和-p選項同時打開)時,git會從指定的提交中拷貝文件到暫存區域和工作目錄。比如,git checkout HEAD~ foo.c會將提交節點HEAD~(即當前提交節點的父節點)中的foo.c複製到工作目錄並且加到暫存區域中。(如果命令中沒有指定提交節點,則會從暫存區域中拷貝內容。)注意當前分支不會發生變化。
當不指定文件名,而是給出一個(本地)分支時,那麼HEAD標識會移動到那個分支(也就是說,我們「切換」到那個分支了),然後暫存區域和工作目錄中的內容會和HEAD對應的提交節點一致。新提交節點(下圖中的a47c3)中的所有文件都會被複制(到暫存區域和工作目錄中);只存在於老的提交節點(ed489)中的文件會被刪除;不屬於上述兩者的文件會被忽略,不受影響。
該做法盡量避免。如果既沒有指定文件名,也沒有指定分支名,而是一個標籤、遠程分支、SHA-1值或者是像master~3類似的東西,就得到一個匿名分支,稱作detached HEAD(被分離的HEAD標識)。這樣可以很方便地在歷史版本之間互相切換。比如說你想要編譯1.6.6.1版本的git,你可以運行git checkout v1.6.6.1(這是一個標籤,而非分支名),編譯,安裝,然後切換回另一個分支,比如說git checkout master。
二、Git分支
2.1 創建分支
創建分支其實就是創建了一個新的指針。使用的指令是git branch
:
$ git branch testing
這會在當前所在的提交對象上創建一個testing指針, 但是此時HEAD指針仍然指向原分支,所以準備在testing分支上工作前,需要切換分支。
2.2 切換分支
需要使用的指令是git checkout
:
$ git checkout testing
這樣HEAD就指向testing分支了,此時提交代碼將會和master分離,產生分叉。
當然,需要將HEAD切換回master才能在master分支上提交。
以上兩條命令可以合併成一句,用一個帶有-b
參數的git checkout
命令:
git checkout -b testing
2.4 合併分支
是時候將分支的代碼整合起來,需要用git merge
命令合併分支。首先確定需要併入到哪一條分支,通常情況下會需要併入到master,所以先將HEAD切換到master:
$ git checkout masterSwitched to branch master$ git merge iss53Merge made by the recursive strategy.index.html | 1 +1 file changed, 1 insertion(+)
Git 將此次合併的結果做了一個新的快照並且讓master指向它。這裡有一個特殊情況就是當master所指的快照是分支的父節點,那麼merge操作將會直接移動master指針到分支指針的位置。
如果沒有任何衝突,那麼合併到這裡就結束了。但大部分情況,代碼往往不能簡單的自動合併,比如兩個分支均修改了同一個變數。任何因包含合併衝突而有待解決的文件,都會以未合併狀態標識出來。Git 會在有衝突的文件中加入標準的衝突解決標記,這樣你可以打開這些包含衝突的文件然後手動解決衝突。出現衝突的文件會包含一些特殊區段,看起來像下面這個樣子:
<<<<<<< HEAD:index.html<div id="footer">contact : email.support@github.com</div>=======<div id="footer"> please contact us at support@github.com</div>>>>>>>> iss53:index.html
此時只需要妥善處理衝突,確保已經把 <<<<<<<
, =======
, 和 >>>>>>>
這些行完全刪除。在解決了所有文件里的衝突之後,對每個文件使用 git add 命令來將其標記為衝突已解決。一旦暫存這些原本有衝突的文件,Git 就會將它們標記為衝突已解決。
這就是 Git 分支的基本操作,工作中使用往往需要一定的管理策略,可以參考阮一峰的 Git分支管理策略。
三、Git遠程操作
遠程操作僅僅多出一個工作區域,即遠程倉庫(Remote)。詳見下圖:
git remote
一個本地倉庫可以和多個遠程倉庫交流。為了便於管理,Git要求每個遠程主機都必須指定一個主機名。git remote
就用於管理主機名。 不帶選項的時候,git remote命令列出所有遠程主機。
$ git remote origin
使用-v選項,可以參看遠程主機的網址。
$ git remote -v origin git@github.com:jquery/jquery.git (fetch) origin git@github.com:jquery/jquery.git (push)
上面命令表示,當前只有一台遠程主機,叫做origin,以及它的網址。
克隆版本庫的時候,所使用的遠程主機自動被Git命名為origin。如果想用其他的主機名,需要用git clone命令的-o選項指定。
$ git clone -o jQuery https://github.com/jquery/jquery.git$ git remote jQuery
面命令表示,克隆的時候,指定遠程主機叫做jQuery。
git remote show命令加上主機名,可以查看該主機的詳細信息。
$ git remote show <主機名>
git remote add命令用於添加遠程主機。
$ git remote add <主機名> <網址>
git remote rm命令用於刪除遠程主機。
$ git remote rm <主機名>
git remote rename命令用於遠程主機的改名。
$ git remote rename <原主機名> <新主機名>
取回代碼
Git的遠程操作基本上就是兩類:取回代碼和上傳代碼。
git clone
如果新建了一個空白的本地倉庫,通常要克隆遠程倉庫到本地,這時就要用到git clone
命令。
$ git clone <版本庫的網址>
比如,克隆jQuery的版本庫。
$ git clone https://github.com/jquery/jquery.git
該命令會在本地主機生成一個目錄,與遠程主機的版本庫同名。如果要指定不同的目錄名,可以將目錄名作為git clone
命令的第二個參數。
$ git clone <版本庫的網址> <本地目錄名>
git clone
支持多種協議,除了HTTP(s)以外,還支持SSH、Git、本地文件協議等,下面是一些例子。
$ git clone http[s]://example.com/path/to/repo.git/$ git clone ssh://example.com/path/to/repo.git/$ git clone git://example.com/path/to/repo.git/$ git clone /opt/git/project.git $ git clone file:///opt/git/project.git$ git clone ftp[s]://example.com/path/to/repo.git/$ git clone rsync://example.com/path/to/repo.git/
SSH協議還有另一種寫法。
$ git clone [user@]example.com:path/to/repo.git/
通常來說,Git協議下載速度最快,SSH協議用於需要用戶認證的場合。各種協議優劣的詳細討論請參考官方文檔。
git fetch
當遠程倉庫有更新需要取回本地時,就要用到git fetch
命令。
$ git fetch <遠程主機名>
上面命令將某個遠程主機的更新,全部取回本地。默認情況下,git fetch
取回所有分支(branch)的更新。如果只想取回特定分支的更新,可以指定分支名。
$ git fetch <遠程主機名> <分支名>
比如,取回origin主機的master分支。
$ git fetch origin master
所取回的更新,在本地主機上要用」遠程主機名/分支名」的形式讀取。比如origin主機的master,就要用origin/master讀取。
git branch
命令的-r選項,可以用來查看遠程分支,-a選項查看所有分支。
$ git branch -rorigin/master$ git branch -a* master remotes/origin/master
上面命令表示,本地主機的當前分支是master,遠程分支是origin/master。
取回遠程主機的更新以後,可以在它的基礎上,使用git checkout
命令創建一個新的分支。
$ git checkout -b newBrach origin/master
上面命令表示,在origin/master的基礎上,創建一個新分支。
此外,也可以使用git merge
命令或者git rebase
命令,在本地分支上合併遠程分支。
$ git merge origin/master# 或者$ git rebase origin/master
上面命令表示在當前分支上,合併origin/master。
git pull
git pull
命令的作用是,取回遠程主機某個分支的更新,再與本地的指定分支合併。
$ git pull <遠程主機名> <遠程分支名>:<本地分支名>
實質上,這等同於先做git fetch
,再做git merge
。
$ git fetch origin$ git merge origin/next
在某些場合,Git會自動在本地分支與遠程分支之間,建立一種追蹤關係(tracking)。比如,在git clone
的時候,所有本地分支默認與遠程主機的同名分支,建立追蹤關係,也就是說,本地的master分支自動」追蹤」origin/master分支。
Git也允許手動建立追蹤關係。
git branch --set-upstream master origin/next
上面命令指定master分支追蹤origin/next分支。
如果當前分支與遠程分支存在追蹤關係,git pull
就可以省略遠程分支名。
$ git pull origin
上面命令表示,本地的當前分支自動與對應的origin主機」追蹤分支」(remote-tracking branch)進行合併。
如果當前分支只有一個追蹤分支,連遠程主機名都可以省略,當前分支自動與唯一一個追蹤分支進行合併。
$ git pull
如果合併需要採用rebase模式,可以使用–rebase選項。
$ git pull --rebase <遠程主機名> <遠程分支名>:<本地分支名>
上傳代碼
上傳之前,為了防止遠程倉庫代碼庫發生衝突,一般都需要先git pull
,以確保上傳代碼沒有過舊。
git push
git push命令用於將本地分支的更新,推送到遠程主機。它的格式與git pull命令相仿。
$ git push <遠程主機名> <本地分支名>:<遠程分支名>
如果當前分支與遠程分支之間存在追蹤關係,則本地分支和遠程分支都可以省略。
$ git push origin
上面命令表示,將當前分支推送到origin主機的對應分支。
如果當前分支只有一個追蹤分支,那麼主機名都可以省略。
$ git push
如果當前分支與多個主機存在追蹤關係,則可以使用-u選項指定一個默認主機,這樣後面就可以不加任何參數使用git push
。
$ git push -u origin master
迄今,Git初學者系列結束了。該系列僅僅介紹日常工作學習中需要的 Git 操作,如果有更高的需求或其他疑問,請參見 Pro Git。
本文參考博客:LiaoHanfus。
推薦閱讀:
※Git的基礎使用教程
※GitHub & Bitbucket & GitLab & Coding 的對比分析
※Github上都有哪些有用但不為大家熟知的小功能?
※Git Tips #1:不再輸錯 git 命令
※git bash在輸入git commit -m的時候忘記輸入信息,卡在一個頁面無法退出怎麼解決?