git 學習(1) ----- git 本地倉庫操做

  最近在項目中使用git了,在實戰中才知道,之前學習的git 知識只是皮毛,須要從新系統的學一下,讀了一本叫  Learn Git in a Month of Lunches 的書籍,這本書通俗易懂,使我對git 有了全面的認識。css

  在平時,咱們經常聽到git 和github,它倆老是一塊兒出現,總有一種必須一塊兒使用的感受。實際上,git和 github 是兩個不一樣的概念, git是一個版本管理工具,而github則是一個網站,主要用於保存代碼,分享代碼。它們 之間沒有必然的聯繫,可使用其中的任意一個。若是咱們只在本身電腦上開發項目,不用共享,只使用git進行版本管理就能夠了,沒有必要使用github. 若是咱們想要分享項目,也能夠只使用github, 在github上網站,咱們能夠直接把源代碼拖動到網站,就像qq 郵箱拖動文件同樣。固然說它們一點聯繫都沒有,也不可能。git 和github 組合使用,一般用於大型的多人協做的項目。好比react, vue 等項目,多人協做,就要把代碼放到一個你們都能找到的地方(gitHub)上,每一個人在進行開發的時候,就要進行版本管理,和github 進行通訊,那就要用到git命令。咱們先學習git。html

  git是一個版本管理工具,那什麼是版本?版本爲何要進行管理?版本,我想你們都據說過,webpack有1,2,3,4 四個大版本。爲何會有這麼多的版本?由於每個版本就是一個變化,bug 修復,增長功能啊。如webpack2, 直接支持import,進行treeshaking, webpack4 提供了零配置的功能。這麼多版本確定要進行管理。這可能有點抽象,想想咱們日常的業務開發也是同樣。咱們寫了一段代碼,實現了一個功能, 但有時以爲代碼實現方式不太好,就進行重寫,可是引入了bug, 就想從新回到原來的代碼?但因爲變更太大,代碼回不去了, 這時就想,要是把之前的代碼保存一份該多好。修改代碼以前保存一下,若是修改失敗,能夠進行回退。每一次的代碼修改都是一次變化,git 就是用來幫咱們管理這些變化的vue

  在windows上使用git, 相對比較麻煩,要先安裝git, 百度一下git for window,或直接輸入網址 https://gitforwindows.org/react

  點擊Download, 下載下來是一個.exe文件。雙擊進行安裝。安裝則比較簡單,就是一路next. 安裝完成後,桌面上一般會有一個git快捷方式, 同時點擊鼠標右鍵,也會有git bash 和git GUI 命令。webpack

  右鍵點擊git bash 或雙擊快捷方式,就能夠打開git bash的窗口,使用git 命令。git

   Git 是管理變化的,最基本的就是要告訴git 是誰作出了這個改變, 因此在使用git 以前要先配置user.name, user.email,就是用戶名和郵箱github

    git config --globle user.name 「sam」  web

    git config --globle user.email 「105778@qq.com」vim

  配置以後,能夠看看有沒有配置成功. 使用git config user.name, git config user.email  能夠看到你剛纔配置的信息。其實還有一個git config --list 命令,能夠看到全部的git 配置,配置成功後,就能夠學習git 了。 咱們新建一個項目,就是文件夾,好比, git-learning來學習git.windows

  進入到git-learning 文件夾中,單擊右鍵,出現的菜單中有一個git Bash Here,單擊它,就會出現git bash 窗口。

  如今要輸入的第一個命令就是git init, 它會在咱們的文件夾中建立一個git 倉庫, 此後git就能夠追蹤整個文件夾的變化,幫助咱們管理整個項目了。輸入git init ,按回車鍵,

  提示初始化了一個空的git 倉庫,也就是建立git 倉庫成功。但你會發現文件夾中什麼也沒有發生,仍是空空如也,哪有建立git 倉庫? 這主要是由於,它建立的git 倉庫是一個.git 文件夾,window 默認不顯示點開頭的文件夾。Win10下,在文件夾上面有一個「查看」標籤,點擊,從右側數,倒數第二個面板(顯示/隱藏)中有一個 「隱藏的項目」複選框,勾選便可,這時看到.git 文件夾。.git文件夾就是git版本庫,整個文件夾中全部的變化都放到它這裏。因此這個文件夾相當重要,千萬不要動它,此時,咱們的git-learning 文件夾也稱之爲工做區,就是咱們工做的地方,能夠增長,刪除文件。

  

  如今git 倉庫建立成功,咱們終於能夠看看git 是怎麼追蹤變化的。在git learning 文件夾中建立一個index.html 文件,能夠用touch index.html命令。查看變化的一個命令是git status, 使用git status 能夠看到工做區發生了哪些變化

 

  能夠看到Untracked files: index.html, index.html 沒有被追蹤, 也就是說git 已經檢測到工做區新增了一個文件index.html. 怎麼才能被git 追蹤? 它提到了一個命令git add, 咱們來使用一下這個命令, 它後面參數就是咱們要add的文件名,在這裏是index.html   git add index.html, 能夠發現什麼都沒有發生,這時咱們再查看一下狀態:

  Changes to be commited, 這個變化能夠被提交,指的就是index.html這個文件能夠被提交(說明 git add 命令執行成功)。這裏要使用的命令是git commit, 注意這個命令有一個參數-m 表示要添加的註釋,提交一個變化,要說明其緣由,爲何要提交,要否則提交它作什麼。git commit -m '', 引號裏面就是註釋

  能夠看到提交成功,再來查看一個狀態 git status

  沒有什麼要提交的了,工做樹是乾淨了。

  如今來簡單回顧一下咱們的操做,先建立一個index.html文件,而後git add 命令,讓git 去追蹤,最後git commit 提交變化,用git status 能夠隨時查看狀態。你可能會有疑問,git add 把文件添加到什麼地方了,git commit 提交,又把文件提交到什麼地方了。這其實涉及到了git 的三個區:工做區, 暫存區, 版本區(git 倉庫)。咱們在工做區建立了一個index.html文件,而後調用 git add 命令, git add 命令就是把文件增長到暫存區,而後git commit , git commit 就是把文件提交到git 倉庫。

  在工做區和版本區中加了一層暫存區,做爲過渡, 顯得更爲靈活. 好比咱們開發一個功能,不可能一次完成, 須要屢次修改才能完成. 這時咱們不可能把未完成的代碼,直接提交到版本庫,但有了暫存區以後,咱們能夠提交到暫存區,暫存區一樣能夠保存咱們的代碼,暫存區又沒有提交到工做區,它不會影響到成熟的版本區. 這樣就同時保護了工做區和版本區。

  咱們把變化(改變的文件)提交到git倉庫,git 就會把當前的變化保存起來,造成一個快照。git commit 就是告訴git 倉庫 把當前狀態保存一下。每提交一次,它就會保存一次,造成一條一條的歷史快照,這樣咱們就能夠版原本回切換。查看提交記錄是用git log 命令。

  這裏還有一個git ls-files 命令,能夠查看版本庫的內容。

  這時也能夠看到git 倉庫中有了index.html ,也表示咱們提交成功了。

  如今咱們再對index.html 進行修改,看看git 又是怎麼追蹤變化的文件的? 用編輯打開index.html, 輸入html 模版。而後再用git status 查看狀態

  Changes not staged for commit, stage就是緩存,變化沒有提交到緩存區。他提供了後續的兩個動做,一個是git add 提交到緩存區,一個是git checkout -- 放棄更改。固然,咱們這裏仍是使用git.add 提交到緩存區。不過,在提交到緩存區以前,咱們最好要看一下文件作了哪些改變,是否是咱們想要作出的改變,這裏的命令是git diff 

  能夠看到git diff 把全部的更改都顯示出來了。difff --git a/index.html  b/index.html  以 git 的方式顯示兩個文件a/index.html 和b/index.html 的不一樣。--- a/index.html --- 表示變更以前的文件。+++ b/index.html , +++表示變更以後文件。 @@ -0,0  +1, 14 @@,對變化的位置作了標識,以@@ 開頭和@@ 結束的內容表示的就是變化的位置, 它會爲兩個部分-0,0 和+1,14.  -表示的是變更以前的文件,0表示變更前的第0 行,後面的0 表示連續0行,鏈接起來讀就是變更以前的文件,從第0行,連續0行有變化,那就是什麼都沒有。

+表示變更後的文件,1表示變更後文件的第一行,14 表示連續14行, 變更後的文件從1行開始,連續14 行有變化。具體的主化內容,則是在它下面是顯示。你能夠看到第一行的開始都有一個加號+, 它表示變化後文件新增的行,有時還會有一個減號,表示變化前的文件中刪除的行。有時什麼都沒有,表示的是沒有變化。

  這時會有一個疑問,變更前的文件指的是哪個文件?它指的是暫存區的文件,也就是git diff 比較的是工做區和暫存區的文件的不一樣。如今把變更提效到暫存區,git add index.html, 再調用git diff 命令,能夠發現什麼都沒有輸出。由於提交以後,工做區和暫存區一致了,沒有什麼不一樣,這也證實了,它只是對比的工做區和暫存區文件的不一樣。

  若是咱們想對比 暫存區內的文件和版本區內的文件的不一樣,那要用 git diff  --staged。git diff --staged 看一下

  git diff master  對比工做區內的文件和版本區內的文件的不一樣, git commit -m "修改index.html" 提交版本區,本身試一下就能夠了,這裏就不寫了。

  這裏,只是對單個文件進行了修改,若是咱們對多個文件進行了修改,git diff 會把全部修改的文件都顯示出來,咱們只想看到一個文件的變化,能夠指它指定一個文件名,git diff 文件名,好比git diff text.txt ,只看到text.txt文件的變化內容。

  咱們看到了變化後的內容,如是咱們想要作的改變,那就要先git add 提交到暫存區,再git commit 提交到版本區。這裏有一個快捷的命令,能夠直接提交到版本區。 git commit -a -m "註釋", -a 就是add 的簡寫。這個簡寫命令只對文件更改有效,由於更改的文件已經在 git 版本中被追蹤了。若是是新建 一個文件,它沒有被追蹤,這個簡寫命令無效。

git commit -a -m "修改index.html"  能夠看到直接提交到倉庫了。

  如今咱們能夠添加並修改一個文件了,那多個文件呢?實際上是同樣的,不過有幾個簡捷的命令。如今咱們添加新的文件,用touch index.js .style.css reset.css, 這時能夠調用git status 來查看狀態,不過,我想你已經知道結果了,那就是這三個文件,git沒有追蹤,而且你也知道下一步作什麼,就是調用git add 命令添加到暫存區。可是按照之前,三個文件就要寫三次git add  命令,git add index.js git add style.css , git add reset.css ,有點麻煩了。不過git 也想到了這個問題,因此git add 命令接受的參數還能夠是文件夾名,咱們調用git add . 試一試,. 表示的就中當前文件夾,連文件夾名都省略掉了,真是很人性化,它把當前文件夾中的文件全都上傳到暫存區

 最後git commit 一下,提交到git 倉庫。

 

 git 刪除文件的操做

  1,若是咱們想刪除掉git 倉庫中的文件,該怎麼作呢?先刪除掉本地(工做區)的文件, 而後再把變更提交到git 倉庫。刪除命令能夠用rm, rm style.css 就能夠刪除掉style.css 文件。刪除文件,它也是一個變更,因此還要git add 提交到暫存區,git commit 提交到git 倉庫。git add 操做實際上是把暫存區的文件刪除了,git commit 把git 倉庫中的文件刪除了。操做一下,操做有沒有問題。

  沒有問題,git ls-files 命令,就是把倉庫中的文件顯示出來,能夠看到確實是刪除了style.css文件。咱們在工做區刪除文件,而後再在暫存區刪除文件,感受操做有點不人性化。咱們在工做區刪除,你直接把暫存區的文件刪除就能夠了。git 也考慮到這個問題,提供了一個git rm 命令,它把工做區和暫存區的文件一塊兒刪除,調用git rm 進入到暫存區階段,只要commit 一下就能夠把文件從倉庫中刪除了。

  git 重命名文件的操做。

  對於文件的重命名操做,可能有點不太好理解。在圖形界面操做時,選中一個文件,而後右鍵重命名,輸入新的文件名,操做的都是同一個文件。但對於命令行操做來講,它確不是這樣的。對於命令行來講,重命名意味着,新建一個文件,而後把舊文件中內容都拷貝到新文件中,而後再把舊文件刪除,因此它用的是mv 命令,就是 move,移動,把一個文件移動到另外一個文件。mv index.js main.js 就是把index.js 改成main.js, 這時調用git status  看一下結果

  git status 告訴咱們,刪除了index.js文件,而後新建了一個main.js文件,這時 調用git add 和 git commit 提交到倉庫。和刪除 同樣,git 也提供了git mv 命令,一步到暫存區。

咱們把main.js 改回index.js  mv main.js index.js, 而後調git mv index.js main.js

  確實是到了暫存區,咱們能夠提交了,

 

  如今咱們對main.js 進行修改,好比聲明變量,輸出值。

// 聲明變量
let a = 5;
let b = 10;

// 輸出值
console.log(a + b);

  而後再git add. 提交到暫存區. 可是發現,這些修改沒有必要,須要從暫存區內撤銷回來。git reset HEAD 文件名 命令就能夠了。git reset HEAD main.js 撤回到工做區,暫存區中的保存的變化取消。

  unstaged changes 也說明撤銷成功了。如今咱們能夠把main.js 中的內容所有刪除,從新寫,其實這裏也可使用另一個命令,由於全部變更都在暫存區和工做區進行,版本區(倉庫)中沒有作任何改變,咱們直接回到版本區中狀態,就至關於把全部變更刪除。git checkout -- 文件名,撤回到版本區的狀態。git checkout -- main.js 

  能夠看到main.js 變成了空文件,回退成功。

  再論git log, 實現版本回退

  當咱們git commit 的時候,git 會造成一個歷史快照,使用git log 能夠查看。git log 還提供了一系列的參數來實現不一樣維度的輸出。

  git log --oneline 以一行方式輸出,更爲簡捷,能夠看到咱們提交了多少次的記錄。

  git log --patch, 以git diff 對比變化的方式,輸出提交記錄。

  你發現只輸出了兩個完整的commit, 而且最下面還有一個:位置的光標在閃爍,這表示等待你繼續輸入命令,由於在git 輸出時,它默認輸出窗口的大小的內容,因此對於這種log的輸出,它確定不少,一個窗口的大小確定輸出不完。這時按空格鍵,能夠發現,它 又輸出了內容, 一直按空格,直到所有輸出完爲止,你能夠看到一個end: 光標在閃爍。

  代表輸出結束。此時按q(或Q)進行結束。

  git log --stat, 以文件變更的展現方式輸出提交記錄。

  仍是和上面同樣,你要按 空格或Q 進行繼續輸出或終止輸出。

  git log --patch-with-stat 對以上兩種方式進行了整合,能夠本身輸出看一看結果

  git log 參數 文件名,只輸出包含指定文件的提交記錄. git log --oneline index.html.  以oneline的方式輸出只包含 index.html 的提交記錄。

  除了使用命令行來查看提交記錄時,咱們也可使用圖形界面工具來查看,它顯得更爲直觀。直接在命令行中輸入gitk, 就能夠打開圖形界面工具

  在圖形界面的上半部分,就是提交記錄,下部分對應的每個提交記錄的變更。在上半部分的每一條提交記錄上進行點擊,下半部分就會相應變化,右鍘還有patch, tree 等選擇,本身可能多點點看一看,是很是直觀。當咱們手動關閉圖形界面工具後,命令行窗口又變成了可輸入狀態。

  版本回退:在學習版本回退以前,要了解是什麼能讓git進行版本回退,那就是指針。在程序開發的過程當中,咱們會進行一次次的提交,從而造成一個提交歷史。就像上面同樣,咱們有一個6條的提交歷史。每一次的提交都會有一個指針,指向上一次的提交,就像鏈表同樣,以下圖所示。

  這一系列的提交也造成了一個分支,你可能沒有注意,git init 在初始化git 倉庫的時候,已經建立了一個默認分支叫master,咱們這一次一次的提交都提交到了master 分支上。

   上圖中最後的master 就是指的master 分支,它表示,咱們一直在master分支上進行工做。同時master也是一個指針或引用,指向咱們分支的最後一次的提交,

  也就是說,分支名,它即指的是咱們開發過程當中的整條分支,同時也是一個指針,指向整條分支的最後一次提交。

  好了,剩下最後一個HEAD指針要學習了,HEAD指針也是指的當前分支,默認指向當前分支的最後一次提交。

  咱們可使用命令看一下,master 和HEAD 是否是指向最後一個提交,命令是git rev-parse master 和 git rev-parse HEAD

  能夠看到它們都指向了最後一次提交。不過,HEAD指針能夠移動,從而實現版本的前進或回退。你能夠把HEAD指針想像成聽歌或看視頻上的時候,進度條上的滑塊,經過拖動滑塊,咱們能夠快進或後退,從而實現想看哪裏就看哪裏。HEAD 指針也是如此,咱們能夠經過改變HEAD的位置,從而實現版本的回退或前進。經常使用的命令有3個 git reset, get checkout, git revert,  這三個命令接受的最基本的參數,就是commit ID.  咱們提交的時候,它都會生成惟一的一個id,如上圖中的 b695ce51ac10a45d995014c3546b4fe49c7a2f58

可是這三個命令的使用場景卻大不相同,須要根據不一樣的場景使用不一樣的命令。

  git reset: reset 是重置的意思,重置意味着從新來過,當咱們重置一個表單的時候,就是咱們剛剛添寫的內容所有捨棄掉,從新添寫。咱們用git log 查看一下commit id 

  如今想回退到刪除style 樣式文件, 那就用 git reset d3be0631e6c50dce17d00226dd270c7070b7ee86, 這個id 有點長,其實只要輸入前面的6-7位就能夠了,由於咱們使用git log  --oneline 的時候,commit id 就是6位。再說,若是git 找不到這個id, 它會告訴咱們找不到,因此也不用擔憂。

  輸出的結果有點奇怪,index.js reset.css 沒有添加到緩存區,可是咱們的文件夾或工做區並無發生變化,仍是隻有兩個文件index.html 和main.js,這是怎麼回事?其實當使用git reset 進行回退的時候,它默認改變的是暫存區,把暫存區的狀態回退到指定id 的版本區(或暫存區)的狀態,工做區不會發生變化。咱們gitk 看看指定的id的版本區都有哪些文件?

在命令行中輸入gitk,

  SHA1 ID 就是咱們要回退到的id, 右下邊能夠看到這個提交所對應的版本區(倉庫)的文件,有index.html, index.js reset.css三個文件,也就是說,當咱們執行git reset d3be06時,暫存區回退到這種狀態,有index.html, index.js reset.css文件。而後再和工做區進行比較,此時工做區只有index.html, main.js,因此對於git來講,至關於咱們在工做區刪除了index.js 和 reset.css 兩個文件,因此它纔會顯示 unstaged change: index.js reset.css, 兩個文件前面還有一個D,它就是Delete的意思,表示刪除,也是說刪除了兩個文件,沒有提交到暫存區。這時你可能想到了使用git diff 來查看一下暫存區和工做區的不一樣

  和咱們剛纔說的同樣,咱們刪除了index.js 和reset.css 沒有提交到暫存區,因爲工做區還有main.js, 因此顯示main.js 沒有被追蹤。這時若是想,回退版本的時候,直接把工做區也替換了,和暫存區狀態同樣。 這樣再給git reset 命令增長一個參數: --hard.  爲了完成這個操做,咱們要回到之前的版本,這時 git log 一下,咱們的提交記錄只剩下4條了,根本就沒有回去的commit ID, 

  至關於,d3be063 後面的兩個提交

  b695ce5, 53767b8 都沒有發生同樣,這就是git reset 重置的做用,也就是說, 若是咱們作的提交,咱們不想要了,要把它扔掉,那就是git reset. 現實的場景就是,在開發新功能的時候,忽然這個功能取消了,或者,開發了一段時間,代碼寫的太爛了,要重寫,這時就用git reset.  

   那咱們到底能不能從過去回到將來?那要使用git reflog,它會把全部的提交記錄顯示出來,找到對應的id, 而後git reset 這個id 就能夠了。如今再回到剛纔那個問題 ?若是git reset的時候,想要把工做區和緩存區都同步到指定版本的內容,使用git reset --hard d3be063,能夠看到這時工做區也回退到了指定版本的狀態。

   git checkout 也能夠接受一個commit id, 移動HEAD 指針。

 

  能夠看到工做目錄改變了,變成了指定的 commit id 的狀態。

 

   checkout 的結果就是 Head 指針和master 指針的分離,若是這時再進行提交,之前提交的歷史記錄也會消失,最好不作任何變更,提交記錄, 不過咱們能夠在這裏建立分支。它的主要場景就是快速查看舊版本。可使用git ckeck master 回到最新的版本。

  git revert: revert 是撤銷的意思,撤銷那一次的修改,從新修改提交。但咱們執行 git revert  a69243e 出現如下彈窗

 

  下面還有更多,滾動鼠標滾輪能夠看到,它有幾個選項,直接編輯(E), 退出Q 等,若是選擇直接編輯,進入一處輸入界面,這應該是一個vim 的界面,能夠輸入解釋信息,爲何要執行撤消操做,輸入完成後,按esc 鍵退出,而後再輸入:wq 退出編輯器。這時再看一下咱們的工做目錄,能夠看到它是回到了指定的狀態。這時git log 你會出現,它會當成一次新的提交,咱們原來的提交歷史沒有消失,這時一種安全的操做。

  可是,若是咱們只想回退到前一版本,在commit id 的方式就有點麻煩了,由於咱們先要git log 找到這個id; 這時git 提供了簡單的操做,用HEAD;  HEAD^ 表示上一個版本, HEAD^^ 表示回退到上兩個版本,當有幾個版本的時候,這種操做就不方便了,這時提供了 HEAD ~num 的模式,num 表示要回退到第幾個版本, HEAD ~5,表示回退到上5個版本。 git reset –hard HEAD^^, 或 git reset –hard HEAD ~2  也表示回退兩個版本。 git checkout 和git revert 也是一樣的用法。

  最後說一點,提交的修改。好比,原本是想一次提交三個文件(a.js, b.js c.js),但不知什麼狀況,只提交了一個文件(a.js) git commit -a -m "change js". 這時怎麼辦,又不想再對其它兩個文件做另一次提交,由於它們是一夥的。這時用到  git commit --amend 命令。首先,把另外兩個文件a.js, b.js  添加到暫存區,git add . , 而後 git commit -m "change three js " --amend. 成功之後,git log 能夠看到,a.js,b.js c.js 的改變成了一個提交。

相關文章
相關標籤/搜索