git用法大全

轉載自實驗樓,以前有更新過兩篇git的文章,畢竟內容太少,而git還有不少更豐富的技能,在實驗樓上有一系列全的教程,這裏作一下備案.須要時查閱.javascript

Git 實戰教程

目錄php

1、實驗說明css

2、git的初始化html

1.Git 配置java

3、得到一個Git倉庫nginx

1.Clone一個倉庫git

2.初始化一個新的倉庫github

4、正常的工做流程web

1. 正常的工做流程sql

5、分支與合併

1.分支

2. 撤銷一個合併

3.快速向前合併

6、Git日誌

1.查看日誌

2.日誌統計

3.格式化日誌

4.日誌排序

7、小結

8、練習

1、實驗說明

1.1 實驗準備

2、比較內容

1.比較提交 - Git Diff

2.比較分支

3.更多的比較選項

3、分佈式的工做流程

1.分佈式的工做流程

2.公共Git倉庫

3.將修改推到一個公共倉庫

4.當推送代碼失敗時要怎麼辦

4、Git標籤

1.輕量級標籤

2.簽名的標籤

5、小結

6、練習

1、實驗說明

1.1 下載測試項目環境

2、忽略某些文件

1.忽略某些文件

3、rebase

1.rebase

4、交互式rebase

1.交互式rebase

5、交互式添加

1.交互式添加

6、儲藏

1.儲藏

2.儲藏隊列

7、Git樹名

1.Git樹名

2.Sha短名

3.分支, Remote 或 標籤

4.日期標識符

5.順序標識符

6.多個父對象

7.波浪號

8.樹對象指針

9.二進制標識符

10.區間

8、小結

9、練習

1、實驗說明

1. 環境登陸

2. 環境使用

3.下載測試項目環境

2、追蹤分支

1.追蹤分支

3、使用Git Grep進行搜索

1.使用Git Grep進行搜索

4、Git的撤銷操做 - 重置, 簽出 和 撤銷

1.修復未提交文件中的錯誤(重置)

2.修復已提交文件中的錯誤

5、維護Git

1.保證良好的性能

2.保持可靠性

6、創建一個公共倉庫

1.創建一個公共倉庫

2.經過git協議導出git倉庫

3.經過http協議導出git倉庫

7、創建一個私有倉庫

1.經過SSH協議來訪問倉庫 

8、小結

9、練習

1、實驗說明

1. 環境登陸

2. 環境使用

3.下載測試項目環境

2、建立新的空分支

1.建立新的空分支

3、修改你的歷史

1.修改你的歷史

4、高級分支與合併

1.在合併過程當中獲得解決衝突的協助

2.多路合併

3.子樹

查找問題的利器 - Git Bisect

4.查找問題的利器 - Git Bisect

5、查找問題的利器 - Git Blame

1.查找問題的利器 - Git Blame

6、Git和Email

1.向一個項目提交補丁

2.向一個項目中導入補丁

7、定製Git

1.更改你的編輯器

2.添加別名

3.添加顏色

4.提交模板

5.日誌格式

8、Git Hooks

1.Git Hooks

2.applypatch-msg

3.pre-applypatch

4.post-applypatch

5.pre-commit

6.prepare-commit-msg

7.commit-msg

8.post-commit

9.pre-rebase

10.post-checkout

11.post-merge

12.pre-receive

13.update

14.post-receive

9、找回丟失的對象

1.準備

2.恢復已刪除分支提交

3.git stash的恢復

10、子模塊

1.子模塊

2.子模塊方式的陷阱

11、小結

12、練習

1、實驗說明

本節實驗爲 Git 入門第一個實驗,能夠幫助你們熟悉如何建立和使用 git 倉庫。

2、git的初始化

在使用git進行代碼管理以前,咱們首先要對git進行初始化。

1.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 (克隆,複製);還有一種是新建一個倉庫,把未進行版本控制的文件進行版本控制。

1.Clone一個倉庫

爲了獲得一個項目的拷貝(copy),咱們須要知道這個項目倉庫的地址(Git URL). Git能在許多協議下使用,因此Git URL可能以ssh://, http(s)://, git://. 有些倉庫能夠經過不僅一種協議來訪問。

咱們在github.com上提供了一個名字爲gitproject的供你們測試的公有倉庫,這個倉庫可使用下面方式進行clone:

$ git clone https://github.com/shiyanlou/gitproject 

clone操做完成後,會發現當前目錄下多了一個gitproject文件夾,這個文件夾裏的內容就是咱們剛剛clone下來的代碼。因爲當前`gitproject僅是測試項目,裏面僅有一個README.md文件。

$ cd gitproject/
(master)$ ls 
README.md

細心的同窗能夠發如今命令提示符$前面多了個(master)。這是因爲實驗樓的Linux使用的是zsh Shell,zsh會判斷當前的目錄是否有Git倉庫,若是是的話則自動把目前所在的git分支顯示在提示符中。Git 分支的概念咱們會在稍後介紹。

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、正常的工做流程

1. 正常的工做流程

git的基本流程以下:

  1. 建立或修改文件
  2. 使用git add命令添加新建立或修改的文件到本地的緩存區(Index)
  3. 使用git commit命令提交到本地代碼庫
  4. (可選,有的時候並無能夠同步的遠端代碼庫)使用git push命令將本地代碼庫同步到遠端代碼庫

進入咱們剛纔創建的project目錄,分別建立文件file1file2file3

$ cd 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)。

使用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 會顯示當前你全部已作的但沒有加入到索引裏的修改。

若是你要作進一步的修改, 那就繼續作, 作完後就把新修改的文件加入到緩存區中。

當全部新建,修改的文件都被添加到了緩存區,咱們就要使用git commit提交到本地倉庫:

$ git commit -m "add 3 files" 

須要使用-m添加本次修改的註釋,完成後就會記錄一個新的項目版本。除了用git add 命令,咱們還能夠用下面的命令將全部沒有加到緩存區的修改也一塊兒提交,但-a命令不會添加新建的文件。

$ git commit -a -m "add 3 files" 

再次輸入git status查看狀態,會發現當前的代碼庫已經沒有待提交的文件了,緩存區已經被清空。

至此,咱們完成了第一次代碼提交,此次提交的代碼中咱們建立了三個新文件。須要注意的是若是是修改文件,也須要使用git add命令添加到緩存區才能夠提交。若是是刪除文件,則直接使用git rm命令刪除後會自動將已刪除文件的信息添加到緩存區,git commit提交後就會將本地倉庫中的對應文件刪除。

這個時候若是本地的倉庫鏈接到了遠程Git服務器,可使用下面的命令將本地倉庫同步到遠端服務器:

$ git push origin master 

這時候可能須要你輸入在Git服務器上的用戶名和密碼。

5、分支與合併

Git的分支可讓你在主線(master分支)以外進行代碼提交,同時又不會影響代碼庫主線。分支的做用體如今多人協做開發中,好比一個團隊開發軟件,你負責獨立的一個功能須要一個月的時間來完成,你就能夠建立一個分支,只把該功能的代碼提交到這個分支,而其餘同事仍然能夠繼續使用主線開發,你天天的提交不會對他們形成任何影響。當你完成功能後,測試經過再把你的功能分支合併到主線。

1.分支

一個Git倉庫能夠維護不少開發分支。如今咱們來建立一個新的叫 experimental的分支:

$ git branch experimental

運行git branch命令能夠查看當前的分支列表,以及目前的開發環境處在哪一個分支上:

$ git branch
 experimental
* master 

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分支上的文件了。

如今能夠在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 file3git commit命令來提交合並後的file3內容,這個過程是手動解決衝突的流程。

# 編輯衝突文件 $ vim file3 # 提交修改後的文件 $ git add file3 $ git commit -m 'merge file3' 

當咱們完成合並後,再也不須要experimental時,可使用下面的命令刪除:

$ git branch -d experimental 

git branch -d只能刪除那些已經被當前分支的合併的分支. 若是你要強制刪除某個分支的話就用git branch –D

2. 撤銷一個合併

若是你以爲你合併後的狀態是一團亂麻,想把當前的修改都放棄,你能夠用下面的命令回到合併以前的狀態:

$ git reset --hard HEAD^
# 查看file3的內容,已經恢復到合併前的master上的文件內容 $ cat file3 

3.快速向前合併

還有一種須要特殊對待的狀況,在前面沒有提到。一般,一個合併會產生一個合併提交(commit), 把兩個父分支裏的每一行內容都合併進來。

可是,若是當前的分支和另外一個分支沒有內容上的差別,就是說當前分支的每個提交(commit)都已經存在另外一個分支裏了,git 就會執行一個「快速向前"(fast forward)操做;git 不建立任何新的提交(commit),只是將當前分支指向合併進來的分支。

6、Git日誌

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)。

2.日誌統計

若是用--stat選項使用'git log',它會顯示在每一個提交(commit)中哪些文件被修改了, 這些文件分別添加或刪除了多少行內容,這個命令至關於打印詳細的提交記錄:

$ git log --stat 

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 

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:查看日誌

8、練習

開通GitHub帳號,建立練習倉庫並練習一遍上述所講的內容。

 

1、實驗說明

本節實驗爲 Git 入門第二個實驗,繼續練習最經常使用的git命令。

1.1 實驗準備

在進行該實驗以前,能夠先clone一個練習項目gitproject:

$ git clone https://github.com/shiyanlou/gitproject 

本節中的實驗操做都是在該項目中完成。

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 diffgit diff --cached都不會有任何輸出了。

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詳細查看其餘參數和功能。

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、分佈式的工做流程

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 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 [8:28:02] README.md file1 newfile 

這就把myrepo的主分支合併到了gitproject的當前分支裏了。

若是gitprojectmyrepo修改文件內容的同時也作了修改的話,可能須要手工去修復衝突。

若是你要常常操做遠程分支(remote branch),你能夠定義它們的縮寫:

$ git remote add myrepo /tmp/myrepo 

git pull命令執行兩個操做: 它從遠程分支(remote branch)抓取修改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 

若是myrepogitproject在不一樣的主機上,能夠經過ssh協議來執行clone 和pull操做:

$ git clone localhost:/home/shiyanlou/gitproject test 

這個命令會提示你輸入shiyanlou用戶的密碼,用戶密碼隨機,能夠點擊屏幕上方的SSH按鈕查看。

2.公共Git倉庫

開發過程當中,一般你們都會使用一個公共的倉庫,並clone到本身的開發環境中,完成一個階段的代碼後能夠告訴目標倉庫的維護者來pull本身的代碼。

若是你和維護者都在同一臺機器上有賬號,那麼大家能夠互相從對 方的倉庫目錄裏直接拉所做的修改,git命令裏的倉庫地址也能夠是本地的某個目錄名:

$ git clone /path/to/repository
$ git pull /path/to/other/repository

也能夠是一個ssh地址:

$ git clone ssh://yourhost/~you/repository 

3.將修改推到一個公共倉庫

經過http或是git協議,其它維護者能夠經過遠程訪問的方式抓取(fetch)你最近的修改,可是他們 沒有寫權限。如何將本地私有倉庫的最近修改主動上傳到公共倉庫中呢?

最簡單的辦法就是用git push命令,推送本地的修改到遠程Git倉庫,執行下面的命令:

$ git push ssh://yourserver.com/~you/proj.git master:master 

或者

$ git push ssh://yourserver.com/~you/proj.git master 

git push命令的目地倉庫能夠是sshhttp/https協議訪問。

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://yourserver.com/~you/proj.git master 

4、Git標籤

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 

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

對於初學者,若是不想深刻git強大的高級功能的話,學完這個實驗就能夠了,由於後續實驗內容用到的比較少,而且理解難度大。若是仍然感興趣,建議使用一段時間git後再仔細學習後續實驗,會有更好的收穫。

6、練習

使用GitHub帳號,建立本身的倉庫並練習一遍本節所講的內容。

 

1、實驗說明

從本節開始,咱們會介紹一些中級和高級的用法,這些用法不多用到,前面三節的內容已經知足了平常工做須要,從本節開始的內容能夠簡單瞭解,須要的時候再詳細查看。

1.1 下載測試項目環境

經過下列命令得到gitproject項目環境,該項目默認只有一個文件README.md,能夠用來進行後續git實驗

$ git clone https://github.com/shiyanlou/gitproject 

2、忽略某些文件

1.忽略某些文件

項目中常常會生成一些Git系統不須要追蹤(track)的文件。典型的是在編譯生成過程當中產生的文件或是編程器生成的臨時備份文件。固然,你不追蹤(track)這些文件,能夠 平時不用"git add"去把它們加到索引中。 可是這樣會很快變成一件煩人的事,你發現 項目中處處有未追蹤(untracked)的文件; 這樣也使"git add ." 和"git commit -a" 變得實際上沒有用處,同時"git status"命令的輸出也會有它們。

你能夠在你的頂層工做目錄中添加一個叫".gitignore"的文件,來告訴Git系統要忽略掉哪些文件,下面是文件內容的示例:

以'#' 開始的行,被視爲註釋。

忽略掉全部文件名是 foo.txt 的文件。

foo.txt 

忽略全部生成的 html 文件。

*.html 

foo.html是手工維護的,因此例外。

!foo.html 

忽略全部.o 和 .a文件。

*.[oa] 

3、rebase

1.rebase

假設你如今基於遠程分支"origin",建立一個叫"mywork"的分支。

$ git checkout -b mywork origin

如今咱們在這個分支作一些修改,而後生成兩個提交(commit)。

$ vi file.txt
$ git commit
$ vi 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

1.交互式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、交互式添加

1.交互式添加

交互式添加提供友好的界面去操做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^^

你也能夠把這些‘標識符'(spec)疊加起來, 下面這個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樹名。

9、練習

請在你本身的 GitHub 倉庫上操做一遍,並深刻理解這些命令。

 

1、實驗說明

1. 環境登陸

無需密碼自動登陸,系統用戶名shiyanlou

若不當心登出後,直接刷新頁面便可

2. 環境使用

實驗報告能夠在我的主頁中查看,其中含有每次實驗的截圖及筆記,以及每次實驗的有效學習時間(指的是在實驗桌面內操做的時間,若是沒有操做,系統會記錄爲發呆時間)。這些都是您學習的真實性證實。

3.下載測試項目環境

經過下列命令得到gitproject項目環境,該項目默認只有一個文件README.md,能夠用來進行後續git實驗

$ git clone https://github.com/shiyanlou/gitproject 

2、追蹤分支

1.追蹤分支

在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

當你運行下命令時:

$ git pull experimental

它會自動從‘origin'抓取(fetch)內容,再把遠程的'origin/experimental'分支合併進(merge)本地的'experimental'分支.

當要把修改推送(push)到origin時, 它會將你本地的'experimental'分支中的修改推送到origin的‘experimental'分支裏, 而無需指定它(origin).

3、使用Git Grep進行搜索

1.使用Git Grep進行搜索

用git grep 命令查找Git庫裏面的某段文字是很方便的. 固然, 你也能夠用unix下的'grep'命令進行搜索, 可是'git grep'命令能讓你不用簽出(checkout)歷史文件, 就能查找它們.

例如, 你要看 git.git這個倉庫裏每一個使用'xmmap'函數的地方, 你能夠運行下面的命令:

$ git grep xmmap 

若是你要顯示行號, 你能夠添加'-n'選項:

$ git grep -n xmmap 

若是咱們想只顯示文件名, 咱們可使用'--name-onley'選項:

$ 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中籤出而且把它恢復成未修改時的樣子.

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'目錄裏的內容,沒有任何簽出(checked out)的文件.

下一步就是你把這個 proj.git 目錄拷到你打算用來託管公共倉庫的主機上. 你能夠用scp, rsync或其它任何方式.

2.經過git協議導出git倉庫

用git協議導出git倉庫, 這是推薦的方法.

若是這臺服務器上有管理員,TA們要告訴你把倉庫放在哪個目錄中, 而且「git:// URL」除倉庫目錄部分外是什麼.

你如今要作的是啓動 git daemon; 它會監聽在 9418端口. 默認狀況下它會容許你訪問全部的git目錄(看目錄中是否有git-daemon-export-ok文件). 若是以某些目錄作爲 git-daemon 的參數, 那麼 git-daemon 會限制用戶經過git協議只能訪問這些目錄.

你能夠在inetd service模式下運行 git-daemon; 點擊 git daemon 能夠查看幫助信息.

3.經過http協議導出git倉庫

git協議有不錯的性能和可靠性, 可是若是主機上已經配好了一臺web服務器,使用http協議(git over http)可能會更容易配置一些.

你須要把新建的"裸倉庫"放到Web服務器的可訪問目錄裏, 同時作一些調整,以便讓web客戶端得到它們所需的額外信息.

$ mv proj.git /home/you/public_html/proj.git
$ cd proj.git
$ git --bare update-server-info
$ chmod a+x hooks/post-update

$ git clone http://yourserver.com/~you/proj.git

$ git clone http://yourserver.com/~you/proj.git 

7、創建一個私有倉庫

1.經過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賬號,那麼TA也能夠從這臺服務器上克隆(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)以及創建公有和私有倉庫。

9、練習

請本身建一個公有倉庫讓小夥伴能夠訪問。

 

1、實驗說明

1. 環境登陸

無需密碼自動登陸,系統用戶名shiyanlou

若不當心登出後,直接刷新頁面便可

2. 環境使用

實驗報告能夠在我的主頁中查看,其中含有每次實驗的截圖及筆記,以及每次實驗的有效學習時間(指的是在實驗桌面內操做的時間,若是沒有操做,系統會記錄爲發呆時間)。這些都是您學習的真實性證實。

3.下載測試項目環境

經過下列命令得到gitproject項目環境,該項目默認只有一個文件README.md,能夠用來進行後續git實驗

$ git clone https://github.com/shiyanlou/gitproject 

2、建立新的空分支

1.建立新的空分支

在偶爾的狀況下,你可能會想要保留那些與你的代碼沒有共同祖先的分支。例如在這些分支上保留生成的文檔或者其餘一些東西。若是你須要建立一個不使用當前代碼庫做爲父提交的分支,你能夠用以下的方法建立一個空分支:

git symbolic-ref HEAD refs/heads/newbranch rm .git/index git clean -fdx <do work> git add your files git commit -m 'Initial commit' 

3、修改你的歷史

1.修改你的歷史

交互式洐合是修改單個提交的好方法。

git filter-branch是修改大量提交的好方法。

4、高級分支與合併

1.在合併過程當中獲得解決衝突的協助

git會把全部能夠自動合併的修改加入到索引中去, 因此git diff只會顯示有衝突的部分. 它使用了一種不常見的語法:

$ git diff

回憶一下, 在咱們解決衝突以後, 獲得的提交會有兩個而不是一個父提交: 一個父提交會成爲HEAD, 也就是當前分支的tip; 另一個父提交會成爲另外一分支的tip, 被暫時存在MERGE_HEAD.

在合併過程當中, 索引中保存着每一個文件的三個版本. 三個"文件暫存(file stage)"中的每個都表明了文件的不一樣版本:

$ git show :1:file.txt $ git show :2:file.txt $ git show :3:file.txt 

當你使用git diff去顯示衝突時, 它在工做樹(work tree), 暫存2(stage 2)和暫存3(stage 3)之間執行三路diff操做, 只顯示那些兩方都有的塊(換句話說, 當一個塊的合併結果只從暫存2中獲得時, 是不會被顯示出來的; 對於暫存3來講也是同樣).

上面的diff結果顯示了file.txt在工做樹, 暫存2和暫存3中的差別. git不在每行前面加上單個'+'或者'-', 相反地, 它使用兩欄去顯示差別: 第一欄用於顯示第一個父提交與工做目錄文件拷貝的差別, 第二欄用於顯示第二個父提交與工做文件拷貝的差別. (參見git diff-files中的"COMBINED DIFF FORMAT"取得此格式詳細信息.)

在用直觀的方法解決衝突以後(可是在更新索引以前), diff輸出會變成下面的樣子:

$ git diff
diff --cc file.txt
index 802992c,2b60207..0000000
--- a/file.txt +++ b/file.txt @@@ -1,1 -1,1 +1,1 @@@ - Hello world -Goodbye ++Goodbye world 

上面的輸出顯示瞭解決衝突後的版本刪除了第一個父版本提供的"Hello world"和第二個父版本提供的"Goodbye", 而後加入了兩個父版本中都沒有的"Goodbye world".

一些特別diff選項容許你對比工做目錄和三個暫存中任何一個的差別:

$ git diff -1 file.txt $ git diff --base file.txt $ git diff -2 file.txt $ git diff --ours file.txt $ git diff -3 file.txt $ git diff --theirs file.txt 

git log和gitk命令也爲合併操做提供了特別的協助:

$ git log --merge
$ gitk --merge

這會顯示全部那些只在HEAD或者只在MERGE_HEAD中存在的提交, 還有那些更新(touch)了未合併文件的提交.

你也可使用git mergetool, 它容許你使用外部工具如emacs或kdiff3去合併文件.

每次你解決衝突以後, 應該更新索引:

$ git add file.txt 

完成索引更新以後, git-diff(缺省地)再也不顯示那個文件的差別, 因此那個文件的不一樣暫存版本會被"摺疊"起來.

2.多路合併

你能夠一次合併多個頭, 只需簡單地把它們做爲git merge的參數列出. 例如,

$ git merge scott/master rick/master tom/master 

至關於

$ git merge scott/master $ git merge rick/master $ git merge tom/master 

3.子樹

有時會出現你想在本身項目中引入其餘獨立開發項目的內容的狀況. 在沒有路徑衝突的前提下, 你只須要簡單地從其餘項目拉取內容便可.

若是有衝突的文件, 那麼就會出現問題. 可能的例子包括Makefile和其餘一些標準文件名. 你能夠選擇合併這些衝突的文件, 可是更多的狀況是你不肯意把它們合併. 一個更好解決方案是把外部項目做爲一個子目錄進行合併. 這種狀況不被遞歸合併策略所支持, 因此簡單的拉取是無用的.

在這種狀況下, 你須要的是子樹合併策略.

這下面例子中, 咱們設定你有一個倉庫位於/path/to/B (若是你須要的話, 也能夠是一個URL). 你想要合併那個倉庫的master分支到你當前倉庫的dir-B子目錄下.

下面就是你所須要的命令序列:

$ git remote add -f Bproject /path/to/B (1)
$ git merge -s ours --no-commit Bproject/master (2) $ git read-tree --prefix=dir-B/ -u Bproject/master (3) $ git commit -m "Merge B project as our subdirectory" (4) $ git pull -s subtree Bproject master (5) 

子樹合併的好處就是它並無給你倉庫的用戶增長太多的管理負擔. 它兼容於較老(版本號小於1.5.2)的客戶端, 克隆完成以後立刻能夠獲得代碼.

然而, 若是你使用子模塊(submodule), 你能夠選擇不傳輸這些子模塊對象. 這可能在子樹合併過程當中形成問題.

另外, 若你須要修改內嵌外部項目的內容, 使用子模塊方式能夠更容易地提交你的修改.

查找問題的利器 - Git Bisect

4.查找問題的利器 - Git Bisect

假設你在項目的'2.6.18'版上面工做, 可是你當前的代碼(master)崩潰(crash)了. 有時解決這種問題的最好辦法是: 手工逐步恢復(brute-force regression)項目歷史, 找出是哪一個提交(commit)致使了這個問題. 可是 linkgit:git-bisect1 能夠更好幫你解決這個問題:

$ git bisect start
$ git bisect good v2.6.18 $ git bisect bad master 

若是你如今運行"git branch", 會發現你如今所在的是"no branch"(譯者注:這是進行git bisect的一種狀態). 這時分支指向提交(commit):"69543", 此提交恰好是在"v2.6.18"和「master"中間的位置. 如今在這個分支裏, 編譯並測試項目代碼, 查看它是否崩潰(crash). 假設它此次崩潰了, 那麼運行下面的命令:

$ git bisect bad

如今git自動簽出(checkout)一個更老的版本. 繼續這樣作, 用"git bisect good","git bisect bad"告訴git每次簽出的版本是否沒有問題; 你如今能夠注意一下當前的簽出的版本, 你會發現git在用"二分查找(binary search)方法"簽出"bad"和"good"之間的一個版本(commit or revison).

在這個項目(case)中, 通過13次嘗試, 找出了致使問題的提交(guilty commit). 你能夠用 git show 命令查看這個提交(commit), 找出是誰作的修改,而後寫郵件給TA. 最後, 運行:

$ git bisect reset 

這會到你以前(執行git bisect start以前)的狀態.

注意: git-bisect 每次所選擇簽出的版本, 只是一個建議; 若是你有更好的想法, 也能夠去試試手工選擇一個不一樣的版本.

運行:

$ git bisect visualize

這會運行gitk, 界面上會標識出"git bisect"命令自動選擇的提交(commit). 你能夠選擇一個相鄰的提交(commit), 記住它的SHA串值, 用下面的命令把它簽出來:

$ git reset --hard fb47ddb2db... 

而後進行測試, 再根據測試結果執行」bisect good"或是"bisect bad"; 就這樣反覆執行, 直到找出問題爲止.

5、查找問題的利器 - Git Blame

1.查找問題的利器 - Git Blame

若是你要查看文件的每一個部分是誰修改的, 那麼 git blame 就是不二選擇. 只要運行'git blame [filename]', 你就會獲得整個文件的每一行的詳細修改信息:包括SHA串,日期和做者:

$ git blame sha1_file.c

若是文件被修改了(reverted),或是編譯(build)失敗了; 這個命令就能夠大展身手了.

你也能夠用"-L"參數在命令(blame)中指定開始和結束行:

$ git blame -L 160,+10 sha1_file.c 

6、Git和Email

1.向一個項目提交補丁

若是你只作了少許的改動, 最簡單的提交方法就是把它們作成補丁(patch)用郵件發出去:

首先, 使用git format-patch; 例如:

$ git format-patch origin 

這會在當前目錄生成一系統編號的補丁文件, 每個補丁文件都包含了當前分支和origin/HEAD之間的差別內容.

而後你能夠手工把這些文件導入你的Email客戶端. 可是若是你須要一次發送不少補丁, 你可能會更喜歡使用git send-email腳本去自動完成這個工做. 在發送以前, 應當先到項目的郵件列表上諮詢一下項目管理者, 瞭解他們管理這些補丁的方式.

2.向一個項目中導入補丁

Git也提供了一個名爲git am的工具(am是"apply mailbox"的縮寫)去應用那些經過Email寄來的系列補丁. 你只須要按順序把全部包含補丁的消息存入單個的mailbox文件, 好比說"patches.mbox", 而後運行

$ git am -3 patches.mbox 

Git會按照順序應用每個補丁; 若是發生了衝突, git會停下來讓你手工解決衝突從而完成合並. ("-3"選項會讓git執行合併操做; 若是你更喜歡停止而且不改動你的工做樹和索引, 你能夠省略"-3"選項.)

在解決衝突和更新索引以後, 你不須要再建立一個新提交, 只須要運行

$ git am --resolved

這時git會爲你建立一個提交, 而後繼續應用mailbox中餘下的補丁.

最後的效果是, git產生了一系列提交, 每一個提交是原來mailbox中的一個補丁, 補丁中的做者信息和提交日誌也一併被記錄下來.

7、定製Git

1.更改你的編輯器

$ git config --global core.editor vim 

2.添加別名

$ git config --global alias.last 'cat-file commit HEAD' $ git last $ git cat-file commit HEAD 

3.添加顏色

$ git config color.branch auto $ git config color.diff auto $ git config color.interactive auto $ git config color.status auto 

或者你能夠經過color.ui選項把顏色所有打開:

$ git config color.ui true 

4.提交模板

$ git config commit.template '/etc/git-commit-template' 

5.日誌格式

$ git config format.pretty oneline

8、Git Hooks

1.Git Hooks

鉤子(hooks)是一些在"$GIT-DIR/hooks"目錄的腳本, 在被特定的事件(certain points)觸發後被調用。當"git init"命令被調用後, 一些很是有用的示例鉤子文件(hooks)被拷到新倉庫的hooks目錄中; 可是在默認狀況下這些鉤子(hooks)是不生效的。 把這些鉤子文件(hooks)的".sample"文件名後綴去掉就可使它們生效了。

2.applypatch-msg

GIT_DIR/hooks/applypatch-msg

當'git-am'命令執行時,這個鉤子就被調用。它只有一個參數:就是存有提交消息(commit log message)的文件的名字。若是鉤子的執行結果是非零,那麼補丁(patch)就不會被應用(apply)。

這個鉤子用於在其它地方編輯提交消息,而且能夠把這些消息規範成項目的標。它也能夠在分析(inspect)完消息文件後拒絕這次提交(commit)。

3.pre-applypatch

GIT_DIR/hooks/pre-applypatch

當'git-am'命令執行時,這個鉤子就被調用。它沒有參數,而且是在一個補丁(patch)被應用後還未提交(commit)前被調用。若是鉤子的執行結果是非零,那麼剛纔應用的補丁(patch)就不會被提交。

它用於檢查當前的工做樹,當提交的補丁不能經過特定的測試就拒絕將它提交(commit)進倉庫。

4.post-applypatch

GIT_DIR/hooks/post-applypatch

當'git-am'命令執行時,這個鉤子就被調用。它沒有參數,而且是在一個補丁(patch)被應用且在完成提交(commit)狀況下被調用。

這個鉤子的主要用途是通知提示(notification),它並不會影響'git-am'的執行和輸出。

5.pre-commit

GIT_DIR/hooks/pre-commit 

這個鉤子被 'git-commit' 命令調用, 並且能夠經過在命令中添加--no-verify 參數來跳過。這個鉤子沒有參數,在獲得提交消息和開始提交(commit)前被調用。若是鉤子執行結果是非零,那麼 'git-commit' 命令就會停止執行。

當默認的'pre-commit'鉤子開啓時,若是它發現文件尾部有空白行,那麼就會停止這次提交。

6.prepare-commit-msg

GIT_DIR/hooks/prepare-commit-msg 

當'git-commit'命令執行時:在編輯器(editor)啓動前,默認提交消息準備好後,這個鉤子就被調用。

若是鉤子的執行結果是非零的話,那麼'git-commit'命令就會被停止執行。

7.commit-msg

GIT_DIR/hooks/commit-msg 

當'git-commit'命令執行時,這個鉤子被調用;也能夠在命令中添加--no-verify參數來跳過。這個鉤子有一個參數:就是被選定的提交消息文件的名字。如這個鉤子的執行結果是非零,那麼'git-commit'命令就會停止執行。

這個鉤子爲提交消息更適當,能夠用於規範提交消息使之符合項目的標準(若是有的話);若是它檢查完提交消息後,發現內容不符合某些標準,它也能夠拒絕這次提交(commit)。

默認的'commit-msg'鉤子啓用後,它檢查裏面是否有重複的簽名結束線(Signed-off-by lines),若是找到它就是停止這次提交(commit)操做。

8.post-commit

GIT_DIR/hooks/post-commit 

當'git-commit'命令執行時,這個鉤子就被調用。它沒有參數,而且是在一個提交(commit)完成時被調用。

這個鉤子的主要用途是通知提示(notification),它並不會影響'git-commit'的執行和輸出。

9.pre-rebase

GIT_DIR/hooks/pre-rebase

當'git-base'命令執行時,這個鉤子就被調用;主要目的是阻止那些不該被rebase的分支被rebase(例如,一個已經發布的分支提交就不該被rebase)。

10.post-checkout

GIT_DIR/hooks/post-checkout

當'git-checkout'命令更新完整個工做樹(worktree)後,這個鉤子就會被調用。這個鉤子有三個參數:前一個HEAD的 ref,新HEAD的 ref,判斷一個簽出是分支簽出仍是文件簽出的標識符(分支簽出=1,文件簽出=0)。這個鉤子不會影響'git-checkout'命令的輸出。

這個鉤子能夠用於檢查倉庫的一致性,自動顯示簽出先後的代碼的區別,也能夠用於設置目錄的元數據屬性。

11.post-merge

GIT_DIR/hooks/post-merge 

12.pre-receive

當用戶在本地倉庫執行'git-push'命令時,服務器上遠端倉庫就會對應執行'git-receive-pack'命令,而'git-receive-pack'命令會調用 pre-receive 鉤子。在開始更新遠程倉庫上的ref以前,這個鉤子被調用。鉤子的執行結果(exit status)決定這次更新可否成功。

每執行一個接收(receive)操做都會調用一次這個鉤子。它沒有命令行參數,可是它會從標準輸入(standard input)讀取須要更新的ref,格式以下:

SP SP LF(SP是空格,LF是回車。) 

<old-value>是保存在ref裏的老對象的名字,<new-value>是保存在ref裏的新對象的名字,<ref-name>就是這次要更新的ref的全名。若是是建立一個新的ref,那麼<old-value>就是由40個0組成的字符串表示。

若是鉤子的執行結果是非零,那麼沒有引用(ref)會被更新。若是執行結果爲零,更新操做還能夠被後面的<<update,'update'>>鉤子所阻止。

鉤子(hook)的標準輸出和標準錯誤輸出(stdout & stderr)都會經過'git-send-pack'轉發給客戶端(other end),你能夠把這個信息回顯(echo)給用戶。

若是你用ruby,那麼能夠像下面的代碼同樣獲得它們的參數。

rev_old, rev_new, ref = STDIN.read.split(" ") 

13.update

GIT_DIR/hooks/update 

當用戶在本地倉庫執行'git-push'命令時,服務器上遠端倉庫就會對應執行'git-receive-pack',而'git-receive-pack'會調用 update 鉤子。在更新遠程倉庫上的ref以前,這個鉤子被調用。鉤子的執行結果(exit status)決定這次update可否成功。

14.post-receive

GIT_DIR/hooks/post-receive

當用戶在本地倉庫執行'git-push'命令時,服務器上遠端倉庫就會對應執行'git-receive-pack'命令;在全部遠程倉庫的引用(ref)都更新後,這個鉤子就會被'git-receive-pack'調用。

9、找回丟失的對象

1.準備

咱們先建立一個用以實驗的倉庫,在裏面建立了若干個提交和分支。

$ mkdir recovery
$ cd recovery
$ git init
$ touch file
$ git add file
$ git commit -m "First commit" $ echo "Hello World" > file $ git add . $ git commit -m "Greetings" $ git branch cool_branch  $ git checkout cool_branch $ echo "What up world?" > cool_file $ git add . $ git commit -m "Now that was cool" $ git checkout master $ echo "What does that mean?" >> file 

2.恢復已刪除分支提交

如今repo裏有兩個branch

$ git branch
cool_branch
* master 

存儲當前倉庫未提交的改動

$ git stash save "temp save" 

刪除一個分支

$ git branch -D cool_branch
$ git branch
* master

用git fsck --lost-found命令找出剛纔刪除的分支裏面的提交對象。

$ git fsck --lost-found

用git show命令查看一個找到的對象的內容,看是否爲咱們所找的。

git show 2e43cd56ee4fb08664cd843cd32836b54fbf594a 

這個提交對象確實是咱們在前面刪除的分支的內容;下面咱們就要考慮一下要如何來恢復它了。

使用 git rebase 進行恢復

$ git rebase 2e43cd56ee4fb08664cd843cd32836b54fbf594a 

如今咱們用git log命令看一下,看看它有沒有恢復:

$ git log 

使用git merge 進行恢復,咱們把剛纔的恢復的提交刪除

$ git reset --hard HEAD^ 

再把剛刪的提交給找回來:

$ git fsck --lost-found

不過這回咱們用是合併命令進行恢復:

$ git merge 2e43cd56ee4fb08664cd843cd32836b54fbf594a 

3.git stash的恢復

前面咱們用git stash把沒有提交的內容進行了存儲,若是這個存儲不當心刪了怎麼辦呢?

當前repo裏有的存儲:

$ git stash list 

把它們清空:

$ git stash clear

再用git fsck --lost-found找回來:

$ git fsck --lost-found

用git show看一下回來的內容對不對:

$ git show 674c0618ca7d0c251902f0953987ff71860cb067 

看起來沒有問題,好的,那麼我就把它恢復了吧:

$ git merge 674c0618ca7d0c251902f0953987ff71860cb067 

10、子模塊

1.子模塊

一個大項目一般由不少較小的, 自完備的模塊組成. 例如, 一個嵌入式Linux發行版的代碼樹會包含每一個進行過本地修改的軟件的代碼; 一個電影播放器可能須要基於一個知名解碼庫的特定版本完成編譯; 數個獨立的程序可能會共用同一個建立腳本.

在集中式版本管理系統中, 能夠經過把每一個模塊放在一個單獨的倉庫中來完成上述的任務. 開發者能夠把全部模塊都簽出(checkout), 也能夠選擇只簽出他須要的模塊. 在移動文件, 修改API和翻譯時, 他們甚至能夠在一個提交中跨多個模塊修改文件

爲說明子模塊的使用方法, 建立4個用做子模塊的示例倉庫:

$ mkdir ~/git
$ cd ~/git $ for i in a b c d do mkdir $i cd $i git init echo "module $i" > $i.txt git add $i.txt git commit -m "Initial commit, submodule $i" cd .. done 

如今建立父項目, 加入全部的子模塊

$ mkdir super $ cd super $ git init $ for i in a b c d do git submodule add ~/git/$i $i done 

注意: 若是你想對外發布你的父項目, 請不要使用本地的地址!

列出git-submodule建立文件:

$ ls -a git-submodule add命令進行了以下的操做: 

它在當前目錄下克隆各個子模塊, 默認簽出master分支.

它把子模塊的克隆路徑加入到gitmodules文件中, 而後把這個文件加入到索引, 準備進行提交.

它把子模塊的當前提交ID加入到索引中, 準備進行提交.

提交父項目:

$ git commit -m "Add submodules a, b, c and d." 

如今克隆父項目:

$ cd ..
$ git clone super cloned $ cd cloned 

子模塊的目錄建立好了, 可是它們是空的:

$ ls -a a
$ git submodule status

注意: 上面列出的提交對象的名字會和你的項目中看到的有所不一樣, 可是它們應該和HEAD的提交對象名字一致. 你能夠運行git ls-remote ../git/a進行檢驗.

拉取子模塊須要進行兩步操做. 首先運行git submodule init, 把子模塊的URL加入到.git/config:

$ git submodule init

如今使用git-submodule update去克隆子模塊的倉庫和簽出父項目中指定的那個版本:

$ git submodule update
$ cd a
$ ls -a

git-submodule update和git-submodule add的一個主要區別就是git-submodule update簽出一個指定的提交, 而不是該分支的tip. 它就像簽出一個標籤(tag): 頭指針脫離, 你不在任何一個分支上工做.

$ git branch

如何你須要對子模塊進行修改, 同時頭指針又是脫離的狀態, 那麼你應該建立或者簽出一個分支, 進行修改, 發佈子模塊的修改, 而後更新父項目讓其引用新的提交:

$ git checkout master

或者

$ git checkout -b fix-up

而後

$ echo "adding a line again" >> a.txt $ git commit -a -m "Updated the submodule from within the superproject." $ git push $ cd .. $ git diff $ git add a $ git commit -m "Updated submodule a." $ git push 

若是你想要更新子模塊, 你應該在git pull以後運行git submodule update.

2.子模塊方式的陷阱

你應該老是在發佈父項目的修改以前發佈子模塊修改. 若是你忘記發佈子模塊的修改, 其餘人就沒法克隆你的倉庫了:

$ cd ~/git/super/a $ echo i added another line to this file >> a.txt $ git commit -a -m "doing it wrong this time" $ cd .. $ git add a $ git commit -m "Updated submodule a again." $ git push $ cd ~/git/cloned $ git pull $ git submodule update 

若是你暫存了一個更新過的子模塊, 準備進行手工提交, 注意不要在路徑後面加上斜槓. 若是加上了斜槓, git會認爲你想要移除那個子模塊而後簽出那個目錄內容到父倉庫.

$ cd ~/git/super/a $ echo i added another line to this file >> a.txt $ git commit -a -m "doing it wrong this time" $ cd .. $ git add a/ $ git status 

爲了修正這個錯誤的操做, 咱們應該重置(reset)這個修改, 而後在add的時候不要加上末尾斜槓.

$ git reset HEAD A $ git add a $ git status 

11、小結

本節講解了建立新的空分支,修改歷史,高級分支與合併,查找問題的利器Git Bisect和Git Blame,Git和Email,定製Git,Git Hooks,找回丟失的對象以及子模塊。

12、練習

本節所講是高級內容,請在本身的 GitHub 倉庫中選作幾個上面的操做。

相關文章
相關標籤/搜索