最近想把代碼傳到GitHub上,結果我發現的demo的npm全是本地安裝,上穿到GitHub要死要死,幾百M,而後我就搜了下怎麼不上傳node_modules
弄了半天也沒成功,因而準備靜下心學一下git,也當一個筆記往後好翻閱.
研究前個人只會5個命令html
$ git init
$ git add .
$ git commit -m "提交的xxxxx"
$ git pull
$ git push
複製代碼
Git是一個開源的分佈式版本控制系統,用於敏捷高效地處理任何或小或大的項目。 Git 是 Linus Torvalds 爲了幫助管理 Linux 內核開發而開發的一個開放源碼的版本控制軟件。 Git 與經常使用的版本控制工具 CVS, Subversion 等不一樣,它採用了分佈式版本庫的方式,沒必要服務器端軟件支持。node
版本庫:工做區有一個隱藏目錄.git,這個不算工做區,而是Git的版本庫。webpack
什麼是版本庫呢?版本庫又名倉庫,英文名repository,你能夠簡單理解成一個目錄,這個目錄裏面的全部文件均可以被Git管理起來,每一個文件的修改、刪除,Git都能跟蹤,以便任什麼時候刻均可以追蹤歷史,或者在未來某個時刻能夠「還原」。git
暫存區:英文叫stage, 或index。通常存放在 ".git目錄下" 下的index文件(.git/index)中,因此咱們把暫存區有時也叫做索引(index)。github
工做區:就是你在電腦裏能看到的目錄。web
我就不詳細介紹了,估計你們都會,就是上面辣個圖,圖上幾個命令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
複製代碼
分支在實際中有什麼用呢?假設你準備開發一個新功能,可是須要兩週才能完成,第一週你寫了50%的代碼,若是馬上提交,因爲代碼還沒寫完,不完整的代碼庫會致使別人不能幹活了。若是等代碼所有寫完再一次提交,又存在丟失天天進度的巨大風險。
如今有了分支,就不用怕了。你建立了一個屬於你本身的分支,別人看不到,還繼續在原來的分支上正常工做,而你在本身的分支上幹活,想提交就提交,直到開發完畢後,再一次性合併到原來的分支上,這樣,既安全,又不影響別人工做。
你已經知道,每次提交,Git都把它們串成一條時間線,這條時間線就是一個分支。截止到目前,只有一條時間線,在Git裏,這個分支叫主分支,即master分支。HEAD嚴格來講不是指向提交,而是指向master,master纔是指向提交的,因此,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就須要修復,在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