Git中~你必須掌握的!

前言:

大佬直接進入下面正題,前言能夠略過!git

我相信有不少童鞋在剛開始使用git或者使用了許久以後仍是對git不怎麼熟悉,尤爲是出現了一大堆英文提示的時候手足無措,又或者代碼"莫名其妙"的發生改動,致使團隊沒法繼續正常工做的時候真巴不得不繼續使用git了.github

不要慌!這篇文章將帶你完徹底全掌握平時常見的場景以及出現的問題如何解決的本領!(同時我本身也能夠再複習一遍~🤭)shell

那麼本文章默認你已經學習過了git,但只是對git有的知識只知其一;不知其二的狀況下去闡述!(也許熱愛git的你還不熟悉git基礎知識建議能夠先去其餘地方學習git相關的基礎知識,遇到不理解的也許這篇文章就會幫你解開謎團!)bash

最小配置

那麼咱們會發如今使用git以前須要配置一段這樣的命令(若是不配置之後push之類的操做會有一大堆提示信息影響咱們的後續操做):app

$ git config --global user.name 'your_name'
 $ git config --global user.email 'your_email@domain.com'
複製代碼

那麼這段命令中的--global你們有沒有想過是什麼意思呢?究竟有什麼做用?dom

config三個做用域

來說下剛剛的--global(全局),那麼既然有全局就確定有局部做用域:在git中叫作--local,其實還有一個是針對系統的:--system學習

--global是對當前用戶(根據系統用戶名斷定)全部倉庫有效測試

--local只對當前工做的這個倉庫有效fetch

--system對系統全部登陸的用戶有效(不經常使用,對整個系統進行配置統一的配置項)ui

查看config的設置命令:

$ git config --list --local
 $ git config --list --global
 $ git config --list --system
複製代碼

創建git倉庫

把已有的項目代碼歸入Git管理(場景一):

$ cd 項目代碼所在的文件夾
$ git init
複製代碼

新建的項目直接用Git管理(場景二):

$ cd 某個文件夾
$ git init your_project #會在當前路徑下建立和項目名稱同名的文件夾
$ cd your_project
複製代碼

文件重命名(方法一)

假設咱們重命名readme.mdread.md 因此咱們執行如下命令

$ mv readme.md read.md
複製代碼

這條命令會被git認爲是 readme.md會刪除掉了,而後新增了一個read.md文件

咱們如今要作的是把新增的read.md文件添加到git管理裏,且刪除原來的readme.md文件

$ git add read.md
$ git rm readme.md
複製代碼

而後使用git status查看管理狀態 結果會發現如今變成了

Changes to be commited:
(use "git reset HEAD <file>..." to unstage)
    renamed: readme.md -> read.md
複製代碼

至此,說明git已經知道了咱們在作重命名操做

假設如今咱們發現本身誤操做了,不想要剛剛的操做了,怎麼辦呢?

$ git reset --hard
複製代碼

其實這條命令屬於git中比較危險的命令,他的意思是把暫存區工做空間裏內容都清理掉(還原到剛剛操做重命名以前的狀態)

文件重命名(方法二)

細心的童鞋可能發現剛剛重命名的操做過於複雜,那有沒有簡單的方法重命名呢?答案是:固然有!(有木有很激動)

$ git mv readme.md read.md
複製代碼

而後使用git status查看管理狀態 結果會發現如今也變成了

Changes to be commited:
(use "git reset HEAD <file>..." to unstage)
    renamed: readme.md -> read.md
複製代碼

這樣一句命令就完成了方法一完成的事情,是否是很簡單呢~ 那麼咱們想提交本次操做該怎麼作呢? 咱們能夠直接使用

$ git commit -m '重命名readme.md爲read.md'
複製代碼

咱們發現如今已經成功的新生成了一個commit記錄

那麼咱們忽然發現此次commit沒什麼做用想撤銷本次commit提交該怎麼作

$ git log #查看全部commitId
$ git revert <commit> #找到你想撤銷的commitId複製並替換掉這裏的<commit>
複製代碼

commitId是相似這樣的:

刪除暫存區文件(並不會直接刪除工做區的文件)

$ git rm 文件名
複製代碼

暫存區相關

$ git rm --cached . #清理暫存區全部文件
複製代碼

git log

經過git log查看版本演變歷史

其實git log後面還能夠攜帶參數

$ git log --oneline --all #能夠查看簡潔的全部commit信息
$ git log -n4 #表明查看最近四次的commit信息
$ git log --all --graph #查看基於圖形的commit歷史記錄
$ git log --oneline <branch> #查看某個分支的commit記錄
複製代碼

分支操做

$ git branch -av #查看本地共有多少分支
$ git checkout -b temp #建立一個新的temp分支
$ git checkout -b temp <commitId> #基於某一個歷史版本新建一個分支 
複製代碼

刪除分支

$ git branch -d 分支名
複製代碼

若是git有提示說明是在一些狀況下git不容許刪除,若是確認的確須要刪除,那麼能夠把小寫d改爲大寫D來強制刪除

圖形界面(git自帶)

gitk
複製代碼

打開後也許會是這樣

固然我們能夠藉助第三方的軟件,確定比git自帶的使用更加方便快捷,由於這篇文章重點偏向命令式操做,因此這裏就不過多介紹了

分離頭指針(detached HEAD)

有時候咱們會作出以下操做

$ git checkout 415c5c8086e16 #後面的隨機字符串指的是某一次的commitId
複製代碼

這時git會給咱們出現相似下面的提示

what? 這段話大概是在說:

你正在基於415c5c8086e16這個commit正在作一個checkout的操做。 你如今正在處於分離頭指針的狀態,你能夠作一些變動,產生一些commit,或者你也能夠把你本身生成的這個commit丟棄掉,或者你能夠繼續作開發,並不會影響其餘分支! 那麼說的明白點就是:

咱們如今正工做在沒有分支的狀況下,那麼就是說如今沒有branch跟它掛鉤對應,那麼若是當咱們在這種狀況下作了一些功能的開發後又切換到了其餘分支後,最後極可能會被git當作垃圾清理掉,因此這就是分離頭指針危險的地方!

但話又說回來,事物都具備兩面性,用的很差或者在不知情的狀況下使用確定會對咱們產生危害,但假設咱們知道的他會有什麼影響後,說不定多想一想,還可能會帶給咱們好處呢。

好處場景舉例:有時候變動只是嘗試性的變動,若是作出來感受很差或者不想要了,那咱們就能夠隨時把它扔掉(直接checkout到其餘分支,不理會他,過段時間就會自動被git清理掉)!那假設咱們坐下來感受還不錯,那麼咱們就可使用

$ git commit -am '提交信息' #這條命令意思是直接生成commit不用add,但不推薦
複製代碼

咱們提交後,準備使用git log看下commit記錄,而後就會發現一件奇怪的事情發生:

咱們仔細看下圖片,右邊只有一個HEAD,正常狀況下,HEAD總會跟一個分支掛鉤,但如今怎麼沒有分支啦? 說明如今咱們還處於分離頭指針狀態!

咱們如今嘗試切換一下分支到master分支!

切換後git可能會出來以下提示

它說有一個commit在後面尚未加到master分支裏面去,那麼這個其實就是分離頭指針致使的!

而後下面它還會再次提醒你,若是你想保存此次的commit記錄,那麼你能夠新建一個分支和這個3d4731d這個commit相關聯!

若是你看都不看一眼這個提示,繼續任性的往下隨心操做,那麼你剛剛在分離頭指針狀態下作的操做會通通丟掉!因此git的提示要多看

比較兩個commit之間的差別

$ git diff commitId1 commitId2
$ git diff HEAD HEAD~1
$ git diff HEAD HEAD^
複製代碼

**HEAD能夠指代最新的commit記錄

^是指最新的commit的上一個commit

^^就是指上上一個

~1也是指上一個 ~2就是上上一個

因此這三條命令效果是同樣的**

commit相關操做

修改最新commit的message

有時候咱們提交的commit了發現描述的信息不全面,想進行修改,那麼咱們可使用下面這條命令

$ git commit --amend
複製代碼

而後git會彈出一個新界面,讓咱們調整以前的message,修改後咱們可使用:wq!來保存這個新修改的message而且退出這個窗口

修改前幾回的commit的message

咱們先來看張圖

這裏咱們用到了 git中的 變基指令 那麼本次咱們想對圖中標2的commit的message進行變動,那麼咱們該怎麼作? 這裏強調下,參數i是 指交互式變基就是指會彈出窗口讓咱們更方便操做的方式進行 變基 還有就是 被變基的commit的commitId會發生改變哦!

重點來嘍 這裏咱們須要選擇一個,咱們此次要變動第二個commit,那麼這個基就要選擇被變(第二個commit)的這個commit的父級(第三個commit),父級的commitId是(27d2f814開頭的那個),本身的commitId是(429243060b開頭的那個),因此要基於父級(27d2f814開頭的那個commit)去作變基操做!

這塊比較繞,你們本身先捋一捋

接下來看命令操做!

$ git rebase -i 27d2f814
複製代碼

敲下回車後咱們發現彈出來了一個交互式的窗口 如圖:

咱們把4292430開頭的那個commitmessage修改爲 Add a refering projects

因此咱們把pick指令改爲reword指令

因此最終交互式窗口裏的內容就會被咱們修改成

$ reword 4292430 Add refering projects #這裏咱們只把剛剛的pick修改成了reword
$ pick a7dc188 Move filename readme.md to readme #本句能夠無視,本例中只修改了第一句
複製代碼

修改完畢後咱們使用:wq!保存並退出交互式控制檯 而後接着git又會彈出另外一個新窗口

那麼咱們在這裏把Add refering projects修改成Add a refering project

修改完畢後咱們使用:wq!保存並退出交互式控制檯 而後git會作出以下提示:

說明咱們的變基操做順利完成了

變基操做實際上是用到了分離頭指針去完成的, 其實git先分離頭指針,而後在上面作了調整,調整完畢後git還把新的commit產生後用一個指針指向了它!

但這裏須要注意:這只是本地的變基行爲,若是有多人已經在線上操做正式項目,切不可盲目用該命令隨意操做,否則後果很嚴重!

差別比較

暫存區和HEAD差別比較

說白了就是add後的文件和最新commit作比較

$ git diff --cached
複製代碼

工做區和暫存區的差別比較

說白了就是本身最新寫的代碼和add裏的對比

$ git diff -- 文件名
$ git diff #比較全部工做區和暫存區的差別
複製代碼

對比不一樣分支的相同文件的差別

$ git diff 分支一 分支二 -- 文件名
複製代碼

恢復相關

暫存區恢復爲和HEAD(最新的commit)的內容同樣

有時候咱們add後忽然發現咱們不要暫存區的東西了,因此就要使用到以下命令了

$ git reset HEAD 或 git reset HEAD -- 文件名 #(若是沒有寫文件名就是所有恢復)
複製代碼

暫存區工做區都恢復爲和HEAD(最新的commit)的內容同樣

$ git reset --hard HEAD 或 git reset --hard HEAD -- 文件名 #(若是沒有寫文件名就是所有恢復)
複製代碼

這裏補充說明下 --hard表明的是工做區

工做區的文件恢復爲和暫存區的同樣

有些時候作了一些變動,咱們已經把這部分的代碼放到了暫存區,而後咱們又繼續在工做區作了一些變動,作完以後,思前想後,發現工做區的變動還不如暫存區的好,因此咱們就但願把工做區的內容扔掉,變成和暫存區的如出一轍。

$ git checkout . #丟掉工做區所有的變動
$ git checkout -- 文件名 #丟棄這個文件的變動
複製代碼

這條命令也要慎用!一旦誤操做,工做區最新的代碼也就丟失啦!

stash

有時候咱們正在寫代碼,忽然加派緊急任務,要修改其餘地方的bug,但咱們又不想提交正在修改的,因此咱們就須要是使用一個命令把當前的狀態臨時保存起來

$ git stash #存儲
$ git stash list #查看存儲好的stash
複製代碼

存儲好以後咱們會發現工做區變成了乾淨的了。 那麼假設咱們的bug已經修改好了,咱們想回到剛剛存儲前的狀態繼續作以前咱們作的事情,該怎麼辦?

$ git stash apply #把stash裏面的東西取出來放到工做區,且他不會刪除stash裏的記錄
$ git stash pop #把stash裏面的東西取出來放到工做區,但他會刪除stash裏的記錄
複製代碼

以上兩個命令隨便挑選一個使用均可以恢復,看狀況而定

.gitignore

咱們只須要在項目中新建一個名字爲:.gitignore的文件 咱們能夠在.gitignore裏配置本身想exclude(排除)的文件或文件夾。

遠程相關

這裏默認你們都會創建遠程倉庫,還不會的童鞋能夠先去學習學習!

git push origin 分支名把本地的某個分支推送到遠程倉庫

git push origin -d 分支名 # 用 -d 參數把遠程倉庫的分支也刪了

假如是某個你本身獨立開發的branch 出錯了,出錯的內容已經合併到 master 同事的工做都在 master 上,你永遠不知道你的一次強制 push 會不會洗掉同事剛發上去的新提交。因此除非你是人員數量和行爲都徹底可控的超小團隊,能夠和同事作到無死角的完美溝通,否則必定別在 master 上強制 push

在這種時候,你只能退一步,選用另外一種策略:增長一個新的提交,把以前提交的內容抹掉。例如以前你增長了一行代碼,你但願撤銷它,那麼你就作一個刪掉這行代碼的提交;若是你刪掉了一行代碼,你但願撤銷它,那麼你就作一個把這行代碼還原回來的提交。這種事作起來也不算麻煩,由於 Git 有一個對應的指令:revert

它的用法很簡單,你但願撤銷哪一個 commit,就把它填在後面:

$ git revert HEAD^
複製代碼

上面這行代碼就會增長一條新的 commit,它的內容和倒數第二個 commit 是相反的,從而和倒數第二個 commit 相互抵消,達到撤銷的效果。

revert完成以後,把新的 commitpush 上去,這個 commit 的內容就被撤銷了。它和前面所介紹的撤銷方式相比,最主要的區別是,此次改動只是被「反轉」了,並無在歷史中消失掉,你的歷史中會存在兩條 commit :一個原始 commit ,一個對它的反轉 commit

2019年10月29日補充:

git在本地建立一個項目的過程

// git init
// git add .
// git commit -m 'first commit'
// git remote add origin git@github.xx/xxx.git
// git push -u origin master
複製代碼
#git設置關閉自動換行
git config --global core.autocrlf false git config --global core.safecrlf true
複製代碼

#編輯Git配置文件

git config -e [--global]
複製代碼

#設置提交代碼時的用戶信息

git config [--global] user.name "[name]" git config [--global] user.email "[email address]"
複製代碼

#從遠端獲取分支

git fetch origin
複製代碼

#更新遠程分支列表

git remote update origin --prune
複製代碼

#基於遠程分支建立本地分支

git checkout -b newBrach origin/master 在origin/master的基礎上,建立一個新分支
複製代碼

#master

master 爲主分支,也是用於部署生產環境的分支,確保master分支穩定性 master 分支通常由develop以及hotfix分支合併,任什麼時候間都不能直接修改代碼
複製代碼

#develop

develop 爲開發分支,始終保持最新完成以及bug修復後的代碼 通常開發的新功能時,feature分支都是基於develop分支下建立的
複製代碼

#feature

開發新功能時,以develop爲基礎建立feature分支 feature/xx 開頭的爲特性分支, 命名規則: feature/login_module、 feature/user_module
複製代碼

#release

release 爲預上線分支,發佈提測階段,會release分支代碼爲基準提測

// 當有一組feature開發完成,首先會合併到develop分支,進入提測時,會建立release分支。
// 若是測試過程當中若存在bug須要修復,則直接由開發者在release分支修復並提交。
// 當測試完成以後,合併release分支到master和develop分支,此時master爲最新代碼,用做上線。
複製代碼

#hotfix

分支命名: hotfix/ 開頭的爲修復分支,它的命名規則與 feature 分支相似 線上出現緊急問題時,須要及時修復,以master分支爲基線,建立hotfix分支,修復完成後,須要合併到master分支和develop分支
複製代碼

#增長新功能

// (dev)$: git checkout -b feature/xxx            # 從dev創建特性分支
// (feature/xxx)$: git add xxx
// (feature/xxx)$: git commit -m 'commit comment'
// (dev)$: git merge feature/xxx --no-ff          # 把特性分支合併到dev
複製代碼

#修復緊急bug

// (master)$: git checkout -b hotfix/xxx         # 從master創建hotfix分支
// (hotfix/xxx)$: blabla                         # 開發
// (hotfix/xxx)$: git add xxx
// (hotfix/xxx)$: git commit -m 'commit comment'
// (master)$: git merge hotfix/xxx --no-ff       # hotfix => master,並上線到生產環境
// (dev)$: git merge hotfix/xxx --no-ff          # hotfix => dev,同步代碼
複製代碼

#測試環境

// (release)$: git merge dev --no-ff   dev => release
複製代碼

#生產環境

// (master)$: git merge release --no-ff  release => master
// (master)$: git tag -a v0.1.0 -m '部署包版本名'
複製代碼

--no-ff 會讓 Git 生成一個新的提交對象。爲何要這樣?一般咱們把 master 做爲主分支,上面存放的都是比較穩定的代碼,提交頻率也很低,而 feature 是用來開發特性的,上面會存在許多零碎的提交,快進式合併會把 feature 的提交歷史混入到 master 中,攪亂 master 的提交歷史。

總結

git經常使用的也就這麼多,你們只要經常使用,記住它們不是啥大問題,你們加油!

聲明:

本文全部文字純手打,遠程相關中的revert命令參考了掘金小冊扔物線大佬創做的小冊,其他部分都是原創!碼字不易,舉起小手點個贊,你的贊就是做者最大的寫做動力

文中若是出現錯誤,請你們在評論區指正,我會及時修改!

相關文章
相關標籤/搜索