從只會git add .的菜鳥到掌握git基本功能

前言

最近想把代碼傳到GitHub上,結果我發現的demo的npm全是本地安裝,上穿到GitHub要死要死,幾百M,而後我就搜了下怎麼不上傳node_modules弄了半天也沒成功,因而準備靜下心學一下git,也當一個筆記往後好翻閱.
研究前個人只會5個命令html

$ git init 
$ git add .
$ git commit -m "提交的xxxxx"
$ git pull
$ git push
複製代碼

Git是什麼

Git是一個開源的分佈式版本控制系統,用於敏捷高效地處理任何或小或大的項目。 Git 是 Linus Torvalds 爲了幫助管理 Linux 內核開發而開發的一個開放源碼的版本控制軟件。 Git 與經常使用的版本控制工具 CVS, Subversion 等不一樣,它採用了分佈式版本庫的方式,沒必要服務器端軟件支持。node

Git的工做流程

  1. 克隆 Git 資源做爲工做目錄。
  2. 在克隆的資源上添加或修改文件。
  3. 若是其餘人修改了,你能夠更新資源。
  4. 在提交前查看修改。
  5. 提交修改。
  6. 在修改完成後,若是發現錯誤,能夠撤回提交併再次修改並提交。

基本概念

本地倉庫(版本庫)

版本庫:工做區有一個隱藏目錄.git,這個不算工做區,而是Git的版本庫。webpack

本地倉庫(版本庫)是什麼

什麼是版本庫呢?版本庫又名倉庫,英文名repository,你能夠簡單理解成一個目錄,這個目錄裏面的全部文件均可以被Git管理起來,每一個文件的修改、刪除,Git都能跟蹤,以便任什麼時候刻均可以追蹤歷史,或者在未來某個時刻能夠「還原」。git

暫存區

暫存區:英文叫stage, 或index。通常存放在 ".git目錄下" 下的index文件(.git/index)中,因此咱們把暫存區有時也叫做索引(index)。github

工做區

工做區:就是你在電腦裏能看到的目錄。web

Git的基本使用

我就不詳細介紹了,估計你們都會,就是上面辣個圖,圖上幾個命令npm

$ git init,              //初始化本地倉庫 .git
$ git status -sb,        //顯示當前全部文件的狀態
$ git diff                //查看更改,查看difference,顯示的格式正是Unix通用的diff格式,
$ git add 文件路徑        //用來將變更加到暫存區
$ git commit -m "信息"    //用來正式提交變更,提交至 .git 倉庫若是有新的變更,咱們只須要依次執行 git add xxx 和 git commit -m 'xxx' 兩個命令便可
$ git log                 //查看變動歷史
複製代碼

版本回退

當我提交了幾個commit,假設咱們如今有3個版本(1,2,3),如今是版本3,發現剛剛的提交錯誤了,想撤回回到版本2安全

$ git reset --hard               //重置暫存區與工做區,與上一次commit保持一致
複製代碼

而後你由發現剛剛的提交是正確的,又想回到版本3,再輸入下面這個命令,至關於你那個回退沒有作bash

$ git reset --hard [commitid]     //重置當前分支的HEAD爲指定commit,同時重置暫存區和工做區,與指定commit一致
//commitid 使用git log --stat查看
複製代碼

平行世界B
在平時世界B的你,剛剛把版本回退到了版本2,因而睡覺去了,次日,發現版本3纔是對的,但是使用git log已經查看不到commit信息了,怎麼辦?服務器

$ git reflog                      //用來記錄你的每一次命令,顯示當前分支的最近幾回提交
複製代碼

場景1:當你改亂了工做區某個文件的內容,想直接丟棄工做區的修改時,用命令
$ git checkout -- file

場景2:當你不但改亂了工做區某個文件的內容,還添加到了暫存區時,想丟棄修改,分兩步,第一步用命令
$ git reset HEAD file
,就回到了場景1,第二步按場景1操做。

場景3:已經提交了不合適的修改到版本庫時,想要撤銷本次提交,git reset --hard,不過前提是沒有推送到遠程倉庫。

刪除文件

$ git rm [file1] [file2] ...      //刪除工做區文件,而且將此次刪除放入暫存區
複製代碼

另外一種狀況是刪錯了,由於版本庫裏還有呢,因此能夠很輕鬆地把誤刪的文件恢復到最新版本:

$ git checkout -- test.txt
複製代碼

分支(branch)

  • 分支在實際中有什麼用呢?假設你準備開發一個新功能,可是須要兩週才能完成,第一週你寫了50%的代碼,若是馬上提交,因爲代碼還沒寫完,不完整的代碼庫會致使別人不能幹活了。若是等代碼所有寫完再一次提交,又存在丟失天天進度的巨大風險。

  • 如今有了分支,就不用怕了。你建立了一個屬於你本身的分支,別人看不到,還繼續在原來的分支上正常工做,而你在本身的分支上幹活,想提交就提交,直到開發完畢後,再一次性合併到原來的分支上,這樣,既安全,又不影響別人工做。

  • 你已經知道,每次提交,Git都把它們串成一條時間線,這條時間線就是一個分支。截止到目前,只有一條時間線,在Git裏,這個分支叫主分支,即master分支。HEAD嚴格來講不是指向提交,而是指向master,master纔是指向提交的,因此,HEAD指向的就是當前分支。

  1. 當咱們建立新的分支,例如dev時,Git新建了一個指針叫dev,指向master相同的提交,再把HEAD指向dev,就表示當前分支在dev上:
  2. 你看,Git建立一個分支很快,由於除了增長一個dev指針,改改HEAD的指向,工做區的文件都沒有任何變化!

不過,從如今開始,對工做區的修改和提交就是針對dev分支了,好比新提交一次後,dev指針往前移動一步,而master指針不變:

3. 假如咱們在dev上的工做完成了,就能夠把dev合併到master上。Git怎麼合併呢?最簡單的方法,就是直接把master指向dev的當前提交,就完成了合併:
4. 合併完分支後,甚至能夠刪除dev分支。刪除dev分支就是把dev指針給刪掉,刪掉後,咱們就剩下了一條master分支:

如何使用分支

$ git checkout -b [branch]                //新建一個分支,並切換到該分支
$ git branch                              //命令會列出全部分支,當前分支前面會標一個*號。
$ git add . 
$ git commit -m "提交分支branch"
$ git checkout master                     //切換回master分支
$ git merge [branch]                      //把branch分支合併到master分支
$ git branch -d branch                     //合併完成後刪除branch分支

複製代碼
查看分支:git branch

建立分支:git branch <name>

切換分支:git checkout <name>

建立+切換分支:git checkout -b <name>

合併某分支到當前分支:git merge <name>

刪除分支:git branch -d <name>
複製代碼

分支衝突

好比如今咱們的文件是這樣的

fuck 'webpack'                      //master分支
複製代碼

咱們建立而且切換到parcel分支

$ git checkout -b parcel     
複製代碼

修改文本內容

fuck 'webpack ---> parcel no.1
提交到暫存區

$ git add .
$ git commit "嘻嘻"                      //parcel分支
複製代碼

切回master分支

$ git checkout master
複製代碼

修改文本內容

fuck 'webpack' --> fuck fuck 'webpack'
提交到暫存區

$ git add .
$ git commit "哈哈"                      //maser分支
複製代碼

這樣咱們的兩個分支內容不同,有了衝突,咱們提交試一下

$ git merge parcel                      //把parcel分支合併到當前master分支
複製代碼

而後就衝突了

$ git status                        //能夠告訴咱們衝突的文件:
# On branch master
# Your branch is ahead of 'origin/master' by 2 commits.
#
# Unmerged paths:
# (use "git add/rm <file>..." as appropriate to mark resolution)
#
# both modified: fuck.txt
#
複製代碼

咱們得手動修改當前master分支的內容與parcel分支內容相同

fuck fuck 'webpack' --> parcel no.1
再次提交

$ git add .
$ git commit "撲撲"                      //maser分支
複製代碼

最後,刪除parcel分支

git branch -d parcel
複製代碼

分支管理策略

一般,合併分支時,若是可能,Git會用Fast forward模式(默認模式),但這種模式下,刪除分支後,會丟掉分支信息。

若是要強制禁用Fast forward模式,Git就會在合併分支時生成一個新的commit,這樣,從分支歷史上就能夠看出分支信息。

列如

$ git checkout -b dev                                 //首先,仍然建立並切換dev分支:
$ git add readme.txt                                  //修改readme.txt文件,並提交一個新的commit
$ git checkout master                                 //如今,咱們切換回master分支
$ git merge --no-ff -m "merge with no-ff" dev         //準備合併dev分支,請注意--no-ff參數,表示禁用Fast forward
$ git log --graph --pretty=oneline --abbrev-commit    //合併後,咱們用git log看看分支歷史:
//合併分支時,加上--no-ff參數就能夠用普通模式合併,合併後的歷史有分支,能看出來曾經作過合併,而fast forward合併就看不出來曾經作過合併。
複製代碼

團隊分支管理

在實際開發中,咱們應該按照幾個基本原則進行分支管理:

首先,master分支應該是很是穩定的,也就是僅用來發布新版本,平時不能在上面幹活;

那在哪幹活呢?幹活都在dev分支上,也就是說,dev分支是不穩定的,到某個時候,好比1.0版本發佈時,再把dev分支合併到master上,在master分支發佈1.0版本;

你和你的小夥伴們每一個人都在dev分支上幹活,每一個人都有本身的分支,時不時地往dev分支上合併就能夠了。

因此,團隊合做的分支看起來就像這樣:

團隊分支應該真是這樣

|- master                       //正式版
  |- dev                        //測試版
    |- michael                  //隊員michael-adc
    |- bob                      //隊員bob-肉
    |- bibi                     //隊員bibi-大腿
複製代碼

Bug分支

軟件開發中,bug就像屢見不鮮同樣。有了bug就須要修復,在Git中,因爲分支是如此的強大,因此,每一個bug均可以經過一個新的臨時分支來修復,修復後,合併分支,而後將臨時分支刪除。

當你接到一個修復一個代號101的bug的任務時,很天然地,你想建立一個分支issue-101來修復它,可是,等等,當前正在dev上進行的工做尚未提交

------------                                              //咱們在dev分支上,發現master分支上有代號101號bug
$ git stash                                               //冷凍如今在dev分支上的工做狀態 凍結吧!  
$ git checkout master                                     //這個bug發生在master主分支上,咱們切回master分支
$ git checkout -b issue-101                               //建立代號101的修復bug分支
修改你的bug
$ git add readme.txt                                      //提交到暫存區
$ git commit -m "fix bug 101"                             //注意填寫信息,以避免往後查證
$ git checkout master                                     //切換回master分支
$ git merge --no-ff -m "merged bug fix 101" issue-101     //合併分支,注意不使用fast forward模式
$ git branch -d issue-101                                 //刪除issue-101分支
$ git checkout dev                                        //bug 改完了,是時候回到dev繼續寫bug了
$ git stash list                                          //查看剛剛的凍結現場
$ git stash pop                                           //git stash pop,恢復的同時把stash內容也刪了:
//一是用git stash apply恢復,可是恢復後,stash內容並不刪除,你須要用git stash drop來刪除
複製代碼

開發一個新測試功能

開發一個新feature,最好新建一個分支;

若是要丟棄一個沒有被合併過的分支,能夠經過git branch -D <name>強行刪除。

多人協做

當你從遠程倉庫克隆時,實際上Git自動把本地的master分支和遠程的master分支對應起來了,而且,遠程倉庫的默認名稱是origin。 要查看遠程庫的信息,用git remote -v

推送分支

推送分支,就是把該分支上的全部本地提交推送到遠程庫。推送時,要指定本地分支,這樣,Git就會把該分支推送到遠程庫對應的遠程分支上:

$ git push origin master
複製代碼

若是要推送其餘分支,好比dev,就改爲:

$ git push origin dev
複製代碼

可是,並非必定要把本地分支往遠程推送,那麼,哪些分支須要推送,哪些不須要呢?

  • master分支是主分支,所以要時刻與遠程同步;

  • dev分支是開發分支,團隊全部成員都須要在上面工做,因此也須要與遠程同步;

  • bug分支只用於在本地修復bug,就不必推到遠程了,除非老闆要看看你每週到底修復了幾個bug;

  • feature分支是否推到遠程,取決於你是否和你的小夥伴合做在上面開發。

多人協做時,你們都會往master和dev分支上推送各自的修改。  
當你的小夥伴從遠程庫clone時,默認狀況下,你的小夥伴只能看到本地的master分支。  
如今,你的小夥伴要在dev分支上開發,就必須建立遠程origin的dev分支到本地,因而他用這個命令建立本地dev分支:
$ git checkout -b dev origin/dev
你的小夥伴已經向origin/dev分支推送了他的提交,而碰巧你也對一樣的文件做了修改,並試圖推送
推送失敗,由於你的小夥伴的最新提交和你試圖推送的提交有衝突,解決辦法也很簡單,Git已經提示咱們,先用git pull把最新的提交從origin/dev抓下來,而後,在本地合併,解決衝突,再推送:
git pull也失敗了,緣由是沒有指定本地dev分支與遠程origin/dev分支的連接,根據提示,設置dev和origin/dev的連接:
$ git branch --set-upstream dev origin/dev
再pull
這回git pull成功,可是合併有衝突,須要手動解決,解決的方法和分支管理中的解決衝突徹底同樣。解決後,提交,再push:
複製代碼

所以,多人協做的工做模式一般是這樣:

首先,能夠試圖用git push origin branch-name推送本身的修改;

若是推送失敗,則由於遠程分支比你的本地更新,須要先用git pull試圖合併;

若是合併有衝突,則解決衝突,並在本地提交;

沒有衝突或者解決掉衝突後,再用git push origin branch-name推送就能成功!

若是git pull提示「no tracking information」,則說明本地分支和遠程分支的連接關係沒有建立,用命令
git branch --set-upstream branch-name origin/branch-name

這就是多人協做的工做模式,一旦熟悉了,就很是簡單。


查看遠程庫信息,使用git remote -v

本地新建的分支若是不推送到遠程,對其餘人就是不可見的;

從本地推送分支,使用git push origin branch-name,若是推送失敗,先用git pull抓取遠程的新提交;

在本地建立和遠程分支對應的分支,使用git checkout -b branch-name origin/branch-name,本地和遠程分支的名稱最好一致;

創建本地分支和遠程分支的關聯,使用git branch --set-upstream branch-name origin/branch-name

從遠程抓取分支,使用git pull,若是有衝突,要先處理衝突。

標籤管理

建立標籤

  • 命令git tag <name>用於新建一個標籤,默認爲HEAD,也能夠指定一個commit id;

  • git tag -a <tagname> -m "blablabla..."能夠指定標籤信息;

  • git tag -s <tagname> -m "blablabla..."能夠用PGP簽名標籤;

  • 命令git tag能夠查看全部標籤。

  • 還能夠建立帶有說明的標籤,用-a指定標籤名,-m指定說明文字:

$ git tag -a v0.1 -m "version 0.1 released" 3628164
複製代碼

操做標籤

若是標籤打錯了,也能夠刪除:

$ git tag -d v0.1
複製代碼

若是要推送某個標籤到遠程,使用命令

$ git push origin <tagname>
複製代碼

或者,一次性推送所有還沒有推送到遠程的本地標籤:

$ git push origin --tags
複製代碼

若是標籤已經推送到遠程,要刪除遠程標籤就麻煩一點,先從本地刪除:

$ git tag -d v0.9
複製代碼

而後,從遠程刪除。刪除命令也是push,可是格式以下:

git push origin :refs/tags/<tagname>
複製代碼

忽略特殊文件

在Git工做區的根目錄下建立一個特殊的.gitignore文件,而後把要忽略的文件名填進去,Git就會自動忽略這些文件。 不須要從頭寫.gitignore文件,GitHub已經爲咱們準備了各類配置文件,只須要組合一下就可使用了。全部配置文件能夠直接在線瀏覽:.gitignore

聲明

本片文章基本參考廖雪峯老師的git教程來,加入了一點個人我的理解,以及配圖等
若是你想深刻了解git能夠查看下面這幾個連接

經常使用git命令清單-阮一峯
讀懂diff-阮一峯
git教程-廖雪峯
git教程-菜鳥教程
gitbook
Git Community Book

相關文章
相關標籤/搜索