測(cè)試人學(xué)習(xí)Git

作為一枚測(cè)試,一直貪方便使用SourceTree工具進(jìn)行Git操作,以致無(wú)法深刻理解Git的精髓,上周重新學(xué)習(xí)了廖雪峰老師的Git教程,瞬間豁然開(kāi)朗。

Git安裝

從官網(wǎng)下載Git安裝包,安裝完成后,打開(kāi)Git Bash設(shè)置本機(jī)的用戶(hù)名和郵箱。

git config --global user.name "用戶(hù)名"
git config --global user.email "郵箱地址"

創(chuàng)建版本庫(kù)及添加文件

使用git init命令可以把本地的目錄變?yōu)榭晒芾淼膅it倉(cāng)庫(kù)。

git_init.png

執(zhí)行完命令后,可發(fā)現(xiàn)目錄下多了一個(gè).git的目錄。該目錄是隱藏的,可使用以下命令查看。

ls -ah
git_init1.png

使用以下命令添加文件到版本庫(kù),第一步添加倉(cāng)庫(kù),第二步提交倉(cāng)庫(kù)。

git add learn.txt
git commit -m "create learn.txt"

git_add_commit.png

再次修改本地的learn.txt文件,使用git status查看倉(cāng)庫(kù)狀態(tài),可以看到提示文件有改動(dòng)。

$ git status
On branch 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:   learngit.txt

no changes added to commit (use "git add" and/or "git commit -a")

使用git diff命令對(duì)比文件改動(dòng)的內(nèi)容,可以看到文件后面加了一行“add by tomandy ---update1” 。

$ git diff learngit.txt
WARNING: terminal is not fully functional
diff --git a/learngit.txt b/learngit.txt
index 97f3542..12b8c54 100644
--- a/learngit.txt
+++ b/learngit.txt
@@ -1,2 +1,3 @@
 i am tomandy.
 who are you?tomandy
+add by tomandy ---update1
\ No newline at end of file

git diff #是工作區(qū)(work dict)和暫存區(qū)(stage)的比較。
git diff --cached #是暫存區(qū)(stage)和分支(master)的比較
git diff HEAD -- learngit.txt命令可以查看工作區(qū)和版本庫(kù)里面最新版本的區(qū)別。

版本回退

git log或git log --pretty=oneline可以查看版本日志。

$ git log
WARNING: terminal is not fully functional
commit 90cfb6d8576f26f46159521e6e1a3f17662e769b
Author: linrongbiao <linrongbiao@hfbank.com.cn>
Date:   Tue Mar 13 14:32:31 2018 +0800

    add something

commit ad0d3bb95e93da1bf22be6d7f689e25a33c90562
Author: linrongbiao <linrongbiao@hfbank.com.cn>
Date:   Tue Mar 13 11:41:22 2018 +0800

    create learngit.txt

    
$ git log --pretty=oneline
WARNING: terminal is not fully functional
90cfb6d8576f26f46159521e6e1a3f17662e769b add something
ad0d3bb95e93da1bf22be6d7f689e25a33c90562 create learngit.txt 

在git中,HEAD表示當(dāng)前版本,也就是上述的90cfb6d8576f26f46159521e6e1a3f17662e769b版本id,上一個(gè)版本是HEAD^, 上上個(gè)版本是HEAD^^,往上100個(gè)版本寫(xiě)成HEAD~100。可以使用git reset命令進(jìn)行版本回退。

$ cat learngit.txt
i am tomandy.
who are you?tomandy
add by tomandy ---update1
$ git reset --hard head^
HEAD is now at ad0d3bb create learngit.txt

$ cat learngit.txt
i am tomandy.
who are you?tomandy

可以發(fā)現(xiàn),learngit.txt回到了最初的版本,即去掉了“add by tomandy ---update1”這行。
git reflog命令記錄每次執(zhí)行的操作日志。

$ git reflog
WARNING: terminal is not fully functional
ad0d3bb HEAD@{0}: reset: moving to head^
90cfb6d HEAD@{1}: commit: add something
ad0d3bb HEAD@{2}: commit (initial): create learngit.txt

git reset命令也可以根據(jù)版本id進(jìn)行版本回退。

$ git reset --hard 90cfb6d
HEAD is now at 90cfb6d add something

$ cat learngit.txt
i am tomandy.
who are you?tomandy
add by tomandy ---update1

可以發(fā)現(xiàn),“add by tomandy ---update1”又回來(lái)了。

工作區(qū)和緩存區(qū)

工作區(qū)有個(gè)隱藏的.git目錄,是Git的版本庫(kù)。Git版本庫(kù)提供了成為stage的暫存區(qū),還有Git為我們自動(dòng)創(chuàng)建的第一個(gè)分支master,以及指向master分支的一個(gè)HEAD指針。

工作區(qū)和暫緩區(qū).png

第一步的git add相當(dāng)于把文件添加到暫緩區(qū)。第二部的git commit實(shí)際上是把暫緩區(qū)的所有內(nèi)容提交到當(dāng)前分支。

撤銷(xiāo)修改

git checkout -- learngit.txt用于把文件在工作區(qū)的修改全部撤銷(xiāo),有以下兩種情況。

  • 一種是learngit.txt修改后還沒(méi)放到暫存區(qū),撤銷(xiāo)修改后就回到和版本庫(kù)一模一樣的狀態(tài)。
  • 一種是learngit.txt修改后已放到暫存區(qū),工作區(qū)又做了修改,撤銷(xiāo)修改后回到添加暫緩區(qū)一模一樣的狀態(tài)。
    總之就是讓文件內(nèi)容回到最近一次git commit或git add的狀態(tài)。
$ cat learngit.txt
i am tomandy.
who are you?tomandy
add by tomandy ---update1
add by tomandy ---update2
add by tomandy ---update3

$ git checkout -- learngit.txt

$ cat learngit.txt
i am tomandy.
who are you?tomandy
add by tomandy ---update1
add by tomandy ---update2

通過(guò)以上命令,發(fā)現(xiàn)learngit.txt恢復(fù)為與版本庫(kù)一致。
git reset head leargit.txt可以把暫存區(qū)的修改撤銷(xiāo)掉,重新放回工作區(qū),然后再使用git checkout -- learngit.txt撤銷(xiāo)工作區(qū)的修改。git checkout其實(shí)是用版本庫(kù)里的版本替換工作區(qū)的版本,無(wú)論工作區(qū)是修改還是刪除,都可以“一鍵還原”。

$ git add learngit.txt

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   learngit.txt


$ git reset head learngit.txt
Unstaged changes after reset:
M       learngit.txt

$
On branch 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:   learngit.txt

no changes added to commit (use "git add" and/or "git commit -a")

$ git checkout -- learngit.txt

$ cat learngit.txt
i am tomandy.
who are you?tomandy
add by tomandy ---update1
add by tomandy ---update2
add by tomandy ---update3

刪除文件

git rm命令可以刪除版本庫(kù)的文件。比如刪除了工作區(qū)的test.txt文件后,git status展示文件與版本庫(kù)不一致,此時(shí)可以使用git rm刪除版本庫(kù)文件,然后再git commit。

$ rm test.txt

$ ls
learngit.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 rm test.txt
rm 'test.txt'

$ git commit -m "delete test.txt"
[master 4a2a120] delete test.txt
 1 file changed, 1 deletion(-)
 delete mode 100644 test.txt

遠(yuǎn)程倉(cāng)庫(kù)

本地Git倉(cāng)庫(kù)和遠(yuǎn)程Github倉(cāng)庫(kù)之間的傳輸是通過(guò)SSH加密的,所以需要先創(chuàng)建SSH key,創(chuàng)建成功的話(huà),最終在用戶(hù)目錄C:\Users\lenovo.ssh下可以看到id_rsa和id_rsa.pub兩個(gè)文件,把公鑰的內(nèi)容添加到Github。

$ ssh-keygen -t rsa -C "youremail@example.com"

為什么GitHub需要SSH Key呢?因?yàn)镚itHub需要識(shí)別出你推送的提交確實(shí)是你推送的,而不是別人冒充的,而Git支持SSH協(xié)議,所以,GitHub只要知道了你的公鑰,就可以確認(rèn)只有你自己才能推送。
Github上建立遠(yuǎn)程倉(cāng)庫(kù)后,可以克隆本地,也可以把本地的Git版本庫(kù)關(guān)聯(lián)遠(yuǎn)程倉(cāng)庫(kù),使用以下命令:

git remote add origin git@github.com:Tomandy1988/TestProject.git

或者克隆遠(yuǎn)程倉(cāng)庫(kù)到本地:

git clone git@github.com:Tomandy1988/TestProject.git

下一步就可以把本地庫(kù)的內(nèi)容全部推送到遠(yuǎn)程倉(cāng)庫(kù):

$ git push -u origin master
The authenticity of host 'github.com (192.30.253.113)' can't be established.
RSA key fingerprint is 16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'github.com,192.30.253.113' (RSA) to the list of known hosts.
Counting objects: 16, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (10/10), done.
Writing objects: 100% (16/16), 1.27 KiB | 0 bytes/s, done.
Total 16 (delta 3), reused 0 (delta 0)
remote: Resolving deltas: 100% (3/3), done.
To git@github.com:Tomandy1988/TestProject.git
 * [new branch]      master -> master
Branch master set up to track remote branch master from origin.

由于遠(yuǎn)程庫(kù)是空的,我們第一次推送master分支時(shí),加上了-u參數(shù),Git不但會(huì)把本地的master分支內(nèi)容推送到遠(yuǎn)程新的master分支,還會(huì)把本地的master分支和遠(yuǎn)程的master分支關(guān)聯(lián)起來(lái),在以后的推送或者拉取時(shí)就可以簡(jiǎn)化命令。
后續(xù)本地作了提交,就可以通過(guò)以下命令把本地master分支的最新修改推送至Github遠(yuǎn)程倉(cāng)庫(kù):

git push origin master

創(chuàng)建與合并分支

master分支是一條線(xiàn),Git用master指向最新的提交,再用Head指向master,就能確定當(dāng)前分支,以及當(dāng)前分支提交點(diǎn),每次提交,master分支都會(huì)向前移動(dòng)一步。

master分支.png

當(dāng)我們創(chuàng)建新的分支dev時(shí),Git新建了一個(gè)指針叫dev,指向master相同的提交,再把HEAD指向dev,就表示當(dāng)前分支在dev上。
dev分支.png

后續(xù)對(duì)工作區(qū)的修改和提交就是針對(duì)dev分支了,比如新提交一次后,dev指針往前移動(dòng)一步,而master指針不變;
dev分支2.png

dev分支的工作完成后,就可以把dev合并到master上了,接著再刪除dev分支。
devmaster分支合并.png

dev分支刪除.png

以下兩組命令效果是一樣的,創(chuàng)建并切換到dev分支:

$ git checkout -b dev
等同于
$ git branch dev
$ git checkout dev

git branch命令列出所有分支,當(dāng)前分支前面標(biāo)注*號(hào)。

$ git branch
* dev
  master

如果在dev分支進(jìn)行工作,后可以通過(guò)以下命令將dev分支合并到master分支,git merge屬于快進(jìn)模式合并,也就是直接把master指向dev當(dāng)前提交,所以合并速度非???。

$ git merge dev
Already up-to-date.

使用git branch -d dev刪除分支。

解決沖突

分支合并往往不是一帆風(fēng)順。比如創(chuàng)建并切換到分支feature,然后修改learngit.txt提交(增加一行“add by tomandy ---update4”)。

$ git add learngit.txt 
$ git commit -m "AND update4"

切換到master分支,增加一行“add by tomandy ---update5”到learngit.txt,此時(shí)master分支和feature分支各自都分別有新的提交,如下圖所示。

沖突.png

這種情況下,Git無(wú)法執(zhí)行“快速合并”,只能試圖把各自的修改合并起來(lái),但這種合并就可能會(huì)有沖突,我們?cè)囋嚳矗?p>

$ git merge feature1
Auto-merging learngit.txt
CONFLICT (content): Merge conflict in learngit.txt
Automatic merge failed; fix conflicts and then commit the result.

查看發(fā)現(xiàn)learngit.txt文件標(biāo)記了不同分支的差異:

$ cat learngit.txt
i am tomandy.
who are you?tomandy
add by tomandy ---update1
add by tomandy ---update2
add by tomandy ---update3
<<<<<<< HEAD
add by tomandy ---update5
=======
add by tomandy ---update4
>>>>>>> dev

修改learngit.txt后,再提交即可解決沖突,最終master和feature分支變成如下圖所示:

沖突1.png

使用以下命令可以查看分支的合并情況 。

$ git log --graph --pretty=oneline --abbrev-commit
WARNING: terminal is not fully functional
*   34fced9 add update4 not update5
|\
| * 7383c70 add update4
* | 0db4d8c add update5
|/
*   3f682d7 conflict fixed
|\
| * cd1f79b add and to test.txt
* | 211f418 add & to test.txt
|/
* daa2f86 add test.txt
* 4a2a120 delete test.txt
* 407a04b add test.txt
* 5529036 add update3
* 73f4ef3 add update2
* 90cfb6d add something
* ad0d3bb create learngit.txt

分支管理策略

通常,合并分支時(shí),如果可能,Git會(huì)用Fast forward模式,但這種模式下,刪除分支后,會(huì)丟掉分支信息。如果要強(qiáng)制禁用Fast forward模式,Git就會(huì)在merge時(shí)生成一個(gè)新的commit,這樣,從分支歷史上就可以看出分支信息。

$ git merge --no-ff -m "merge with no-ff" dev
Merge made by the 'recursive' strategy.
 readme.txt |    1 +
 1 file changed, 1 insertion(+)

在實(shí)際開(kāi)發(fā)中,我們應(yīng)該按照幾個(gè)基本原則進(jìn)行分支管理:
首先,master分支應(yīng)該是非常穩(wěn)定的,也就是僅用來(lái)發(fā)布新版本,平時(shí)不能在上面干活;那在哪干活呢?干活都在dev分支上,也就是說(shuō),dev分支是不穩(wěn)定的,到某個(gè)時(shí)候,比如1.0版本發(fā)布時(shí),再把dev分支合并到master上,在master分支發(fā)布1.0版本;
你和你的小伙伴們每個(gè)人都在dev分支上干活,每個(gè)人都有自己的分支,時(shí)不時(shí)地往dev分支上合并就可以了。
所以,團(tuán)隊(duì)合作的分支看起來(lái)就像這樣:

團(tuán)隊(duì)合作分支.png

多人協(xié)作

以下命令查看遠(yuǎn)程倉(cāng)庫(kù)信息。

$ git remote
origin

$ git remote -v
origin  git@github.com:Tomandy1988/TestProject.git (fetch)
origin  git@github.com:Tomandy1988/TestProject.git (push)

當(dāng)從遠(yuǎn)程庫(kù)clone時(shí),默認(rèn)情況下,只能看到本地的master分支。如果要在dev分支上開(kāi)發(fā),就必須創(chuàng)建遠(yuǎn)程origin的dev分支到本地,可以使用以下命令創(chuàng)建本地dev分支。

$ git checkout -b dev origin/dev

使用以下命令指定本地dev分支與遠(yuǎn)程origin/dev分支的鏈接。

$ git branch --set-upstream dev origin/dev
Branch dev set up to track remote branch dev from origin.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容