1、實驗說明css
1. 內容簡介html
本節爲版本控制系統和 Git 的歷史介紹,不包含實驗操做內容。Git 實驗操做的內容從第二節開始。git
2. 課程來源github
感謝譯者 liuhui998 受權,本實驗課程基於 《Git Community Book 中文版》 製做。web
3.課程學習說明編程
學習本課程須要有必定的Linux基礎,熟悉Linux的經常使用命令。vim
基本用法部分的實驗已經涵蓋了最經常使用的 git 操做,中級用法能夠簡單瞭解,用到時再查詳細文檔。緩存
2、Git 誕生安全
同生活中的許多偉大事件同樣,Git 誕生於一個極富紛爭大舉創新的年代。1991年,Linus 建立了開源的 Linux,而且有着爲數衆多的參與者。雖然有世界各地的志願者爲 Linux 編寫代碼,可是絕大多數的 Linux 內核維護工做都花在了提交補丁和保存歸檔的繁雜事務上(1991-2002年間)。在這期間,全部的源代碼都是由 Linus 手工合併。服務器
由於 Linus 堅決地反對 CVS 和 SVN,這些集中式的版本控制系統不但速度慢,並且必須聯網才能使用。雖然有一些商用的版本控制系統,比 CVS、SVN 好用,但那是付費的,和 Linux 的開源精神不符。
不過,到了 2002 年,Linux 系統已經發展了十年了,代碼庫之大讓 Linus 很難繼續經過手工方式管理了,社區的弟兄們也對這種方式表達了強烈不滿,因而整個項目組啓用了一個商業版本的分佈式版本控制系統 BitKeeper 來管理和維護代碼。BitKeeper 的東家 BitMover 公司出於人道主義精神,受權Linux 社區無償使用這個版本控制系統。
安定團結的大好局面在 2005 年被打破,開發 BitKeeper 的商業公司同 Linux 內核開源社區的合做關係結束,緣由是 Linux 社區牛人彙集,開發 Samba 的Andrew 試圖破解 BitKeeper 的協議,這麼幹的其實也不僅他一個,可是被 BitMover 公司發現了,因而 BitMover 公司收回了 Linux 社區的無償使用權。這就迫使 Linux 開源社區( 特別是 Linux 的締造者 Linus Torvalds )不得不吸收教訓,只有開發一套屬於本身的版本控制系統纔不至於重蹈覆轍。
他們對新的系統制訂了若干目標:速度、簡單的設計、對非線性開發模式的強力支持(容許上千個並行開發的分支)、徹底分佈式、有能力高效管理相似 Linux 內核同樣的超大規模項目(速度和數據量)。自誕生於 2005 年以來,Git 日臻成熟完善,迅速成爲最流行的分佈式版本控制系統,在高度易用的同時,仍然保留着初期設定的目標。它的速度飛快,極其適合管理大項目,它還有着使人難以置信的非線性分支管理系統,能夠應付各類複雜的項目開發需求。2008 年,GitHub 網站上線了,它爲開源項目免費提供 Git 存儲,無數開源項目開始遷移至 GitHub,包括 jQuery,PHP,Ruby 等等。
歷史就是這麼偶然,若是不是當年 BitMover 公司威脅 Linux 社區,可能如今咱們就沒有免費而超級好用的 Git 了。
3、版本控制系統
Linus 一直痛恨的 CVS 及 SVN 都是集中式的版本控制系統,而 Git 是分佈式版本控制系統,集中式和分佈式版本控制系統有什麼區別呢?
先說集中式版本控制系統,版本庫是集中存放在中央服務器的,而你們工做的時候,用的都是本身的電腦,因此要先從中央服務器取得最新的版本,而後開始工做,工做完成,再把本身的修訂推送給中央服務器。這類系統,都有一個單一的集中管理的服務器,保存全部文件的修訂版本,而協同工做的人們都經過客戶端連到這臺服務器,取出最新的文件或者提交更新。
那分佈式版本控制系統與集中式版本控制系統有何不一樣呢?首先,分佈式版本控制系統根本沒有「中央服務器」,每一個人的電腦上都是一個完整的版本庫,這樣,你工做的時候,就不須要聯網了,由於版本庫就在你本身的電腦上。既然每一個人電腦上都有一個完整的版本庫,那多我的如何協做呢?比方說你在本身電腦上改了文件A,你的同事也在他的電腦上改了文件A,這時,大家倆之間只需把各自的修改推送給對方,就能夠互相看到對方的修改了。
和集中式版本控制系統相比,分佈式版本控制系統的安全性要高不少,由於每一個人電腦裏都有完整的版本庫,某一我的的電腦壞掉了沒關係,隨便從其餘人那裏複製一個就能夠了。而集中式版本控制系統的中央服務器要是出了問題,全部人都無法幹活了。
在實際使用分佈式版本控制系統的時候,其實不多在兩人之間的電腦上推送版本庫的修改,由於可能大家倆不在一個局域網內,兩臺電腦互相訪問不了,也可能今天你的同事病了,他的電腦壓根沒有開機。所以,分佈式版本控制系統一般也有一臺充當「中央服務器」的電腦,但這個服務器的做用僅僅是用來方便「交換」你們的修改,沒有它你們也同樣幹活,只是交換修改不方便而已。
許多這類系統均可以指定和若干不一樣的遠端代碼倉庫進行交互。籍此,你就能夠在同一個項目中,分別和不一樣工做小組的人相互協做。你能夠根據須要設定不一樣的協做流程,好比層次模型式的工做流,而這在之前的集中式系統中是沒法實現的。
4、相關資源
若是感興趣能夠參考更詳細的 Git 資料:
Git 項目網站 https://git-scm.com/
Git 詳細文檔:Git 官方參考文檔 https://git-scm.com/doc
Github 網站:使用 Git 進行版本控制的代碼託管網站 https://github.com/
本實驗課程中咱們將對最經常使用的 Git 操做命令進行實踐,上手使用 Git 做爲代碼版本控制的工具。
點擊實驗桌面右邊工具欄的 下一個實驗 開始進入到 Git 的實驗操做吧!
1、實驗說明
本節實驗爲 Git 入門第一個實驗,能夠幫助你們熟悉如何建立和使用 Git 倉庫。
知識點
倉庫配置及初始化
克隆倉庫
添加更新內容到索引中及提交
比較內容
獲取當前項目情況
分支建立切換合併
恢復版本及查看日誌
實驗環境
實驗環境爲 Ubuntu Linux 命令行環境,須要瞭解基本的 Linux 操做,若是沒有使用過 Linux 的同窗,推薦先學習 Linux 基礎入門 前三個實驗。
2、Git 的初始化
在使用 Git進行代碼管理以前,咱們首先要對 Git 進行初始化配置。
使用 Git 的第一件事就是設置你的名字和 email,這些就是你在提交 commit 時的簽名,每次提交記錄裏都會包含這些信息。使用 git config 命令進行配置:
$ git config --global user.name "Scott Chacon"
$ git config --global user.email "schacon@gmail.com"
執行了上面的命令後,會在家目錄(/home/shiyanlou)下創建一個叫 .gitconfig 的文件(該文件爲隱藏文件,須要使用 ls -al 查看到). 內容通常像下面這樣,可使用 vim 或 cat 查看文件內容:
$ cat ~/.gitconfig
[user]
email = schacon@gmail.com
name = Scott Chacon
上面的配置文件就是 Git 全局配置的文件,通常配置方法是 git config --global <配置名稱> <配置的值>。
若是你想使項目裏的某個值與前面的全局設置有區別(例如把私人郵箱地址改成工做郵箱),你能夠在項目中使用 git config 命令不帶 --global 選項來設置. 這會在你當前的項目目錄下建立 .git/config,從而使用針對當前項目的配置。
3、得到一個Git倉庫
既然咱們如今把一切都設置好了,那麼咱們須要一個 Git 倉庫。有兩種方法能夠獲得它:一種是從已有的Git 倉庫中 clone (克隆,複製);還有一種是新建一個倉庫,把未進行版本控制的文件進行版本控制。
3.1 Clone一個倉庫
爲了獲得一個項目的拷貝(copy),咱們須要知道這個項目倉庫的地址(Git URL)。Git 能在許多協議下使用,因此 Git URL 可能以 ssh://,http(s)://,git:// 開頭。有些倉庫能夠經過多種協議來訪問。
咱們在 github.com 上提供了一個名字爲 gitproject 的供你們測試的公有倉庫,這個倉庫可使用下面方式進行 clone:
$ cd /home/shiyanlou/
$ git clone https://github.com/shiyanlou/gitproject
clone 操做完成後,會發現 /home/shiyanlou 目錄下多了一個 gitproject 文件夾,這個文件夾裏的內容就是咱們剛剛 clone 下來的代碼。因爲當前 gitproject 僅是測試項目,裏面僅有一個 README.md 文件。
$ cd gitproject/
(master)$ ls
README.md
細心的同窗能夠發如今命令提示符 $ 前面多了個 (master)。這是因爲實驗樓的 Linux 使用的是zsh Shell,zsh 會判斷當前的目錄是否有 Git 倉庫,若是是的話則自動把目前所在的 Git 分支顯示在提示符中。Git 分支的概念咱們會在稍後介紹。
3.2 初始化一個新的倉庫
能夠對一個已存在的文件夾用下面的命令讓它置於 Git 的版本控制管理之下。
建立代碼目錄 project:
$ cd /home/shiyanlou/
$ mkdir project
進入到代碼目錄,建立並初始化Git倉庫:
$ cd project
$ git init
Git 會輸出:
Initialized empty Git repository in /home/shiyanlou/project/.git/
經過 ls -la 命令會發現project目錄下會有一個名叫 .git 的目錄被建立,這意味着一個倉庫被初始化了。能夠進入到 .git 目錄查看下有哪些內容。
4、正常的工做流程
Git 的基本流程以下:
建立或修改文件
使用 git add 命令添加新建立或修改的文件到本地的緩存區(Index)
使用 git commit 命令提交到本地代碼庫
(可選,有的時候並無能夠同步的遠端代碼庫)使用git push命令將本地代碼庫同步到遠端代碼庫
4.1 建立或修改文件
進入咱們剛纔創建的 project 目錄,分別建立文件 file1,file2,file3:
$ cd /home/shiyanlou/project
$ touch file1 file2 file3
修改文件,可使用 vim 編輯內容,也能夠直接 echo 添加測試內容。
$ echo "test" >> file1
$ echo "test" >> file2
$ echo "test" >> file3
此時可使用 git status 命令查看當前 Git 倉庫的狀態:
$ git status
On branch master
Initial commit
Untracked files:
(use "git add <file>...") to include in what will be committed)
file1
file2
file3
nothing added to commit but untracked files present (use "git add" to track)
能夠發現,有三個文件處於 untracked 狀態,下一步咱們就須要用 git add 命令將他們加入到緩存區(Index)。
4.2 使用 git add 加入緩存區
使用 git add 命令將新建的文件添加到緩存區:
$ git add file1 file2 file3
而後再次執行 git status 就會發現新的變化:
$ git status
On branch master
Initial commit
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: file1
new file: file2
new file: file3
你如今爲 commit 作好了準備,你可使用 git diff 命令再加上 --cached 參數,看看緩存區中哪些文件被修改了。進入到 git diff --cached 界面後須要輸入 q 才能夠退出:
$ git diff --cached
若是沒有--cached參數,git diff 會顯示當前你全部已作的但沒有加入到緩存區裏的修改。
若是你要作進一步的修改, 那就繼續作, 作完後就把新修改的文件加入到緩存區中。
4.3 使用 git commit 提交修改
當全部新建,修改的文件都被添加到了緩存區,咱們就要使用 git commit 提交到本地倉庫:
$ git commit -m "add 3 files"
須要使用 -m 添加本次修改的註釋,完成後就會記錄一個新的項目版本。除了用 git add 命令,咱們還能夠用下面的 -a 參數將全部沒有加到緩存區的修改也一塊兒提交,但 -a 命令不會添加新建的文件。
$ git commit -a -m "add 3 files"
再次輸入 git status 查看狀態,會發現當前的代碼庫已經沒有待提交的文件了,緩存區已經被清空。
至此,咱們完成了第一次代碼提交,此次提交的代碼中咱們建立了三個新文件。須要注意的是若是是修改文件,也須要使用 git add 命令添加到緩存區才能夠提交。若是是刪除文件,則直接使用 git rm 命令刪除後會自動將已刪除文件的信息添加到緩存區,git commit 提交後就會將本地倉庫中的對應文件刪除。
這時若是咱們但願將本地倉庫關聯到遠端服務器,咱們可使用 git remote 命令,不一樣於剛剛的 git clone 命令,直接將遠端的倉庫克隆下來。
咱們當前的倉庫是使用 git init 初始化的本地倉庫,因此咱們須要將本地倉庫與遠程倉庫關聯,使用以下命令(須要修改下面的遠程倉庫地址爲本身的倉庫地址):
$ git remote add origin https://github.com/kinglion580/shiyanlou.git
對於上述命令而言,git remote add 命令用於添加遠程主機,origin 是主機名,此處咱們能夠自定義,不必定非要使用 origin,而 https://github.com/kinglion580/shiyanlou.git,是我本身的遠程倉庫,此處 須要替換爲本身的遠程倉庫地址
這個時候若是本地的倉庫鏈接到了遠程Git服務器,可使用下面的命令將本地倉庫同步到遠端服務器:
# 須要輸入倉庫對應的用戶名和密碼
$ git push origin master
5、分支與合併
Git 的分支可讓你在主線(master 分支)以外進行代碼提交,同時又不會影響代碼庫主線。分支的做用體如今多人協做開發中,好比一個團隊開發軟件,你負責獨立的一個功能須要一個月的時間來完成,你就能夠建立一個分支,只把該功能的代碼提交到這個分支,而其餘同事仍然能夠繼續使用主線開發,你天天的提交不會對他們形成任何影響。當你完成功能後,測試經過再把你的功能分支合併到主線。
5.1 建立分支
一個 Git 倉庫能夠維護不少開發分支。如今咱們來建立一個新的叫 experimental 的分支:
$ git branch experimental
運行 git branch 命令能夠查看當前的分支列表,以及目前的開發環境處在哪一個分支上:
$ git branch
experimental
* master
5.2 切換分支
experimental 分支是你剛纔建立的,master 分支是 Git 系統默認建立的主分支。星號標識了你當工做在哪一個分支下,輸入 git checkout 分支名 能夠切換到其餘分支:
$ git checkout experimental
Switched to branch 'experimental'
切換到 experimental 分支,切換完成後,先編輯裏面的一個文件,再提交(commit)改動,最後切換回 master 分支:
# 修改文件file1
$ echo "update" >> file1
# 查看當前狀態
$ git status
# 添加並提交file1的修改
$ git add file1
$ git commit -m "update file1"
# 查看file1的內容
$ cat file1
test
update
# 切換到master分支
$ git checkout master
查看下 file1 中的內容會發現剛纔作的修改已經看不到了。由於剛纔的修改時在 experimental 分支下,如今切換回了 master 分支,目錄下的文件都是 master 分支上的文件了。
5.3 合併分支
如今能夠在 master 分支下再做一些不一樣的修改:
# 修改文件file2
$ echo "update again" >> file2
# 查看當前狀態
$ git status
# 添加並提交file2的修改
$ git add file2
$ git commit -m "update file2 on master"
# 查看file2的內容
$ cat file2
test
update again
這時,兩個分支就有了各自不一樣的修改,分支的內容都已經不一樣,如何將多個分支進行合併呢?
能夠經過下面的 git merge 命令來合併 experimental 到主線分支 master:
# 切換到master分支
$ git checkout master
# 將experimental分支合併到master
$ git merge -m 'merge experimental branch' experimental
-m 參數仍然是須要填寫合併的註釋信息。
因爲兩個 branch 修改了兩個不一樣的文件,因此合併時不會有衝突,執行上面的命令後合併就完成了。
若是有衝突,好比兩個分支都改了一個文件 file3,則合併時會失敗。首先咱們在master分支上修改file3 文件並提交:
# 切換到master分支
$ git checkout master
# 修改file3文件
$ echo "master: update file3" >> file3
# 提交到master分支
$ git commit -a -m 'update file3 on master'
而後切換到 experimental,修改 file3 並提交:
# 切換到experimental分支
$ git checkout experimental
# 修改file3文件
$ echo "experimental: update file3" >> file3
# 提交到experimental分支
$ git commit -a -m 'update file3 on experimental'
切換到 master 進行合併:
$ git checkout master
$ git merge experimental
Auto-merging file3
CONFLICT (content): Merge conflict in file3
Automatic merge failed; fix conflicts and then commit the result.
合併失敗後先用 git status 查看狀態,會發現 file3 顯示爲 both modified,查看 file3內容會發現:
$ cat file3
test
<<<<<<< HEAD
master: update file3
=======
experimental: update file3
>>>>>>> experimental
上面的內容也可使用 git diff 查看,先前已經提到 git diff 不加參數能夠顯示未提交到緩存區中的修改內容。
能夠看到衝突的內容都被添加到了 file3 中,咱們使用 vim 編輯這個文件,去掉 Git 自動產生標誌衝突的 <<<<<< 等符號後,根據須要只保留咱們須要的內容後保存,而後使用 git add file3 和 git commit 命令來提交合並後的 file3 內容,這個過程是手動解決衝突的流程。
# 編輯衝突文件
$ vim file3
# 提交修改後的文件
$ git add file3
$ git commit -m 'merge file3'
5.4 刪除分支
當咱們完成合並後,再也不須要experimental時,可使用下面的命令刪除:
$ git branch -d experimental
git branch -d只能刪除那些已經被當前分支的合併的分支. 若是你要強制刪除某個分支的話就用git branch –D
5.5 撤銷一個合併
若是你以爲你合併後的狀態是一團亂麻,想把當前的修改都放棄,你能夠用下面的命令回到合併以前的狀態:
$ git reset --hard HEAD^
# 查看file3的內容,已經恢復到合併前的master上的文件內容
$ cat file3
5.6 快速向前合併
還有一種須要特殊對待的狀況,在前面沒有提到。一般,一個合併會產生一個合併提交(commit), 把兩個父分支裏的每一行內容都合併進來。
可是,若是當前的分支和另外一個分支沒有內容上的差別,就是說當前分支的每個提交(commit)都已經存在另外一個分支裏了,Git 就會執行一個 快速向前(fast forward)操做;Git 不建立任何新的提交(commit),只是將當前分支指向合併進來的分支。
6、Git 日誌
下面咱們來學習有關 Git 日誌的內容。
6.1 查看日誌
git log 命令能夠顯示全部的提交(commit):
$ git log
若是提交的歷史紀錄很長,回車會逐步顯示,輸入 q 能夠退出。
git log 有不少選項,可使用 git help log 查看,例以下面的命令就是找出全部從 "v2.5「 開始在 fs 目錄下的全部 Makefile 的修改(這個只是舉例,不用操做):
$ git log v2.5.. Makefile fs/
Git 會根據 git log 命令的參數,按時間順序顯示相關的提交(commit)。
6.2 日誌統計
若是用 --stat 選項使用 git log,它會顯示在每一個提交(commit)中哪些文件被修改了, 這些文件分別添加或刪除了多少行內容,這個命令至關於打印詳細的提交記錄:
$ git log --stat
6.3 格式化日誌
你能夠按你的要求來格式化日誌輸出。--pretty 參數可使用若干表現格式,如 oneline:
$ git log --pretty=oneline
或者你也可使用 short 格式:
$ git log --pretty=short
你也可用 medium,full,fuller,email 或 raw。 若是這些格式不徹底符合你的需求, 你也能夠用 --pretty=format 參數定義格式。
--graph 選項能夠可視化你的提交圖(commit graph),會用ASCII字符來畫出一個很漂亮的提交歷史(commit history)線:
$ git log --graph --pretty=oneline
6.4 日誌排序
日誌記錄能夠按不一樣的順序來顯示。若是你要指定一個特定的順序,能夠爲 git log 命令添加順序參數。
按默認狀況,提交會按逆時間順序顯示,能夠指定 --topo-order 參數,讓提交按拓撲順序來顯示(就是子提交在它們的父提交前顯示):
$ git log --pretty=format:'%h : %s' --topo-order --graph
你也能夠用 --reverse 參數來逆向顯示全部提交日誌。
7、小結
本節講解了幾個基本命令:
git config:配置相關信息
git clone:複製倉庫
git init:初始化倉庫
git add:添加更新內容到索引中
git diff:比較內容
git status:獲取當前項目情況
git commit:提交
git branch:分支相關
git checkout:切換分支
git merge:合併分支
git reset:恢復版本
git log:查看日誌
課後練習
開通 [GitHub](https://github.com) 帳號,建立練習倉庫並練習一遍上述所講的內容。
1、實驗說明
本節實驗爲 Git 入門第二個實驗,繼續練習最經常使用的 Git 命令。
知識點
對比差別
分佈式的工做流程
Git 標籤
實驗環境
實驗環境爲 Ubuntu Linux 命令行環境,須要瞭解基本的 Linux 操做,若是沒有使用過 Linux 的同窗,推薦先學習 Linux 基礎入門 前三個實驗。
實驗準備
在進行該實驗以前,能夠先 clone 一個練習項目 gitproject :
$ cd /home/shiyanlou
$ git clone https://github.com/shiyanlou/gitproject
本節中的實驗操做都是在該項目中完成。
2、比較內容
下面將學習如何比較提交,分支等內容。
2.1 比較提交 - Git Diff
如今咱們對項目作些修改:
$ cd gitproject
# 向README文件添加一行
$ echo "new line" >> README.md
# 添加新的文件file1
$ echo "new file" >> file1
使用 git status 查看當前修改的狀態:
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: README.md
Untracked files:
(use "git add <file>..." to include in what will be committed)
file1
no changes added to commit (use "git add" and/or "git commit -a")
能夠看到一個文件修改了,另一個文件添加了。如何查看修改的文件內容呢,那就須要使用 git diff 命令。git diff 命令的做用是比較修改的或提交的文件內容。
$ git diff
diff --git a/README.md b/README.md
index 21781dd..410e719 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,3 @@
gitproject
==========
+new line
上面的命令執行後須要使用 q 退出。命令輸出當前工做目錄中修改的內容,並不包含新加文件,請注意這些內容尚未添加到本地緩存區。
將修改內容添加到本地緩存區,通配符能夠把當前目錄下全部修改的新增的文件都自動添加:
$ git add *
再執行 git diff 會發現沒有任何內容輸出,說明當前目錄的修改都被添加到了緩存區,如何查看緩存區內與上次提交之間的差異呢?須要使用 --cached 參數:
$ git diff --cached
diff --git a/README.md b/README.md
index 21781dd..410e719 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,3 @@
gitproject
==========
+new line
diff --git a/file1 b/file1
new file mode 100644
index 0000000..fa49b07
--- /dev/null
+++ b/file1
@@ -0,0 +1 @@
+new file
能夠看到輸出中已經包含了新加文件的內容,由於 file1 已經添加到了緩存區。
最後咱們提交代碼:
$ git commit -m 'update code'
提交後 git diff 與 git diff --cached 都不會有任何輸出了。
2.2 比較分支
能夠用 git diff 來比較項目中任意兩個分支的差別。
咱們首先建立一個新的分支 test,並在該分支上提交一些修改:
# 建立test分支並切換到該分支
$ git branch test
$ git checkout test
# 添加新的一行到file1
$ echo "branch test" >> file1
# 建立新的文件file2
$ echo "new file2" >> file2
# 提交全部修改
$ git add *
$ git commit -m 'update test branch'
而後,咱們查看 test 分支和 master 之間的差異:
$ git diff master test
diff --git a/file1 b/file1
index fa49b07..17059cd 100644
--- a/file1
+++ b/file1
@@ -1 +1,2 @@
new file
+branch test
diff --git a/file2 b/file2
new file mode 100644
index 0000000..80e7991
--- /dev/null
+++ b/file2
@@ -0,0 +1 @@
+new file2
git diff 是一個難以置信的有用的工具,能夠找出你項目上任意兩個提交點間的差別。可使用 git help diff 詳細查看其餘參數和功能。
2.3 更多的比較選項
若是你要查看當前的工做目錄與另一個分支的差異,你能夠用下面的命令執行:
# 切換到master
$ git checkout master
# 查看與test分支的區別
$ git diff test
diff --git a/file1 b/file1
index 17059cd..fa49b07 100644
--- a/file1
+++ b/file1
@@ -1,2 +1 @@
new file
-branch test
diff --git a/file2 b/file2
deleted file mode 100644
index 80e7991..0000000
--- a/file2
+++ /dev/null
@@ -1 +0,0 @@
-new file2
你也以加上路徑限定符,來只比較某一個文件或目錄:
$ git diff test file1
diff --git a/file1 b/file1
index 17059cd..fa49b07 100644
--- a/file1
+++ b/file1
@@ -1,2 +1 @@
new file
-branch test
上面這條命令會顯示你當前工做目錄下的 file1 與 test 分支之間的差異。
--stat 參數能夠統計一下有哪些文件被改動,有多少行被改動:
$ git diff test --stat
file1 | 1 -
file2 | 1 -
2 files changed, 2 deletions(-)
3、分佈式的工做流程
下面咱們學習 Git 的分佈式工做流程。
3.1 分佈式的工做流程
你目前的項目在 /home/shiyanlou/gitproject 目錄下,這是咱們的 Git 倉庫(repository),另外一個用戶也想與你協做開發。他的工做目錄在這臺機器上,如何讓他提交代碼到你的 Git 倉庫呢?
首先,咱們假設另外一個用戶也用 shiyanlou 用戶登陸,只是工做在不一樣的目錄下開發代碼,實際工做中不太可能發生,大部分狀況都是多個用戶,這個假設只是爲了讓實驗簡化。
該用戶須要從 Git 倉庫進行克隆:
# 進入到臨時目錄
$ cd /tmp
# 克隆git倉庫
$ git clone /home/shiyanlou/gitproject myrepo
$ ls -l myrepo
-rw-rw-r-- 1 shiyanlou shiyanlou 31 Dec 22 08:24 README.md
-rw-rw-r-- 1 shiyanlou shiyanlou 9 Dec 22 08:24 file1
這就建了一個新的 "myrepo" 的目錄,這個目錄裏包含了一份gitproject倉庫的克隆。這份克隆和原始的項目如出一轍,而且擁有原始項目的歷史記錄。
在 myrepo 作了一些修改而且提交:
$ cd /tmp/myrepo
# 添加新的文件newfile
$ echo "newcontent" > newfile
# 提交修改
$ git add newfile
$ git commit -m "add newfile"
myrepo 修改完成後,若是咱們想合併這份修改到 gitproject 的 git 倉庫該如何作呢?
能夠在倉庫 /home/shiyanlou/gitproject 中把myrepo的修改給拉 (pull)下來。執行下面幾條命令:
$ cd /home/shiyanlou/gitproject
$ git pull /tmp/myrepo master
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From /tmp/myrepo
* branch master -> FETCH_HEAD
Updating 8bb57aa..866c452
Fast-forward
newfile | 1 +
1 file changed, 1 insertion(+)
create mode 100644 newfile
# 查看當前目錄文件
$ ls
README.md file1 newfile
這就把 myrepo 的主分支合併到了 gitproject 的當前分支裏了。
若是 gitproject 在 myrepo 修改文件內容的同時也作了修改的話,可能須要手工去修復衝突。
若是你要常常操做遠程分支(remote branch),你能夠定義它們的縮寫:
$ git remote add myrepo /tmp/myrepo
git pull 命令等同於執行兩個操做: 先使用 git fetch 從遠程分支抓取最新的分支修改信息,而後使用 git merge 把修改合併進當前的分支。
gitproject 裏能夠用 git fetch 來執行 git pull 前半部分的工做, 可是這條命令並不會把抓下來的修改合併到當前分支裏:
$ git fetch myrepo
From /tmp/myrepo
* [new branch] master -> myrepo/master
獲取後,咱們能夠經過 git log 查看遠程分支作的全部修改,因爲咱們已經合併了全部修改,因此不會有任何輸出:
$ git log -p master..myrepo/master
當檢查完修改後,gitproject 能夠把修改合併到它的主分支中:
$ git merge myrepo/master
Already up-to-date.
若是咱們在 myrepo 目錄下執行 git pull 會發生什麼呢?
myrepo 會從克隆的位置拉取代碼並更新本地倉庫,就是把 gitproject 上的修改同步到本地:
# 進入到gitproject
$ cd /home/shiyanlou/gitproject
# 添加一行內容到newfile
$ echo "gitproject: new line" >> newfile
# 提交修改
$ git commit -a -m 'add newline to newfile'
[master 8c31532] add newline to newfile
1 file changed, 1 insertion(+)
# 進入myrepo目錄
$ cd /tmp/myrepo
# 同步gitproject的全部修改
$ git pull
remote: Counting objects: 6, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From /home/shiyanlou/gitproject
8bb57aa..8c31532 master -> origin/master
Updating 866c452..8c31532
Fast-forward
newfile | 1 +
1 file changed, 1 insertion(+)
由於 myrepo 是從 gitproject 倉庫克隆的,那麼他就不須要指定 gitproject 倉庫的地 址。由於 Git 把 gitproject 倉庫的地址存儲到 myrepo 的配置文件中,這個地址就是在 git pull 時默認使用的遠程倉庫:
$ git config --get remote.origin.url
/home/shiyanlou/gitproject
若是 myrepo 和 gitproject 在不一樣的主機上,能夠經過 ssh 協議來執行 clone 和pull 操做:
$ git clone localhost:/home/shiyanlou/gitproject test
這個命令會提示你輸入 shiyanlou 用戶的密碼,用戶密碼隨機,能夠點擊實驗操做界面右側工具欄的 SSH直連 按鈕查看。
3.2 公共 Git 倉庫
開發過程當中,一般你們都會使用一個公共的倉庫,並 clone 到本身的開發環境中,完成一個階段的代碼後能夠告訴目標倉庫的維護者來 pull 本身的代碼。
若是你和維護者都在同一臺機器上有賬號,那麼大家能夠互相從對 方的倉庫目錄裏直接拉所做的修改,git 命令裏的倉庫地址也能夠是本地的某個目錄名:
$ git clone 倉庫A的路徑
$ git pull 倉庫B的路徑
也能夠是一個ssh地址:
$ git clone ssh://服務器/帳號/倉庫名稱
3.3 將修改推到一個公共倉庫
經過 http 或是 git 協議,其它維護者能夠經過遠程訪問的方式抓取(fetch)你最近的修改,可是他們沒有寫權限。如何將本地私有倉庫的最近修改主動上傳到公共倉庫中呢?
最簡單的辦法就是用 git push 命令,推送本地的修改到遠程 Git 倉庫,執行下面的命令:
$ git push ssh://服務器倉庫地址 master:master
或者
$ git push ssh://服務器倉庫地址 master
git push 命令的目地倉庫能夠是 ssh 或 http/https 協議訪問。
3.4 當推送代碼失敗時要怎麼辦
若是推送(push)結果不是快速向前 fast forward,可能會報像下面同樣的錯誤:
error: remote 'refs/heads/master' is not an ancestor of
local 'refs/heads/master'.
Maybe you are not up-to-date and need to pull first?
error: failed to push to 'ssh://yourserver.com/~you/proj.git'
這種狀況一般是由於沒有使用 git pull 獲取遠端倉庫的最新更新,在本地修改的同時,遠端倉庫已經變化了(其餘協做者提交了代碼),此時應該先使用 git pull 合併最新的修改後再執行 git push:
$ git pull
$ git push ssh://服務器倉庫地址 master
4、Git標籤
下面學習 Git 標籤相關內容。
4.1 輕量級標籤
咱們能夠用 git tag 不帶任何參數建立一個標籤(tag)指定某個提交(commit):
# 進入到gitproject目錄
$ cd /home/shiyanlou/gitproject
# 查看git提交記錄
$ git log
# 選擇其中一個記錄標誌位stable-1的標籤,注意須要將後面的8c315325替換成倉庫下的真實提交內,commit的名稱很長,一般咱們只須要寫前面8位便可
$ git tag stable-1 8c315325
# 查看當前全部tag
$ git tag
stable-1
這樣,咱們能夠用stable-1 做爲提交 8c315325 的代稱。
前面這樣建立的是一個「輕量級標籤」。
若是你想爲一個tag添加註釋,或是爲它添加一個簽名, 那麼咱們就須要建立一個 "標籤對象"。
標籤對象
git tag 中使用 -a, -s 或是 -u三個參數中任意一個,都會建立一個標籤對象,而且須要一個標籤消息(tag message)來爲 tag 添加註釋。 若是沒有 -m 或是 -F 這些參數,命令執行時會啓動一個編輯器來讓用戶輸入標籤消息。
當這樣的一條命令執行後,一個新的對象被添加到 Git 對象庫中,而且標籤引用就指向了一個標籤對象,而不是指向一個提交,這就是與輕量級標籤的區別。
下面是一個建立標籤對象的例子:
$ git tag -a stable-2 8c315325 -m "stable 2"
$ git tag
stable-1
stable-2
4.2 簽名的標籤
簽名標籤可讓提交和標籤更加完整可信。若是你配有GPG key,那麼你就很容易建立簽名的標籤。首先你要在你的 .git/config 或 ~/.gitconfig 裏配好key。
下面是示例:
[user]
signingkey = <gpg-key-id>
你也能夠用命令行來配置:
$ git config (--global) user.signingkey <gpg-key-id>
如今你能夠在建立標籤的時候使用 -s 參數來建立「簽名的標籤」:
$ git tag -s stable-1 1b2e1d63ff
若是沒有在配置文件中配 GPG key,你能夠用 -u 參數直接指定。
$ git tag -u <gpg-key-id> stable-1 1b2e1d63ff
5、小結
本節學習了下面知識點:
git diff
分佈式的工做流程
git tag
課後練習
使用 [GitHub](https://github.com) 帳號,建立本身的倉庫並練習一遍本節所講的內容。
對於初學者,若是不想深刻 git 強大的高級功能的話,學完這個實驗就能夠開始上手開發了,後續實驗內容用到的比較少,而且理解難度大。若是仍然感興趣,建議使用一段時間 Git 後再仔細學習後續實驗,會有更好的收穫。
比賽規則
1. 仔細閱讀題目描述,在實驗環境中完成任務
2. 完成任務後點擊桌面右方的提交結果按鈕
3. 系統自動評測並給出是否經過的信息
挑戰:初始化本地 Git 倉庫
介紹
本節挑戰中,咱們須要建立一個本地 Git 倉庫。咱們須要設置我的的 Git 信息,包括 username 和 email。另外須要對本地 Git 倉庫進行初始化操做以及增長一些項目文件。
須要完成的任務包括:
設置 Git 信息;
完成本地 Git 倉庫的初始化操做;
設置關聯到遠程倉庫;
建立 README.md 文件並進行 commit(不須要 push 到遠程倉庫);
目標
本地 Git 倉庫目錄必須爲 /home/shiyanlou/HelloGit/。
遠程倉庫地址固定爲 git@shiyanlou.com/HelloGit.git,遠程版本庫名稱爲 origin。
須要在代碼目錄 /home/shiyanlou/HelloGit/ 中建立 README.md 文件,文件的內容以下:
Hello World
使用 git commit 提交 README.md 文件。
因爲遠程倉庫 git@shiyanlou.com/HelloGit.git 並不存在,因此不須要 git push 推送到遠程倉庫。
知識點
倉庫初始化
代碼提交
1、實驗說明
從本節開始,咱們會介紹一些中級和高級的用法,這些用法不多用到,前面實驗的內容已經知足了平常工做須要,從本節開始的內容能夠簡單瞭解,須要的時候再詳細查看。
知識點
忽略部分文件
rebase 命令
stash 命令
Git 樹名
實驗環境
實驗環境爲 Ubuntu Linux 命令行環境,須要瞭解基本的 Linux 操做,若是沒有使用過 Linux 的同窗,推薦先學習 Linux 基礎入門 前三個實驗。
git 配置
$ git config --global user.name "Scott Chacon"
$ git config --global user.email "schacon@gmail.com"
下載測試項目環境
經過下列命令得到 gitproject 項目環境,該項目默認只有一個文件 README.md,能夠用來進行後續 git 實驗:
$ cd /home/shiyanlou
$ git clone https://github.com/shiyanlou/gitproject
2、忽略某些文件
項目中常常會生成一些 Git 系統不須要追蹤(track)的文件。典型的是在編譯生成過程當中產生的文件或是編程器生成的臨時備份文件。
固然,若是你不追蹤(track)這些文件,平時能夠不使用 git add 去把它們加到緩存區中,可是這樣會很快變成一件煩人的事,你發現項目中處處有未追蹤(untracked)的文件。這樣也使 git add . 和 git commit -a 變得實際上沒有用處,同時 git status 命令的輸出也會有它們。
如何解決這些問題呢?
你能夠在你的頂層工做目錄中添加一個叫 .gitignore 的文件,來告訴 Git 系統要忽略掉哪些文件,下面是文件內容的示例。
以'#' 開始的行,被視爲註釋。忽略掉全部文件名是 foo.txt 的文件,.gitignore 的文件內容爲:
foo.txt
忽略全部生成的 html 文件:
*.html
若是 foo.html 這個文件不能忽略,能夠寫個例外:
!foo.html
忽略全部 .o 和 .a 文件:
*.[oa]
3、rebase
假設你如今基於遠程分支 origin,建立一個叫 mywork 的分支。
$ cd /home/shiyanlou/gitproject
$ git checkout -b mywork origin
如今咱們在這個分支作一些修改,而後生成兩個提交(commit)。
$ vim file.txt
$ git commit
$ vim otherfile.txt
$ git commit
可是與此同時,有些人也在 origin 分支上作了一些修改而且作了提交了。這就意味着 origin 和 mywork 這兩個分支各自 前進 了,它們之間 分叉 了。
在這裏,你能夠用 pull 命令把 origin 分支上的修改拉下來而且和你的修改合併;結果看起來是會出現一個新的 合併的提交 (merge commit):
可是,若是你想讓 mywork 分支歷史看起來像沒有通過任何合併同樣,你也許能夠用 git rebase:
$ git checkout mywork
$ git rebase origin
這些命令會把你的 mywork 分支裏的每一個提交(commit)取消掉,而且把它們臨時保存爲補丁(patch)(這些補丁放到 .git/rebase 目錄中),而後把 mywork 分支更新到最新的 origin 分支,最後把保存的這些補丁應用到 mywork 分支上。
當 mywork 分支更新以後,它會指向這些新建立的提交(commit),而那些老的提交會被丟棄。 若是運行垃圾收集命令(pruning garbage collection), 這些被丟棄的提交就會刪除。
在 rebase 的過程當中,也許會出現衝突(conflict)。在這種狀況,Git 會中止 rebase 並會讓你去解決衝突;在解決完衝突後,用 git-add 命令去更新這些內容的索引(Index), 而後,你無需執行 git-commit,只要執行:
$ git rebase --continue
這樣 git 會繼續應用(apply)餘下的補丁。
在任什麼時候候,你能夠用 --abort 參數來終止rebase的行動,而且 mywork 分支會回到 rebase 開始前的狀態。
$ git rebase --abort
4、交互式 rebase
你也能夠選擇進行交互式的 rebase。這種方法一般用於在向別處推送提交以前對它們進行重寫。交互式 rebase 提供了一個簡單易用的途徑讓你在和別人分享提交以前對你的提交進行分割、合併或者重排序。在把從其餘開發者處拉取的提交應用到本地時,你也可使用交互式 rebase 對它們進行清理。
若是你想在 rebase 的過程當中對一部分提交進行修改,你能夠在 git rebase 命令中加入 -i 或 --interactive 參數去調用交互模式:
$ git rebase -i origin/master
這個命令會執行交互式 rebase 操做,操做對象是那些自最後一次從 origin 倉庫拉取或者向origin 推送以後的全部提交。
若想查看一下將被 rebase 的提交,能夠用以下的 log 命令:
$ git log github/master..
一旦你完成對提交信息的編輯而且退出編輯器,這個新的提交及提交信息會被保存起來。
若是指定進行 edit 操做,git 會完成一樣的工做,可是在對下一提交進行操做以前,它會返回到命令行讓你對提交進行修正,或者對提交內容進行修改。
例如你想要分割一個提交,你須要對那個提交指定 edit 操做:
你會進入到命令行,撤銷(revert)該提交,而後建立兩個(或者更多個)新提交。假設提交 21d80a5 修改了兩個文件,file1 和 file2,你想把這兩個修改放到不一樣的提交裏。你能夠在進入命令行以後進行以下的操做:
$ git reset HEAD^
$ git add file1
$ git commit -m 'first part of split commit'
$ git add file2
$ git commit -m 'second part of split commit'
$ git rebase --continue
交互式 rebase 的最後一個做用是丟棄提交。若是把一行刪除而不是指定 pick 、squash和 edit 中的任何一個,git 會從歷史中移除該提交。
5、交互式添加
交互式添加提供友好的界面去操做 Git 索引(index),同時也提供了可視化索引的能力。只需簡單輸入 git add -i,便可使用此功能。Git 會列出全部修改過的文件及它們的狀態:
$ git add -i
在這個例子中,咱們能夠看到有5個修改過的文件尚未被加入到索引中(unstaged),甚至能夠看到每一個文件增長和減小的行數。緊接着是一個交互式的菜單,列出了咱們能夠在此模式中使用的命令。
若是咱們想要暫存(stage)這些文件,咱們能夠鍵入 2 或者 u 進入更新(update)模式。而後咱們能夠經過鍵入文件的範圍(本例中是1-4)來決定把哪些文件加入到索引之中。
What now> 2
staged unstaged path
1: unchanged +4/-0 assets/stylesheets/style.css
2: unchanged +23/-11 layout/book_index_template.html
3: unchanged +7/-7 layout/chapter_template.html
4: unchanged +3/-3 script/pdf.rb
5: unchanged +121/-0 text/14_Interactive_Rebasing/0_ Interactive_Rebasing.markdown
Update>> 1-4
staged unstaged path
* 1: unchanged +4/-0 assets/stylesheets/style.css
* 2: unchanged +23/-11 layout/book_index_template.html
* 3: unchanged +7/-7 layout/chapter_template.html
* 4: unchanged +3/-3 script/pdf.rb
5: unchanged +121/-0 text/14_Interactive_Rebasing/0_ Interactive_Rebasing.markdown
Update>>
若是鍵入回車,我會回到主菜單中,同時能夠看到那些指定文件的狀態已經發生了改變:
What now> status
staged unstaged path
1: +4/-0 nothing assets/stylesheets/style.css
2: +23/-11 nothing layout/book_index_template.html
3: +7/-7 nothing layout/chapter_template.html
4: +3/-3 nothing script/pdf.rb
5: unchanged +121/-0 text/14_Interactive_Rebasing/0_ Interactive_Rebasing.markdown
如今咱們能夠看到前4個文件已經被暫存,可是最後一個沒有。基本上,這是一個更加緊湊的查看狀態的方式,實質上的信息與咱們在命令行中運行 git status 是一致的:
$ git status
6、儲藏
1.儲藏
當你正在作一項複雜的工做時, 發現了一個和當前工做不相關可是又很討厭的 bug. 你這時想先修復 bug 再作手頭的工做, 那麼就能夠用 git stash 來保存當前的工做狀態, 等你修復完 bug 後,執行反儲藏(unstash)操做就能夠回到以前的工做裏。
$ git stash save "work in progress for foo feature"
上面這條命令會保存你的本地修改到儲藏(stash)中, 而後將你的工做目錄和索引裏的內容所有重置, 回到你當前所在分支的上次提交時的狀態。
好了, 你如今就能夠開始你的修復工做了。
$ git commit -a -m "blorpl: typofix"
當你修復完bug後, 你能夠用 git stash apply 來回復到之前的工做狀態。
$ git stash apply
2.儲藏隊列
你也可屢次使用 git stash 命令, 每執行一次就會把針對當前修改的儲藏(stash)添加到儲藏隊列中. 用 git stash list 命令能夠查看你保存的儲藏(stashes):
$ git stash list
能夠用相似 git stash apply stash@{1} 的命令來使用在隊列中的任意一個儲藏(stashes). git stash clear 則是用來清空這個隊列。
7、Git 樹名
1. Git 樹名
不用 40 個字節長的 SHA 串來表示一個提交(commit)或是其它 git 對象,有不少種名字表示方法。在 Git 裏,這些名字就叫樹名(treeish)。
2. Sha 短名
若是你的一個提交(commit)的 sha 名字是 980e3ccdaac54a0d4de358f3fe5d718027d96aae, git會把下面的串視爲等價的:
980e3ccdaac54a0d4de358f3fe5d718027d96aae
980e3ccdaac54a0d4
980e3cc
只要你的sha短名(Partial Sha)是不重複的(unique),它就不會和其它名字衝突(若是你使用了5個字節以上那是很難重複的),Git 也會把sha短名(Partial Sha)自動補全。
3. 分支, Remote 或 標籤
你可使用分支,remote 或標籤名來代替 SHA 串名, 它們只是指向某個對象的指針。假設你的master 分支目前在提交(commit):980e3 上, 如今把它推送(push)到 origin 上並把它命名爲標籤 v1.0, 那麼下面的串都會被 git 視爲等價的:
980e3ccdaac54a0d4de358f3fe5d718027d96aae
origin/master
refs/remotes/origin/master
master
refs/heads/master
v1.0
refs/tags/v1.0
這意味着你執行下面的兩條命令會有一樣的輸出:
$ git log master
$ git log refs/tags/v1.0
4. 日期標識符
Git 的引用日誌(Ref Log)可讓你作一些 相對 查詢操做:
master@{yesterday}
master@{1 month ago}:
上面的第一條命令是:master 分支的昨天狀態(head)的縮寫。注意: 即便在兩個有相同 master 分支指向的倉庫上執行這條命令,可是若是這個兩個倉庫在不一樣機器上,那麼執行結果也極可能會不同。
5. 順序標識符
這種格式用來表達某點前面的第 N 個提交(ref)。
master@{5}
上面的表達式表明着 master 前面的第 5 個提交(ref)。
6. 多個父對象
這能告訴你某個提交的第 N 個直接父提交(parent)。這種格式在合併提交(merge commits)時特別有用,這樣就可使提交對象(commit object)有多於一個直接父對象(direct parent):
master^2
7. 波浪號
波浪號用來標識一個提交對象(commit object)的第 N 級嫡(祖)父對象(Nth grandparent),例如:
master~2
就表明 master 所指向的提交對象的第一個父對象的第一個父對象(譯者:你能夠理解成是嫡系爺爺)。 它和下面的這個表達式是等價的:
master^^
你也能夠把這些標識符疊加起來, 下面這個3個表達式都是指向同一個提交(commit):
master^^^^^^
master~3^~2
master~6
8. 樹對象指針
若是你們對以前的 Git 對象模型還有印象的話, 就記得提交對象(commit object)是指向一個樹對象(tree object)的。假如你要獲得一個提交對象(commit object)指向的樹對象(tree object)的 sha 串名, 你就能夠在 ‘樹名' 的後面加上 {tree} 來獲得它:
master^{tree}
9. 二進制標識符
若是你要某個二進制對象(blob)的 sha 串名,你能夠在樹名(treeish)後添加二進制對象(blob)對應的文件路徑來獲得它:
master:/path/to/file
10. 區間
最後,你能夠用 .. 來指兩個提交(commit)之間的區間. 下面的命令會給出你在 7b593b5 和 51bea1 之間除了 7b593b5 外的全部提交(commit)(注意:51bea1是最近的提交):
7b593b5..51bea1
這會包括全部從 7b593b 開始的提交(commit)。譯者注:至關於 7b593b..HEAD:
7b593b..
8、小結
本節講解了 git 的進階知識,在添加索引時能夠經過配置 .gitignore 文件來忽略文件,又講解了git rebase、git stash 和 git樹名。
課後練習
請在你本身的 GitHub 倉庫上操做一遍,並深刻理解這些命令。
1、實驗說明
本節實驗中咱們將繼續學習和實踐一些 Git 相關的命令。
知識點
追蹤分支
grep 搜索
Git 的撤消操做
維護 Git
創建公有和私有倉庫
實驗環境
實驗環境爲 Ubuntu Linux 命令行環境,須要瞭解基本的 Linux 操做,若是沒有使用過 Linux 的同窗,推薦先學習 Linux 基礎入門 前三個實驗。
git 配置
$ git config --global user.name "Scott Chacon"
$ git config --global user.email "schacon@gmail.com"
下載測試項目環境
經過下列命令得到 gitproject 項目環境,該項目默認只有一個文件 README.md,能夠用來進行後續 Git 實驗:
$ cd /home/shiyanlou
$ git clone https://github.com/shiyanlou/gitproject
2、追蹤分支
在 Git 中,追蹤分支是用於聯繫本地分支和遠程分支的。 若是你在 追蹤分支(Tracking Branches)上執行 推送(push)或 拉取(pull)時,它會自動推送(push)或拉取(pull)到關聯的遠程分支上。
若是你常常要從遠程倉庫里拉取(pull)分支到本地,而且不想很麻煩的使用 git pull 這種格式; 那麼就應當使用 追蹤分支(Tracking Branches)。
git clone 命令會自動在本地創建一個 master分支,它是 origin/master 的 追蹤分支 。而 origin/master 就是被克隆(clone)倉庫的 master 分支。
你能夠在使用 git branch 命令時加上 --track 參數,來手動建立一個 追蹤分支 。
$ git branch --track experimental origin/experimental
前提是遠程倉庫也有一個 experimental 倉庫,由於咱們這裏遠程倉庫沒有 experimental 分支,因此會報錯。
當你運行下命令時:
$ git pull experimental
它會自動從 origin 抓取(fetch)內容,再把遠程的 origin/experimental 分支 合併進(merge)本地的 experimental 分支。
當要把修改推送(push)到 origin 時,它會將你本地的 experimental 分支中的修改推送到origin 的 experimental 分支裏,而無需指定它(origin)。
3、使用 Git Grep 進行搜索
用 git grep 命令查找 Git 庫裏面的某段文字是很方便的。固然,你也能夠用 Linux 下的 grep 命令進行搜索,可是 git grep 命令能讓你不用 簽出(checkout)歷史文件,就能查找它們。
例如,你要看倉庫裏每一個使用 xmmap 函數的地方,你能夠運行下面的命令:
$ git grep xmmap
若是你要顯示行號,你能夠添加 -n選項:
$ git grep -n xmmap
若是咱們想只顯示文件名,咱們可使用 --name-only 選項:
$ git grep --name-only xmmap
咱們用 -c 選項能夠查看每一個文件裏有多少行 匹配內容(line matches):
$ git grep -c xmmap
如今, 若是咱們要查找 git 倉庫裏某個特定版本里的內容, 咱們能夠像下面同樣在命令行末尾加上標籤名(tag reference):
$ git grep xmmap v1.5.0
咱們也能夠組合一些搜索條件,下面的命令就是查找咱們在倉庫的哪一個地方定義了 SORT_DIRENT:
$ git grep -e '#define' --and -e SORT_DIRENT
我不但能夠進行與(both)條件搜索操做,也能夠進行或(either)條件搜索操做:
$ git grep --all-match -e '#define' -e SORT_DIRENT
咱們也能夠查找出符合一個條件(term)且符合兩個條件(terms)之一的文件行,例如咱們要找出名字中含有 PATH 或是 MAX 的常量定義:
$ git grep -e '#define' --and \( -e PATH -e MAX \)
4、Git 修復操做
1. 修復未提交文件中的錯誤(重置)
若是你如今的 工做目錄(work tree)裏搞的一團亂麻,可是你如今尚未把它們提交。你能夠經過下面的命令,讓工做目錄回到上次提交時的狀態(last committed state):
$ git reset --hard HEAD^
這條命令會把你工做目錄中全部未提交的內容清空(固然這不包括未置於版控制下的文件 untracked files)。從另外一種角度來講, 這會讓 git diff 和 git diff --cached 命令的顯示法都變爲空。
若是你只是要恢復一個文件,如 hello.rb ,你就要使用 git checkout:
$ git checkout -- hello.rb
這條命令把 hello.rb 從 HEAD 中 checkout 而且把它恢復成未修改時的樣子。
2. 修復已提交文件中的錯誤
若是你已經作了一個 提交(commit),可是你立刻後悔了,這裏有兩種大相徑庭的方法去處理這個問題。
建立一個 新的提交(commit),在新的提交裏撤消老的提交所做的修改。這種做法在你已經把代碼發佈的狀況下十分正確.
你也能夠去修改你的 老提交(old commit)。可是若是你已經把代碼發佈了,那麼千萬別這麼作,git 不會處理項目歷史會改變的狀況,若是一個分支的歷史被改變了那之後就不能正常的合併。
建立新提交來修復錯誤
建立一個新的, 撤銷(revert)了前期修改的 提交(commit)是很容易的。只要把出錯的提交(commit)的名字(reference)作爲參數傳給命令 git revert 就能夠了,下面這條命令就演示瞭如何撤消最近的一個提交:
$ git revert HEAD
這樣就建立了一個撤消了上次提交(HEAD)的新提交, 你就有機會來修改新提交(new commit)裏的提交註釋信息。
你也可撤消更早期的修改, 下面這條命令就是撤銷 上上次(next-to-last)的提交:
$ git revert HEAD^
在這種狀況下,Git 嘗試去撤銷老的提交,而後留下完整的老提交前的版本. 若是你最近的修改和要撤銷的修改有 重疊(overlap),那麼就會被要求手工解決 衝突(conflicts),就像解決 合併(merge)時出現的衝突同樣。
譯者注:git revert 其實不會直接建立一個 提交(commit),只會把撤銷後的文件內容放到 索引(index)裏,你須要再執行 git commit 命令,它們纔會成爲真正的提交(commit)。
修改提交來修復錯誤
若是你剛剛作了某個提交(commit), 可是你又想立刻修改這個提交,git commit 如今支持一個叫--amend 的參數,它能讓你修改剛纔的這個提交(HEAD commit)。這項機制能讓你在代碼發佈前,添加一些新的文件或是修改你的提交 註釋(commit message)。
若是你在 老提交(older commit)裏發現一個錯誤,可是如今尚未發佈到代碼服務器上,你可使用 git rebase 命令的交互模式,git rebase -i 會提示你在編輯中作相關的修改。這樣其實就是讓你在 rebase 的過程來修改提交。
5、維護Git
1. 保證良好的性能
在大的倉庫中, git 靠壓縮歷史信息來節約磁盤和內存空間。
壓縮操做並非自動進行的,你須要手動執行 git gc:
$ git gc
壓縮操做比較耗時,你運行 git gc 命令最好是在你沒有其它工做的時候。
2. 保持可靠性
git fsck 運行一些倉庫的一致性檢查,若是有任何問題就會報告。這項操做也有點耗時,一般報的警告就是 懸空對象(dangling objects)。
$ git fsck
懸空對象(dangling objects)並非問題,最壞的狀況它們只是多佔了一些磁盤空間,但有時候它們是找回丟失的工做的最後一絲但願.
6、創建一個公共倉庫
1. 創建一個公共倉庫
假設你我的的倉庫在目錄 ~/proj,咱們先克隆一個新的「裸倉庫「,而且建立一個標誌文件告訴 git-daemon 這是個公共倉庫:
$ git clone --bare ~/proj proj.git
$ touch proj.git/git-daemon-export-ok
上面的命令建立了一個 proj.git 目錄, 這個目錄裏有一個 裸 git 倉庫 —— 即只有 .git 目錄裏的內容,沒有任何簽出(checkout)的文件。
下一步就是你把這個 proj.git 目錄拷到你打算用來託管公共倉庫的主機上,你能夠用 scp, rsync 或其它任何方式。
2. 經過 git 協議導出 git 倉庫
用 Git 協議導出 Git 倉庫, 這是推薦的方法。
若是這臺服務器上有管理員,他會告訴你把倉庫放在哪個目錄中,而且告訴你倉庫的地址 git://URL 是什麼。
服務器上須要啓動 git daemon,它默認監聽在 9418 端口,默認狀況下它會容許你訪問全部的 Git 目錄(看目錄中是否有 git-daemon-export-ok 文件)。能夠配置 git daemon 的啓動參數來讓 git-daemon 限制用戶經過 Git 協議只能訪問哪些目錄。
3. 經過 http 協議導出 git 倉庫
Git 協議有不錯的性能和可靠性,可是若是主機上已經配好了一臺 web 服務器,使用 http 協議(git over http)可能會更容易配置一些。
你須要把新建的 裸倉庫 放到 Web 服務器 的 可訪問目錄 裏, 同時作一些調整,以便讓 web 客戶端得到它們所需的額外信息:
$ mv proj.git /var/www/html/proj.git
$ cd proj.git
$ git --bare update-server-info
$ chmod a+x hooks/post-update
克隆的時候可使用下面的命令進行克隆:
$ git clone http://服務器地址/proj.git
7、創建一個私有倉庫
經過 SSH 協議來訪問倉庫
一般最簡單的辦法是經過 ssh 協議訪問 Git(Git Over SSH)。
若是你在一臺機器上有了一個 ssh 賬號, 你只要把 git 祼倉庫 放到任何一個能夠經過 ssh 訪問的目錄,而後能夠像 ssh 登陸同樣簡單的使用它。假設你如今有一個倉庫,而且你要把它建成能夠在網上可訪問的私有倉庫,你能夠用下面的命令,導出一個 祼倉庫,而後用 scp 命令把它們拷到你的服務器上:
$ git clone --bare /home/user/myrepo/.git /tmp/myrepo.git
$ scp -r /tmp/myrepo.git myserver.com:/opt/git/myrepo.git
若是其它人也在 myserver.com 這臺服務器上有 ssh 賬號,那麼他也能夠從這臺服務器上克隆(clone)代碼:
$ git clone myserver.com:/opt/git/myrepo.git
上面的命令會提示你輸入 ssh 密碼或是使用 公鑰(public key)。
8、小結
本節實驗中咱們學習瞭如下的知識點:
追蹤分支
使用 git grep 進行搜索
Git 的撤消操做(git reset、git checkout、git revert)
維護 Git(git gc、git fsck)
創建公有和私有倉庫
課後練習
請本身建一個公有倉庫讓小夥伴能夠訪問並提交代碼。
在開發者分支下完成工做
介紹
本節挑戰中,咱們須要從指定地址 clone 整個工程至實驗樓的環境。而後建立 dev 分支。以後咱們須要增長 README-new.md 文件,可是還想保留之前的 README.md 文件並在提交時永遠忽略其修改。
本節挑戰中要完成的任務:
clone 遠程倉庫中工程;
建立並切換至 dev 分支;
增長 README-new.md 文件,忽略 README.md 文件修改;
目標
遠程倉庫地址 http://github.com/shiyanlou/gitproject,請克隆該倉庫到 /home/shiyanlou 目錄下,倉庫克隆後的目錄命名保持爲 gitproject,路徑爲 /home/shiyanlou/gitproject。
向 dev 分支提交新建的 /home/shiyanlou/gitproject/README-new.md 文件,文件內容以下:
shiyanlou development
知識點
忽略文件
切換分支
提交代碼