Git基本使用
安裝 Git
首先,在終端輸入git
,看看系統有沒有安裝 Git:
- 如果已經安裝過了,它會向你介紹 git 相關的命令
- 如果沒有安裝,它會告訴你沒有安裝
Linux 與 Windows 安裝方式
在 Mac 上進行開發,如果安裝了 Xcode,Git 也會被自動安裝。
安裝完成之後,需要最後一步設定:
$ git config --global user.name "Your Name"
$ git config --global user.email "email@example.com"
複製程式碼
因為 Git 是分散式版本控制系統,所以,每個機器都必須自報家門:名字和 Email 地址。
注意 git config
命令的 --global
引數,用了這個引數,表示你這臺機器上所有的 Git 倉庫都會使用這個配置,當然也可以對某個倉庫指定不同的使用者名稱和 Email 地址。
建立版本庫/倉庫/repository
使用 git init
命定把當前目錄變成 Git 可以管理的倉庫。
$ git init
Initialized empty Git repository in /Users/momo/Desktop/Git測試/.git/
複製程式碼
這就已經建立好了,並且當前目錄下多了一個 .git 的目錄,這個目錄是 Git 來跟蹤管理版本庫的。
把檔案新增到版本庫
- 使用命令
git add <file>
,注意,可以反覆多次使用,新增多個檔案; - 使用命令
git commit -m <message>
,完成。
檢視倉庫的狀態
使用 git status
可以檢視工作區的狀態
- 新建、刪除、修改了哪些檔案
- 這些檔案的狀態:not staged for commit 或者 to be committed
- 還會顯示未被追蹤的檔案 Untracked files
使用 git diff
可以檢視檔案具體的修改內容
檢視提交日誌
git log
git log --pretty=oneline
$ git log --pretty=oneline
8a26a5c6c62bb485d0a1dbed9c5d5d7de74a8964 (HEAD -> master) 刪除了檔案
59c61e6748783590b4d430de11edad75cfc2b637 修改了檔名
fd131b631e8938379b93ee1ba2f675714efdcfae 新增了一個檔案
複製程式碼
每一行前面的一大串字元是 commit id
(版本號)。
版本回退
在 Git 中,用 HEAD
表示當前版本,上一個版本是 HEAD^
,上上一個版本是 HEAD^^
,如果往上 100 個版本的話,可以寫成 HEAD~100
。
回退到上一個版本
$ git reset --hard HEAD^
HEAD is now at 59c61e6 修改了檔名
複製程式碼
去某一個版本
$ git reset --hard 8a26a
HEAD is now at 8a26a5c 刪除了檔案
複製程式碼
版本號沒必要寫全,前幾位就可以了,Git 會自動去找。
檢視版本號
使用 git log
可以檢視之前的提交記錄以及版本號。
如果已經回退到了之前的某個版本,這時候如果使用 git log
就不能看到當前版本之後的提交的版本號了。
這時如果想返回到之後的版本,可以使用 git reflog
檢視命令歷史,以確定版本號。
工作區與暫存區
工作區 (Working Directory)
之前使用了 git init
來把當前目錄變成了 Git 可以管理的倉庫。
當前目錄就是一個工作區。
版本庫 (Repository)
工作區有一個隱藏目錄 .git
,這個不算工作區,而是 Git 的版本庫。
Git 的版本庫裡存了跟多東西,其中最重要的就是成為 stage (或者叫做 index) 的暫存區,還有 Git 為我們自動建立的第一個分支 master
,以及指向 master
的一個指標叫 HEAD
。
在把工作區的檔案新增到 Git 版本庫中時需要兩步:
git add
把檔案修改新增到暫存區git commit
把暫存區的所有內容提交到當前分支
撤銷修改
當你亂改了工作區某個檔案的內容時,想直接丟棄工作區的修改,可以使用 git checkout -- file
。這個命令其實就是用版本庫裡的版本替換工作區的版本,無論工作區中是修改還是刪除檔案,都可以"一鍵還原"。命令中--
很重要,如果去掉了 --
就成了切換分支的命令了。
當你亂改了工作區的某個檔案內容,並且提交到了暫存區,想丟棄修改,分兩步。
第一步用命令 git reset HEAD file
撤銷暫存區的修改。完成之後可以用 git status
檢視一下狀態。
第二部用用上邊提到的 git checkout -- file
來丟棄工作區的修改。
當你已經用 git commit
提交到版本庫時,想要撤銷修改,可以回退版本。
刪除檔案
假設有一個已經被 Git 追蹤的檔案 test.txt。
$ ls
test.txt
複製程式碼
現在刪除它
$ rm test.txt
複製程式碼
這時檢視倉庫狀態
$ git status
On branch master
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
deleted: test.txt
no changes added to commit (use "git add" and/or "git commit -a")
複製程式碼
這個時候有兩種選擇
- 使用
git checkout -- file
放棄修改,檔案會還原 - 使用
git add file
或者git rm file
都可以將"刪除"提交到暫存區,然後可以檢視暫存區的狀態,再使用git commit
提交到版本庫。這樣工作區和版本庫裡面的檔案就都被刪除了。
建立與合併分支
每次提交,Git 都把它們串成一條時間線,這條時間線就是一條分支。一開始的時候,只有一條 master
分支。
HEAD
嚴格來講不是指向提交的,而是指向當前分支,現在是 master
。
master
是指向當前提交的。每次提交 master
就會向前移動一步。
建立新分支的時候,比如 dev
,Git 新建了一個指標 dev
,指向 master
相同的提交。切換分支的時候,Git 再把 HEAD
指向 dev
。
現在每次提交時,dev
就會往前移動,而 master
不變。
在 dev
上的工作完成之後,就可以把 dev
合併到 master
上了。當前這種情況,Git 會直接把 master
指向 dev
的當前提交,就完成了合併:
合併完成之後,可以刪除 dev
分支。刪除 dev
分支就是把 dev
指標刪掉。
檢視當前分支:
$ git branch
複製程式碼
建立分支:
$ git checkout 分支名稱
複製程式碼
切換分支:
$ git branch 分支名稱
複製程式碼
建立並切換分支:
$ git checkout -b 分支名稱
複製程式碼
合併指定分支到當前分支:
$ git merge 指定分支名稱
複製程式碼
刪除分支:
$ git branch -d 分支名稱
複製程式碼
Fast-forward 快進模式:
之前做的合併操作就是快進模式,直接把 master
指向 dev
的當前提交,所以合併速度非常快。除了這種模式,還有其它的合併方式。
解決衝突
當兩條分支都提交了修改時,這時候合併就不是快進模式了,它只能試圖把各自的修改合併起來。
如果兩條分支都修改了同一處,那麼它就會不知道應該改採用哪個分支的修改,這就是衝突。
$ git merge dev
Auto-merging test.txt
CONFLICT (content): Merge conflict in test.txt
複製程式碼
這段命令試圖將 dev 合併到 master,但是產生了衝突,Git 提示我在 test.txt 檔案中有衝突。
使用 git status
檢視工作區的狀態,它也告訴我衝突的檔案:
$ git status
On branch master
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: test.txt
no changes added to commit (use "git add" and/or "git commit -a")
複製程式碼
檢視 test.txt
檔案的內容:
$ cat test.txt
1
<<<<<<< HEAD
3
4
=======
2
3
>>>>>>> dev
複製程式碼
可以看到,test.txt 檔案中本來只有第一行寫的是 1
。
master
分支上新增了 3、4 並做了提交。
dev
分支上新增了 2、3 並做了提交。
在 git merge dev
之後,Git 把 dev 分支的 test.txt 檔案合併到了 master 分支的 test.txt 檔案。並且標記出了有衝突的地方。
手動修改 test.txt 處理衝突後,使用 git add
、git commit
進行提交,這樣整個合併過程才算是完成。
如果合併的過程中沒有出現衝突,那麼 Git 會提示我們輸入 message,輸入完成之後已經合併成功了。
使用 git log --graph
命令也可以檢視分支合併的情況:
$ git log --pretty=oneline --graph --abbrev-commit
* 5403d91 (HEAD -> master) Merge branch 'dev'
|\
| * 4f86c6a (dev) dev commit 3
* | 0372da4 master merge from dev 2
|\ \
| |/
| * cd070ad dev commit 2
* | c746cc7 master merge from dev
|\ \
| |/
| * 794d56a dev commit 1
* | cfe77bc master commit 2
|/
* 7bca0cd master commit 1
複製程式碼
從下往上看:
- 我先在 master 上做了一次提交,master commit 1。
- 建立並切換到了 dev 分支。
- 切換回 master 分支。在 master 上修改 test.txt 並提交,master commit 2。
- 切換到 dev,修改 test.txt 並提交,dev commit 1。
- 切換到 master,開始合併分支 -> 遇到衝突 -> 修改檔案處理衝突 -> 提交 -> 合併完成,master merge from dev。
- 切換到 dev,修改提交,dev commit 2。
- 切換到 master,合併分支,master commit merge from dev 2。
- 切換到 dev ,修改提交,dev commit 3。
- 切換回 master,合併,Merge branch 'dev'。
分支管理策略
合併分支時,如果可能,Git 會使用 Fast forward
模式,但這種模式下,刪除分之後,會丟失掉分支的資訊。
可以通過 --no-ff
強制禁用 Fast forward
模式,這樣 Git 就會在 merge 時產生一個新的 commit,這樣從分支歷史上就可以看出分支資訊。例如:
$ git merge --no-ff -m "merge with no-ff" dev
複製程式碼
合併分支時,快進模式下沒有產生提交,所以不用輸入資訊。非快進模式下的合併,產生了一次提交,用 -m
輸入提交資訊。
合併之後的圖就像這樣:
在實際開發中:
master
分支應該是非常穩定的,僅用來發布新版本,平時不能在上面幹活。
幹活都在 dev
分支上,dev
分支時不穩定的,到某個時候,比如 1.0 版本釋出時,再把 dev
分支合併到 master
上,在 master
分支釋出 1.0
版本;
小夥伴們在 dev
分支上幹活,每個人都有自己的分支,時不時地往 dev
分支上合併就可以了。
所以,團隊協作的分支看起來就像這樣:
Bug 分支
當線上出現 bug 需要即刻修復時。可以切換到 master,在建立分支 bug_101
,在分支上解決完 bug 之後合併到 master 上,然後刪除 bug_101
分支。
在切換分支分支的時候,如果當前分支上還存在沒有提交的修改,那麼是不能進行切換分支的。但是現在工作只進行到了一半,還沒辦法提交,這時可以使用 stash
功能,可以把當前工作縣城 "儲藏" 起來,等以後恢復現場後繼續工作:
$ git stash
複製程式碼
$ git stash pop
複製程式碼
新功能分支
當開發一個新功能的時候,最好也建立一個新的分支。
如果要強制刪除一個沒有被合併過的分支,可以使用 git branch -D <name>
。
遠端倉庫
SSH Key
本地的 Git 倉庫和遠端庫之間的傳輸一半都是通過 SSH 加密的,所以需要設定 SSH Key。
第 1 步:建立 SSH Key。在使用者主目錄下,看看有沒有 .ssh 目錄,再看看這個目錄下有沒有 id_rsa
和 id_rsa.pub
這兩個檔案,如果已經有了,可以直接跳到下一步。如果沒有,建立 SSH Key:
$ ssh-keygen -t rsa -C youremail@example.com
複製程式碼
把郵件替換成自己的郵件地址,一路回車即可,這裡無需設定密碼。
完成之後就可以在 ~/.ssh 中看到 i_rsa 和 id_rsa.pub 這兩個檔案。這就是 SSH Key 的金鑰對,id_rsa
是私鑰,id_rsa.pub
是公鑰,可以放心地告訴任何人。
第 2 步:在遠端網站上找到設定SSH Key
的頁面,將 id_rsa.pub
檔案中的內容粘進去即可。
為什麼遠端網站需要 SSH Key呢?
因為遠端網站需要識別出你推送的提交確實是你推送的,而不是別人冒充的,而 Git 支援 SSH 協議,所以,它只要知道了你的公鑰,就可以確認只有你自己才能推送。
當然,也可以在網站新增多個公鑰,這樣就可以了使用多個電腦推送了。
關聯遠端倉庫
先有本地倉庫
假設現在已經有了一個本地倉庫,又想建立一個遠端倉庫,並且這兩個倉庫可以同步,可以這樣做:
第 1 步:先建立一個空的遠端倉庫,然後在本地倉庫目錄下執行命令:
$ git remote add origin git@github.com:遠端倉庫名稱
複製程式碼
執行後遠端倉庫的名稱就是 origin
,這也是 Git 預設的叫法,也可以改成別的。
這樣 orign 就與我們的本地倉庫關聯起來了。
第 2 步:現在我們就可以把本地倉庫的所有內容推送到遠端庫上:
$ git push -u origin master
複製程式碼
把本地庫的內容推送到遠端,用 git push
命令,實際上是把當前分支 master
推送到遠端。
由於遠端庫是空的,所以第一次推送 master
分支時,加上了 -u
引數,Git 不但會把本地的 master
分支內容推送的遠端新的 master
分支,還會把本地的 master
分支和遠端的 master
分支關聯起來,在以後的推送或者拉取時就可以簡化命令。
第 3 步:以後本地提交之後,就可以使用:
$ git push origin master
複製程式碼
把本地 master
分支的最新修改推送至 origin。
先有遠端倉庫
如果從零開發的話,最好的方式是先建立遠端庫,然後,從遠端庫克隆。使用 git clone
命令即可。
$ git clone 遠端倉庫給的地址
複製程式碼
這樣就可以把遠端倉庫克隆到本地,並且它們相關聯。
多人協作
當從遠端倉庫克隆的時候,實際上 Git 自動把本地的 master
分支和遠端的 master
分支對應起來了,並且,遠端倉庫的預設名稱是 origin
。
要檢視遠端庫的資訊,用 git remote
,用 git remote -v
可以顯示更詳細的資訊:會顯示可以抓取和推送的origin
的地址。如果沒有推送許可權,就看不到 push 的地址。
推送分支
推送分支就是把該分支上所有本地提交推送到遠端庫。推送時,要指定本地分支,這樣,Git 就會把該分支推送到遠端庫對應的遠端分支上:
$ git push origin 分支名稱
複製程式碼
抓取分支
在開發時,我們會是不是向遠端分支推送新的提交。如果在推送的時候,別人也碰巧修改了這裡,那麼就會產生衝突,推送失敗。
解決的辦法也很簡單,先用 git pull
把最新的提交從抓下來,與本地的分支合併,解決衝突後再推送。
更詳細的說明點這裡。