跟著小程一起聊聊GIT那點事

一、GIT發(fā)展史

同生活中的許多偉大事件一樣,Git 誕生于一個極富紛爭大舉創(chuàng)新的年代。Linux 內核開源項目有著為數眾廣的參與者。絕大多數的 Linux 內核維護工作都花在了提交補丁和保存歸檔的繁瑣事務上(1991-2002年間)。到 2002 年,整個項目組開始啟用分布式版本控制系統(tǒng) BitKeeper 來管理和維護代碼。

到 2005 年的時候,開發(fā) BitKeeper 的商業(yè)公司同 Linux 內核開源社區(qū)的合作關系結束,他們收回了免費使用 BitKeeper 的權力。這就迫使 Linux 開源社區(qū)(特別是 Linux 的締造者 Linus Torvalds )不得不吸取教訓,只有開發(fā)一套屬于自己的版本控制系統(tǒng)才不至于重蹈覆轍。他們對新的系統(tǒng)訂了若干目標:

  • 速度
  • 簡單的設計
  • 對非線性開發(fā)模式的強力支持(允許上千個并行開發(fā)的分支)
  • 完全分布式
  • 有能力高效管理類似 Linux 內核一樣的超大規(guī)模項目(速度和數據量)

自誕生于 2005 年以來,Git 日臻成熟完善,在高度易用的同時,仍然保留著初期設定的目標。它的速度飛快,極其適合管理大項目,它還有著令人難以置信的非線性分支管理系統(tǒng),可以應付各種復雜的項目開發(fā)需求。

二、如何安裝GIT
1、Ubuntu上安裝
    $ sudo apt-get install git-core
2、Windows上安裝
    有個叫做 msysGit 的項目提供了安裝包,參考:
    http://code.google.com/p/msysgit 
3、從源碼安裝
    Git的工作需要調用curl,zlib,openssl,expat,libiconv等庫的代碼,所有要先安裝這些依賴工具。
    $ sudo apt-get install curl-devel expat-devel gettext-devel openssl-devel zlib-devel
    再從下面的 Git 官方站點下載最新版本源代碼 :
    http://git-scm.com/download
    然后編譯并安裝,例如:
    $ tar -zxf git-1.6.0.5.tar.gz 
    $ cd git-1.6.0.5 
    $ make prefix=/usr/local all 
    $ sudo make prefix=/usr/local install 
    
    現在已經可以用 git 命令了,例如把 Git 項目倉庫克隆到本地,以便日后更新: 
    $ git clone git://git.kernel.org/pub/scm/git/git.git 

三、運行GIT前的配置

一般在新的系統(tǒng)上,我們都需要先配置下自己的 Git 工作環(huán)境。配置工作只需一次,以后升級時還會沿用現在的配置。當然,如果需要,你隨時可以用相同的命令修改已有的配置。

Git 提供了一個叫做 git config 的工具,專門用來配置或讀取相應的工作環(huán)境變量。而正是由這些環(huán)境變量,決定了 Git 在各個環(huán)節(jié)的具體工作方式和行為。這些變量可以存放在以下三個不同的地方:

  • /etc/gitconfig文件:
    系統(tǒng)中對所有用戶都普遍適用的配置。若使用 git config 時用 --system 選項,讀寫的就是這個文件。

  • ~/.gitconfig文件:用戶目錄下的配置文件只適用于該用戶。若使用 git config 時用 --global 選項,讀寫的就是這個文件。

  • 當前項目的 git 目錄中的配置文件(也就是工作目錄中的 .git/config 文件):這里的配置僅僅針對當前項目有效。每一個級別的配置都會覆蓋上層的相同配置,所以 .git/config 里的配置會覆蓋/etc/gitconfig 中的同名變量。

第一個要配置的是你個人的用戶名稱和電子郵件地址。這兩條配置很重要,每次 Git 提交時都會引用這兩條信息,說明是誰提交了更新,所以會隨更新內容一起被永久納入歷史記錄:

$ git config --global user.name "John Doe" 
$ git config --global user.email johndoe@example.com

如果用了 --global 選項,那么更改的配置文件就是位于你用戶主目錄下的那個,以后你所有的項目都會默認使用這里配置的用戶信息。如果要在某個特定的項目中使用其他名字或者電郵,只要去掉 --global 選項重新配置即可,新的設定保存在當前項目的 .git/config 文件里。

接下來要設置的是默認使用的文本編輯器。Git 需要你輸入一些額外消息的時候,會自動調用一個外部文本編輯器給你用。默認會使用操作系統(tǒng)指定的默認編輯器,一般可能會是 Vi 或者 Vim。如果你有其他偏好,比如 Emacs 的話,可以重新設置:
$ git config --global core.editor emacs

還有一個比較常用的是,在解決合并沖突時使用哪種差異分析工具。比如要改用 vimdiff 的話:
$ git config --global merge.tool vimdiff
Git可以理解 kdiff3,tkdiff,meld,xxdiff,emerge,vimdiff,gvimdiff,ecmerge,和 opendiff 等合并工具的輸出信息。當然,你也可以指定使用自己開發(fā)的工具。

查看配置信息
要檢查已有的配置信息,可以使用 git config --list 命令:

$ git config --list 
user.name=Scott Chacon 
user.email=schacon@gmail.com 

也可以直接查閱某個環(huán)境變量的設定,只要把特定的名字跟在后面即可,例如:

git config user.name 
Scott Chacon 
四、獲取GIT幫助

想了解 Git 的各種命令該怎么用,可以閱讀它們的使用幫助,方法有三:

$ git help <verb> 
$ git <verb> --help 
$ man git-<verb>

比如,要學習 config 命令可以怎么用,運行:
$ git help config

我們隨時都可以瀏覽這些幫助信息而無需連網。不過,要是你覺得還不夠,可以到 Frenode IRC 服務器(irc.freenode.net)上的 #git 或 #github 頻道尋求他人幫助。這兩個頻道上總有著上百號人,大多都有著豐富的 git 知識,并且樂于助人。

五、Git中文件的狀態(tài)和基本工作流程

對于任何一個文件,在 Git 內都只有三種狀態(tài):已提交(committed),已修改(modified)和已暫存(staged)。已提交表示該文件已經被安全地保存在本地數據庫中了;已修改表示修改了某個文件,但還沒有提交保存;已暫存表示把已修改的文件放在下次提交時要保存的清單中。

由此我們看到 Git 管理項目時,文件流轉的三個工作區(qū)域:Git 的本地數據目錄,工作目錄以及暫存區(qū)域。

Paste_Image.png

每個項目都有一個 git 目錄,它是 Git 用來保存元數據和對象數據庫的地方。該目錄非常重要,每次克隆鏡像倉庫的時候,實際拷貝的就是這個目錄里面的數據。

從項目中取出某個版本的所有文件和目錄,用以開始后續(xù)工作的叫做工作目錄。這些文件實際上都是從 git 目錄中的壓縮對象數據庫中提取出來的,接下來就可以在工作目錄中對這些文件進行編輯。

所謂的暫存區(qū)域只不過是個簡單的文件,一般都放在 git 目錄中。有時候人們會把這個文件叫做索引文件,不過標準說法還是叫暫存區(qū)域。

基本的 Git 工作流程如下所示:

  • 在工作目錄中修改某些文件。
  • 對這些修改了的文件作快照,并保存到暫存區(qū)域。
  • 提交更新,將保存在暫存區(qū)域的文件快照轉儲到 git 目錄中。

所以,我們可以從文件所處的位置來判斷狀態(tài):如果是 git 目錄中保存著的特定版本文件,就屬于已提交狀態(tài);如果作了修改并已放入暫存區(qū)域,就屬于已暫存狀態(tài);如果自上次取出后,作了修改但還沒有放到暫存區(qū)域,就是已修改狀態(tài)。

六、Git常用命令
git init
git clone
git add <file>
git commit
git diff
git diff --cached
git rm <file>
git rm <file> --cached
git mv <file> <newfile>
git status
git log
git commit --amend
git reset HEAD <file>
git reset --soft HEAD~n
git reset --hard HEAD~n
git checkout -- <file>
git checkout <file>
git remote
git remote add [shortname] [url]
git fetch [remotename]
git push [remotename] [localbranch]:[remotebranch]
git remote show [remotename]
git remote rename [remotename] [new-remotename]
git remote rm [remotename]
git tag
git tag -a [tagname] –m [comments]
git push [remotename] [tagname]
git push [remotename] –tags
git branch [branchname]
git checkout [branchname]
git branch -d [branchname]
git merge [branchname]
git branch
git checkout -b [branchname] [remotename]/[branchname]
git push [remotename] :[remotebranch]
git rebase [branchname]
git pull

七、Git命令使用舉例
  • 從當前目錄初始化
    要對現有的某個項目開始用 Git 管理,只需到此項目所在的目錄,執(zhí)行:
    git init
    初始化后,在當前目錄下會出現一個名為 .git 的目錄,所有 Git 需要的數據和資源都存放在這個目錄中。

  • 從現有倉庫克隆,如克隆git的代碼庫
    git clone git://git.kernel.org/pub/scm/git/git.git

  • 跟蹤新文件和暫存已修改文件
    git add <file>

  • 提交更新
    git commit
    這種方式會啟動文本編輯器以便輸入本次提交的說明。也可以使用 -m 參數后跟提交說明的方式,在一行命令中提交更新:
    git commit -m “Initial commit of test repo”

  • 查看已暫存和未暫存的修改
    git diff
    此命令比較的是工作目錄中當前文件和暫存區(qū)域快照之間的差異,也就是修改之后還沒有暫存起來的變化內容。若要看已經暫存起來的文件和上次提交時的快照之間的差異,可以用 git diff --cached 命令

  • 移除文件
    要從 Git 中移除某個文件,就必須要從已跟蹤文件清單中移除(確切地說,是從暫存區(qū)域移除),然后提交。
    git rm <file>
    另外一種情況是,我們想把文件從 Git 倉庫中刪除(亦即從暫存區(qū)域移除),但仍然希望保留在當前工作目錄中。 可以用--cached選項
    git rm --cached <file>

  • 移動文件
    git mv <file> <newfile>

  • 檢查當前文件狀態(tài)
    git status

  • 查看提交歷史
    git log

  • 修改最后一次提交
    有時候我們提交完了才發(fā)現漏掉了幾個文件沒有加,或者提交信息寫錯了。想要撤消剛才的提交操作,可以使用 --amend 選項重新提交:
    git commit --amend
    如果剛才提交完沒有作任何改動,直接運行此命令的話,相當于有機會重新編輯提交說明,而所提交的文件快照和之前的一樣。如果剛才提交時忘了暫存某些修改,可以先補上暫存操作,然后再運行 --amend 提交。

  • 取消已經暫存的文件
    git reset HEAD <file>

  • 取消對文件的修改
    git checkout -- <file>
    git checkout <file> 一般與上面的命令效果相同,但如果有一個分支名與文件名相同,就不一樣了。加--來消除歧義。

  • 查看當前的遠程庫
    git remote
    也可以加上 -v 選項,顯示對應的克隆地址
    git remote -v

  • 添加遠程倉庫
    git remote add [shortname] [url]

  • 從遠程倉庫抓取數據
    git fetch [remotename]
    此命令會到遠程倉庫中拉取所有你本地倉庫中還沒有的數據。運行完成后,你就可以在本地訪問該遠程倉庫中的所有分支,將其中某個分支合并到本地,或者只是取出某個分支,一探究竟。

  • 推送數據到遠程倉庫
    git push [remotename] [localbranch]:[remotebranch]

  • 查看遠程倉庫信息
    git remote show [remotename]

  • 遠程倉庫的刪除和重命名

git remote rename [remotename] [new-remotename]
git remote rm [remotename]
  • 顯示已有的標簽
    git tag

  • 新建標簽
    git tag -a [tagname] –m [comments]
    如果想為以前的某次提交打標簽,只要在打標簽的時候跟上對應提交對象的校驗和(或前幾位字符)即可 。

  • 用某個標簽新建分支
    git checkout –b [branchname] [tagname]

  • 分享標簽
    默認情況下,git push 并不會把標簽傳送到遠端服務器上,只有通過顯式命令才能分享標簽到遠端倉庫。
    git push [remotename] [tagname]
    如果要一次推送所有(本地新增的)標簽上去,可以使用 --tags 選項:
    git push [remotename] –tags

  • 創(chuàng)建分支
    git branch [branchname]

  • 切換分支
    git checkout [branchname]

  • 新建并切換到該分支
    git checkout -b [branchname]

  • 刪除分支
    git branch -d [branchname]

  • 合并分支
    git merge [branchname]
    以上命令將[branchname]分支合并到當前分支

  • 查看分支
    git branch

  • 遠程分支和創(chuàng)建跟蹤分支
    遠程分支(remote branch)是對遠程倉庫狀態(tài)的索引。它們是一些無法移動的本地分支;只有在進行 Git 的網絡活動時才會更新。遠程分支就像是書簽,提醒著你上次連接遠程倉庫時上面各分支的位置。我們用 (遠程倉庫名)/(分支名) 這樣的形式表示遠程分支。從遠程分支檢出的本地分支成為跟蹤分支。
    git checkout -b [branchname] [remotename]/[branchname]
    或者 git checkout --track [remotename]/[branchname]

  • 刪除遠程分支
    git branch -r -d origin/[branchname]

  • 衍合
    git rebase [branchname]

  • 從遠程倉庫抓取數據并merge
    git pull

八、Git分支

在 Git 中提交時,會保存一個提交(commit)對象,它包含一個指向暫存內容快照的指針,作者和相關附屬信息,以及一定數量(也可能沒有)指向該提交對象直接祖先的指針:第一次提交是沒有直接祖先的,普通提交有一個祖先,由兩個或多個分支合并產生的提交則有多個祖先。

為直觀起見,我們假設在工作目錄中有三個文件,準備將它們暫存后提交。暫存操作會對每一個文件計算校驗和(即SHA-1 哈希字串),然后把當前版本的文件快照保存到 Git 倉庫中(Git 使用 blob 類型的對象存儲這些快照),并將校驗和加入暫存區(qū)域?,F在,Git 倉庫中有五個對象:三個表示文件快照內容的 blob 對象;一個記錄著目錄樹內容及其中各個文件對應 blob 對象索引的 tree 對象;以及一個包含指向 tree 對象(根目錄)的索引和其他提交信息元數據的 commit 對象 。

概念上來說,倉庫中的各個對象保存的數據和相互關系看起來 如下所示:

Paste_Image.png

多次提交后,倉庫歷史如下:

Paste_Image.png

Git 中的分支,其實本質上僅僅是個指向 commit 對象的可變指針。

Paste_Image.png

Git 通過個git branch命令創(chuàng)建分支,比如新建一個testing分支:
git branch testing
這會在當前commit對象上新建一個分支指針, 同時Git保存著一個名為HEAD的特別指針,來讓Git知道當前在哪個分支上工作。如下:

Paste_Image.png

要切換到其他分支,可以執(zhí)行命令git checkout,如切換到新建的testing分支:
git checkout testing
這樣HEAD就指向testing分支,如下:

Paste_Image.png

此時在testing分支上工作,如果有新的提交,提交后的結果如下:

Paste_Image.png

此時切換回master分支再提交后的結果如下:

Paste_Image.png
九、Git分支合并與衍合

如將experiment分支合并回master分支執(zhí)行以下命令:

git checkout master
git merge experiment```

合并前后如下所示:


![Paste_Image.png](http://upload-images.jianshu.io/upload_images/1049928-78e3e7bdccdc4965.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

有時候合并操作并不會如此順利。如果你修改了兩個待合并分支里同一個文件的同一部分,Git 就無法干凈地把兩者合到一起,這種問題只能由人來解決。如果你想用一個有圖形界面的工具來解決這些問題,不妨運行 git mergetool,它會調用一個可視化的合并工具并引導你解決所有沖突。確認所有沖突都解決后,可以用 git commit 來完成這次合并提交。

其實,合并兩個分支還有另外一個選擇:你可以把在 C3 里產生的變化補丁重新在 C4 的基礎上打一遍。在 Git 里,這種操作叫做衍合(rebase)。有了 rebase 命令,就可以把在一個分支里提交的改變在另一個分支里重放一遍。

git checkout experiment
git rebase master

衍合前后如下所示:

![Paste_Image.png](http://upload-images.jianshu.io/upload_images/1049928-1d40b0417c9988aa.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

再進行一次快進:

git checkout master
git merge experiment

結果如下所示:

![Paste_Image.png](http://upload-images.jianshu.io/upload_images/1049928-f6d5ba058b7464a5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/500)

現在,合并后的 C3(即現在的 C3’)所指的快照,同三方合并例子中的 C5 所指的快照內容一模一樣了。最后整合得到的結果沒有任何區(qū)別,但衍合能產生一個更為整潔的提交歷史。如果視察一個衍合過的分支的歷史記錄,看起來更清楚:仿佛所有修改都是先后進行的,盡管實際上它們原來是同時發(fā)生的。 

但衍合也并不是完美無缺的,一句話可以總結這點:
永遠不要衍合那些已經推送到公共倉庫的更新。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 1. 安裝 Github 查看是否安裝git: $ git config --global user.name "...
    Albert_Sun閱讀 13,835評論 9 163
  • Git是目前最流行的版本管理系統(tǒng),也是最先進的分布式版本控制系統(tǒng)(distributed version cont...
    pro648閱讀 5,950評論 1 17
  • 聲明:這篇文章來源于廖雪峰老師的官方網站,我僅僅是作為學習之用 Git簡介 Git是什么? Git是目前世界上最先...
    橫渡閱讀 4,108評論 3 27
  • 站在走廊的窗戶前,想起來畢業(yè)前夕每天晚上在寢室欣賞夜色的場景那個時候心里就知道,以后的歲月里我一定會懷念那平靜的時...
    你好李小潘閱讀 426評論 0 1
  • 養(yǎng)多肉,專業(yè)的花客會三令五申的強調花盆選擇的重要性,而對于觀賞玩肉的我來說,讓多肉更創(chuàng)意更新意似乎更有意義。相信多...
    九界jiujie閱讀 832評論 0 0

友情鏈接更多精彩內容