前言
本文是參考廖雪峰老師的Git資料再加上我自己對Git的理解,記錄我的Git學(xué)習(xí)歷程,作下此文是為以后學(xué)習(xí),工作,開發(fā)中如果遇到問題可以回過頭來參考參考。因為水平有限,難免會有出錯的地方,歡迎指正。
Git是什么
- 官方話:Git是一個免費的開源分布式版本控制系統(tǒng),旨在快速高效地處理從小型到大型項目的所有事務(wù)。
- 引用廖雪峰老師的話,它能自動幫我記錄每次文件的改動,還可以讓同事協(xié)作編輯,這樣就不用自己管理一堆類似的文件了,也不需要把文件傳來傳去。如果想查看某次改動,只需要在軟件里瞄一眼就可以。
為什么要學(xué)習(xí)Git
- 面試要被問??梢詰?yīng)付面試。
- 很多公司開發(fā)都用Git來處理項目?,F(xiàn)在不學(xué),以后肯定還要學(xué)。
- 在我看來Git是現(xiàn)如今所有程序員都要掌握的,以后與同事共同開發(fā)項目必定要用到的,熟練掌握Git命令,可以提高開發(fā)的效率。。
安裝Git
- Windows
直接在官網(wǎng)上去下載。下載完成后,隨便在某個文件下右鍵如果有Git Bash Here就安裝成功。安裝后,還要在命令行輸入
$git config --global user.name "你的名字"
$git config --global user.email "你的郵箱"
global表示全局,這臺機(jī)器所有的Git倉庫都會使用這個配置。允許單個倉庫使用其他的名字和郵箱。
- Mac
評論區(qū)指出Mac也可以像Windows一樣,按上面的步驟安裝。
也可以直接從AppStore安裝Xcode,Xcode集成了Git,不過默認(rèn)沒有安裝,你需要運行Xcode,選擇菜單“Xcode”->“Preferences”,在彈出窗口中找到“Downloads”,選擇“Command Line Tools”,點“Install”就可以完成安裝了。
倉庫
- 本地倉庫是對于遠(yuǎn)程倉庫而言的。
- 本地倉庫 = 工作區(qū) + 版本區(qū)
- 工作區(qū)即磁盤上的文件集合。
- 版本區(qū)(版本庫)即
.git文件 - 版本庫 = 暫存區(qū)(stage) + 分支(master) + 指針Head
- 以我使用最頻繁的git命令為例,即提交到github為例。
-
git init原本本地倉庫只包含著工作區(qū),這是最常見的工作狀態(tài)。此時,git init一下,表示在本地區(qū)域創(chuàng)建了一個.git文件,版本區(qū)建立。 -
git add .表示把工作區(qū)的所有文件全部提交到版本區(qū)里面的暫存區(qū) - 當(dāng)然你也可以通過
git add ./xxx/一條一條分批添加到暫存區(qū)。 -
git commit -m "xxx"把暫存區(qū)的所有文件提交到倉庫區(qū),暫存區(qū)空空蕩蕩。 -
git remote add origin https://github.com/name/name_cangku.git把本地倉庫與遠(yuǎn)程倉庫連接起來。 -
git push -u origin master把倉庫區(qū)的文件提交到遠(yuǎn)程倉庫里。 - 一旦提交后,如果你又沒有對工作區(qū)做任何修改,那么工作區(qū)就是“干凈”的。會有這樣的信息
nothing to commit, working tree clean
提交到GitHub
以前不熟悉git命令的時候,我提交項目到github上都是直接在網(wǎng)頁上直接拉取文件提交上去的。有點羞恥。
-
git init.初始化,表示把這個文件變成Git可以管理的倉庫。初始化后打開隱藏的文件可以看到有一個.git文件。 -
git add .后面的一個點表示把這個文件全部提交到暫存區(qū)。 -
git add ./readme.md/表示把這個文件下面的readme.md文件提交到暫存區(qū)。 -
git commit -m "你要評論一點什么東西"git commit的意思是把暫存區(qū)的全部文件提交到本地倉庫。-m后接評論。 -
git remote add origin https://github.com/name/name_cangku.git表示把你本地的倉庫與GitHub上的遠(yuǎn)程倉庫連接起來。只需要連接一次,以后提交的時候就可以不用謝這條命令了。name是你的github名字,name_cangku是你的倉庫名。注意不要把后面的.git給漏掉了。因為我前面就是這么走過來的,繞了很多彎路。至于如何在GitHub上新建倉庫,網(wǎng)上有很多教程,這里不再贅述了。 -
git push -u origin master把本地倉庫提交到遠(yuǎn)程倉庫。(最后一步)在你的遠(yuǎn)程倉庫上刷新一下就可以看到你提交的文件了。 - 最后提到的是,在
git commit -m ""之前,可以重復(fù)git add到暫存區(qū)。但是git commit會把你之前存放在暫存區(qū)的全部文件一次性全部提交到本地倉庫。
版本的回溯與前進(jìn)
提交一個文件,有時候我們會提交很多次,在提交歷史中,這樣就產(chǎn)生了不同的版本。每次提交,Git會把他們串成一條時間線。如何回溯到我們提交的上一個版本,用git reset --hard + 版本號即可。 版本號可以用git log來查看,每一次的版本都會產(chǎn)生不一樣的版本號?;厮葜?,git log查看一下發(fā)現(xiàn)離我們最近的那個版本已經(jīng)不見了。但是我還想要前進(jìn)到最近的版本應(yīng)該如何?只要git reset --hard + 版本號就行。退一步來講,雖然我們可以通過git reset --hard + 版本號,靠記住版本號來可以在不同的版本之間來回穿梭。但是,有時候把版本號弄丟了怎么辦?git reflog幫你記錄了每一次的命令,這樣就可以找到版本號了,這樣你又可以通過git reset來版本穿梭了。
撤銷
- 場景1:在工作區(qū)時,你修改了一個東西,你想撤銷修改,
git checkout -- file。廖雪峰老師指出撤銷修改就回到和版本庫一模一樣的狀態(tài),即用版本庫里的版本替換工作區(qū)的版本。 - 場景2:你修改了一個內(nèi)容,并且已經(jīng)
git add到暫存區(qū)了。想撤銷怎么辦?回溯版本,git reset --hard + 版本號,再git checkout -- file,替換工作區(qū)的版本。 - 場景3:你修改了一個內(nèi)容,并且已經(jīng)
git commit到了master。跟場景2一樣,版本回溯,再進(jìn)行撤銷。
刪除
- 如果你
git add一個文件到暫存區(qū),然后在工作區(qū)又把文件刪除了,Git會知道你刪除了文件。如果你要把版本庫里的文件刪除,git rm并且git commit -m "xxx". - 如果你誤刪了工作區(qū)的文件,怎么辦?使用撤銷命令,
git checkout --<file>就可以。這再次證明了撤銷命令其實就是用版本庫里的版本替換工作區(qū)的版本,無論工作區(qū)是修改還是刪除,都可以“一鍵還原”。
分支
分支,就像平行宇宙,廖雪峰老師如是說。你創(chuàng)建了一個屬于你自己的分支,別人看不到,還繼續(xù)在原來的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到開發(fā)完畢后,再一次性合并到原來的分支上,這樣,既安全,又不影響別人工作。
創(chuàng)建與合并分支
在沒有其他分支插進(jìn)來時,只有一個master主分支。每次你
git push -u origin master 提交就是增加一條時間軸,master也會跟著移動。
創(chuàng)建一個other的分支,通過other提交,雖然時間軸向前走了,但是主分支master還在原來的位置。
理論分析完,看一下命令怎么寫。
- 創(chuàng)建分支
other,切換到other分支。
git branch other
git checkout other
- 查看當(dāng)前所有分支
git branch
* other
master
當(dāng)前的分支會有一個*
- 用
other提交
git add ./xxx/
git commit -m "xxx"
-
other分支完成,切換回master
git checkout master
- 此時,master分支上并沒有
other的文件,因為分支還沒有合并。 - 合并分支
git merge other
- 合并完成之后,就可以在master分支上查看到文件了。
- 刪除
other分支。
git branch -d other
- 我由此想到,在以后工作中,應(yīng)該是一個開放小組共同開發(fā)一個項目,組長會創(chuàng)建很多分支,每一個分支可以交給一個人去開發(fā)某一個功能,一個小組共同開發(fā)而且不會相互干擾。誰的功能完成了,可以由組長合并一下完成了的分支。哦,完美!
解決合并分支問題
假如有這樣一種情況,分支
other已經(jīng)commit了,但是此時指針指回master時,并且master沒有合并,而是git add / commit 提交了。這樣,就產(chǎn)生了沖突,主分支master文件內(nèi)容與other分支的內(nèi)容不一樣。合并不起來!所以,
- 修改文件的內(nèi)容,讓其保持一致。
-
git addgit commit提交。 -
分支合并了。
image -
git log --graph查看分支合并圖 -
git branch -d other刪除分支,任務(wù)結(jié)束。
分支管理策略
-
git merge --no-ff other禁用Fast forward模式,因為使用Fast forward模式,刪除分支后,分支歷史信息會丟失。
BUG分支
廖雪峰老師提到,工作中每個bug都可以通過一個新的臨時分支來修復(fù),修復(fù)后,合并分支,然后將臨時分支刪除。但如果你手上有分支在工作中,你的上級要你改另外的分支的BUG。你要把現(xiàn)在正在工作的分支保存下來,
git stash,把當(dāng)前工作現(xiàn)場“存儲”起來,等以后恢復(fù)后繼續(xù)工作。當(dāng)你解決BUG后,git checkout other回到自己的分支。用git stash list查看你剛剛“存放”起來的工作去哪里了。此時你要恢復(fù)工作:
-
git stash apply恢復(fù)卻不刪除stash內(nèi)容,git stash drop刪除stash內(nèi)容。 -
git stash pop恢復(fù)的同時把stash內(nèi)容也刪了. - 此時,用
git stash list查看,看不到任何stash內(nèi)容。
總結(jié):修復(fù)bug時,我們會通過創(chuàng)建新的bug分支進(jìn)行修復(fù),然后合并,最后刪除;當(dāng)手頭工作沒有完成時,先把工作現(xiàn)場git stash一下,然后去修復(fù)bug,修復(fù)后,再git stash pop,回到工作現(xiàn)場
刪除分支
-
git branch -d + 分支有可能會刪除失敗,因為Git會保護(hù)沒有被合并的分支。 -
git branch -D + 分支強(qiáng)行刪除,丟棄沒被合并的分支。
多人協(xié)作
-
git remote查看遠(yuǎn)程庫的信息,會顯示origin,遠(yuǎn)程倉庫默認(rèn)名稱為origin -
git remote -v顯示更詳細(xì)的信息 -
git push -u origin master推送master分支到origin遠(yuǎn)程倉庫。 -
git push -u origin other推送other到origin遠(yuǎn)程倉庫。
抓取分支
產(chǎn)生上圖的沖突時,
-
git pull把最新的提交從遠(yuǎn)程倉庫中抓取下來,在本地合并,解決沖突。在進(jìn)行git pull - 如果
git pull也失敗了,還要指定分支之間的鏈接,這一步Git會提醒你怎么做。然后再git pull。廖雪峰老師的總結(jié):多人協(xié)作的工作模式通常是這樣:
首先,可以試圖用
git push origin <branch-name>推送自己的修改;如果推送失敗,則因為遠(yuǎn)程分支比你的本地更新,需要先用
git pull試圖合并;如果合并有沖突,則解決沖突,并在本地提交;
沒有沖突或者解決掉沖突后,再用
git push origin <branch-name>推送就能成功!如果
git pull提示no tracking information,則說明本地分支和遠(yuǎn)程分支的鏈接關(guān)系沒有創(chuàng)建,用命令git branch --set-upstream-to <branch-name> origin/<branch-name>。
Rebase
-
git rebase把分叉的提交歷史“整理”成一條直線,看上去更直觀.缺點是本地的分叉提交已經(jīng)被修改過了。 - 最后在進(jìn)行
git push -u origin master -
rebase的目的是使得我們在查看歷史提交的變化時更容易,因為分叉的提交需要三方對比。
標(biāo)簽管理
比如一個APP要上線,通常在版本庫中打一個標(biāo)簽(tag),
這樣,就確定了打標(biāo)簽的版本。將來無論什么時候,取某個標(biāo)簽的版本,就是把那個打標(biāo)簽的時刻的歷史版本取出來。所以,標(biāo)簽也是版本庫的一個快照。
Git的標(biāo)簽雖然是版本庫的快照,但其實它就是指向某個commit的指針。
tag其實就是一個讓人容易記住的有意義的名字,它跟某個commit綁在一起。比如tag v2.1就是把歷史上的一個版本的東西叫做v2.1
創(chuàng)建標(biāo)簽
步驟:
-
git branch查看當(dāng)前分支,git checkout master切換到master分支。 -
git tag <name>打標(biāo)簽,默認(rèn)為HEAD。比如git tag v1.0 - 默認(rèn)標(biāo)簽是打在最新提交的
commit上的。如果想要打標(biāo)簽在以前的commit上,要git log找到歷史提交的commitid. - 如果一個
commt id是du2n2d9,執(zhí)行git tag v1.0 du2n2d9就把這個版本打上了v1.0的標(biāo)簽了。 -
git tag查看所有標(biāo)簽,可以知道歷史版本的tag - 標(biāo)簽不是按時間順序列出,而是按字母排序的。
-
git show <tagname>查看標(biāo)簽信息。 -
git tag -a <標(biāo)簽名> -m "<說明>",創(chuàng)建帶說明的標(biāo)簽。-a指定標(biāo)簽名,-m指定說明文字。用show可以查看說明。
操作標(biāo)簽
-
git tag -d v1.0刪除標(biāo)簽。因為創(chuàng)建的標(biāo)簽都只存儲在本地,不會自動推送到遠(yuǎn)程。所以,打錯的標(biāo)簽可以在本地安全刪除。 -
git push origin <tagname>推送某個標(biāo)簽到遠(yuǎn)程 -
git push origin --tags一次性推送全部尚未推送到遠(yuǎn)程的本地標(biāo)簽 - 如果標(biāo)簽推送到遠(yuǎn)程。
git tag -d v1.0先刪除本地標(biāo)簽v1.0。git push origin :refs/tags/v1.0刪除遠(yuǎn)程標(biāo)簽v1.0
自定義Git
-
git config --global color.ui true讓Git顯示顏色,會讓命令輸出看起來更醒目 - 忽略特殊文件
創(chuàng)建一個.gitignore文件,把需要忽略的文件名填進(jìn)去。Git就會自動忽略這些文件。我也在學(xué)習(xí)中遇到過這樣的問題,比如node_modules文件就可以忽略。 忽略文件原則:忽略操作系統(tǒng)自動生成的文件,比如縮略圖等;
忽略編譯生成的中間文件、可執(zhí)行文件等,也就是如果一個文件是通過另一個文件自動生成的,那自動生成的文件就沒必要放進(jìn)版本庫,比如Java編譯產(chǎn)生的.class文件;
忽略你自己的帶有敏感信息的配置文件,比如存放口令的配置文件。- 強(qiáng)制提交已忽略的的文件。
git add -f <file> -
git check-ignore -v <file>檢查為什么Git會忽略該文件。 -
給Git命令配別名,這個有點騷,就是你以后想輸入
git rebase時,你給它一個“外號”,就叫它git nb。以后你可以通過git nb來代替git rebase。具體怎么轉(zhuǎn)換可以去廖雪峰老師的網(wǎng)站看。因為水平有限,我覺得先把正常的Git命令搞清楚來就很不錯了。
常用Git命令總結(jié)
-
git config --global user.name "你的名字"讓你全部的Git倉庫綁定你的名字 -
git config --global user.email "你的郵箱"讓你全部的Git倉庫綁定你的郵箱 -
git init初始化你的倉庫 -
git add .把工作區(qū)的文件全部提交到暫存區(qū) -
git add ./<file>/把工作區(qū)的<file>文件提交到暫存區(qū) -
git commit -m "xxx"把暫存區(qū)的所有文件提交到倉庫區(qū),暫存區(qū)空空蕩蕩 -
git remote add origin https://github.com/name/name_cangku.git把本地倉庫與遠(yuǎn)程倉庫連接起來 -
git push -u origin master把倉庫區(qū)的主分支master提交到遠(yuǎn)程倉庫里 -
git push -u origin <其他分支>把其他分支提交到遠(yuǎn)程倉庫 -
git status查看當(dāng)前倉庫的狀態(tài) -
git diff查看文件修改的具體內(nèi)容 -
git log顯示從最近到最遠(yuǎn)的提交歷史 -
git clone + 倉庫地址下載克隆文件 -
git reset --hard + 版本號回溯版本,版本號在commit的時候與master跟隨在一起 -
git reflog顯示命令歷史 -
git checkout -- <file>撤銷命令,用版本庫里的文件替換掉工作區(qū)的文件。我覺得就像是Git世界的ctrl + z -
git rm刪除版本庫的文件 -
git branch查看當(dāng)前所有分支 -
git branch <分支名字>創(chuàng)建分支 -
git checkout <分支名字>切換到分支 -
git merge <分支名字>合并分支 -
git branch -d <分支名字>刪除分支,有可能會刪除失敗,因為Git會保護(hù)沒有被合并的分支 -
git branch -D + <分支名字>強(qiáng)行刪除,丟棄沒被合并的分支 -
git log --graph查看分支合并圖 -
git merge --no-ff <分支名字>合并分支的時候禁用Fast forward模式,因為這個模式會丟失分支歷史信息 -
git stash當(dāng)有其他任務(wù)插進(jìn)來時,把當(dāng)前工作現(xiàn)場“存儲”起來,以后恢復(fù)后繼續(xù)工作 -
git stash list查看你剛剛“存放”起來的工作去哪里了 -
git stash apply恢復(fù)卻不刪除stash內(nèi)容 -
git stash drop刪除stash內(nèi)容 -
git stash pop恢復(fù)的同時把stash內(nèi)容也刪了 -
git remote查看遠(yuǎn)程庫的信息,會顯示origin,遠(yuǎn)程倉庫默認(rèn)名稱為origin -
git remote -v顯示更詳細(xì)的信息 -
git pull把最新的提交從遠(yuǎn)程倉庫中抓取下來,在本地合并,和git push相反 -
git rebase把分叉的提交歷史“整理”成一條直線,看上去更直觀 -
git tag查看所有標(biāo)簽,可以知道歷史版本的tag -
git tag <name>打標(biāo)簽,默認(rèn)為HEAD。比如git tag v1.0 -
git tag <tagName> <版本號>把版本號打上標(biāo)簽,版本號就是commit時,跟在旁邊的一串字母數(shù)字 -
git show <tagName>查看標(biāo)簽信息 -
git tag -a <tagName> -m "<說明>"創(chuàng)建帶說明的標(biāo)簽。-a指定標(biāo)簽名,-m指定說明文字 -
git tag -d <tagName>刪除標(biāo)簽 -
git push origin <tagname>推送某個標(biāo)簽到遠(yuǎn)程 -
git push origin --tags一次性推送全部尚未推送到遠(yuǎn)程的本地標(biāo)簽 -
git push origin :refs/tags/<tagname>刪除遠(yuǎn)程標(biāo)簽<tagname> -
git config --global color.ui true讓Git顯示顏色,會讓命令輸出看起來更醒目 -
git add -f <file>強(qiáng)制提交已忽略的的文件 -
git check-ignore -v <file>檢查為什么Git會忽略該文件
結(jié)語
廖雪峰老師講Git講的通俗易懂,對小白很友好。認(rèn)認(rèn)真真花上兩天時間去整理,會有所收獲的。廖老師的個人網(wǎng)站傳送門