快速上手Git版本控制
基本概念和操作
如何提交
git add . 添加所有文件
git commit -m "備注" 提交到本地版本庫(kù)

git add命令實(shí)際上就是把要提交的所有修改放到暫存區(qū)(Stage),
然后,執(zhí)行g(shù)it commit就可以一次性把暫存區(qū)的所有修改提交到分支。
提交之后是這樣的 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

git diff HEAD -- readme.txt 命令可以查看工作區(qū)和版本庫(kù)里面最新版本的區(qū)別
如何撤銷
git checkout -- filename 可以丟棄工作區(qū)的修改
git checkout -- file命令中的--很重要,沒有--,就變成了“
切換到另一個(gè)分支”的命令
git checkout 其實(shí)是用版本庫(kù)里的版本替換工作區(qū)的版本,無論工作區(qū)是修改還是刪除,都可以“一鍵還原”
遠(yuǎn)程倉(cāng)庫(kù)
查看遠(yuǎn)程倉(cāng)庫(kù)地址
git remote -v
把本地庫(kù)的內(nèi)容推送到遠(yuǎn)程
git push 把當(dāng)前分支推送到遠(yuǎn)程,如果是從遠(yuǎn)程倉(cāng)庫(kù)clone出來的話可以直接使用。
本地作了提交,就可以通過命令
git push origin master
另外:
把本地的master分支,推送到遠(yuǎn)程的origin倉(cāng)庫(kù)
git push -u origin master
加上了-u參數(shù),Git不但會(huì)把本地的master分支內(nèi)容推送的遠(yuǎn)程新的master分支,還會(huì)把本地的master分支和遠(yuǎn)程的master分支關(guān)聯(lián)起來,在以后的推送或者拉取時(shí)就可以簡(jiǎn)化命令。
要關(guān)聯(lián)一個(gè)遠(yuǎn)程庫(kù),使用命令:
git remote add origin git@server-name:path/repo-name.git
關(guān)聯(lián)后,使用命令git push -u origin master第一次推送master分支的所有內(nèi)容;
此后,每次本地提交后,只要有必要,就可以使用命令git push origin master推送最新修改;
假設(shè)我們從零開發(fā),那么最好的方式是先創(chuàng)建遠(yuǎn)程庫(kù),然后,從遠(yuǎn)程庫(kù)克?。?br>
git clone git@server-name:path/repo-name.git
git 支持HTTP和Git協(xié)議,HTTP一般更快一些。
分支詳解

每次提交,master分支都會(huì)向前移動(dòng)一步,這樣,隨著你不斷提交,master分支的線也越來越長(zhǎng)

創(chuàng)建了一個(gè)分支dev,Head指向到dev(dev變成當(dāng)前分支)

從現(xiàn)在開始,對(duì)工作區(qū)的修改和提交就是針對(duì)dev分支了,比如新提交一次后,dev指針往前移動(dòng)一步,而master指針不變。

假如我們?cè)赿ev上的工作完成了,就可以把dev合并到master上。Git怎么合并呢?最簡(jiǎn)單的方法,就是直接把master指向dev的當(dāng)前提交,就完成了合并。

如上圖所示,合并完分支后,甚至可以刪除dev分支。刪除dev分支就是把dev指針給刪掉,刪掉后,我們就剩下了一條master分支。
別急,下面是分支的操作。
分支操作
拉取遠(yuǎn)程分支
git checkout -b picking origin/picking 拉取遠(yuǎn)程分支到本地(本地也創(chuàng)建了分支picking)
不要忘記-b 后兩個(gè)參數(shù),一個(gè)是本地分支叫picking,遠(yuǎn)程分支origin/picking。
git checkout -b origin/picking,這個(gè)是錯(cuò)誤的,這個(gè)只是創(chuàng)建了本地分支origin/picking
創(chuàng)建分支
git checkout 命令加上-b參數(shù)表示創(chuàng)建并切換。
例:
git checkout -b dev 創(chuàng)建(本地)分支 dev并切換。
切換分支
這里再次說明:切換分支就是 git checkout <branch>
git branch 命令會(huì)列出所有分支,當(dāng)前分支前面會(huì)標(biāo)一個(gè) * 號(hào)。
例:命令窗口輸出
dell@dell-PC MINGW64 /e/IdeaProject/spring-framework (4.2.6.RELEASE)
$ git branch
* 4.2.6.RELEASE
4.2.x
master
git checkout master 回到master分支
刪除分支
git branch -d dev 刪除分支dev
git 鼓勵(lì)你使用分支完成某個(gè)任務(wù),合并后再刪掉分支。
合并分支的情況
有四種合并情況:
在master分支下:
git merge master;//將master合并到master上,自然master不會(huì)改變。git merge dev;//將dev合并到master上,自然dev不會(huì)發(fā)生改變;而master則需分情況討論,若master在dev之前則masterdev變?yōu)楹蚫ev一樣,若master在dev之后,則master不變。
在dev分支下:
git merge dev;//將dev合并到dev上,自然dev不會(huì)發(fā)生改變git merge master;//將master合并到dev上,自然master不會(huì)改變;而dev則需分情況討論,若dev在master之前則dev變?yōu)楹蚼aster一樣,若dev在master之后,則dev不變。
總而言之,任意在任意一個(gè)分支A下均可與其它分支(包括該分支自身)B和并,且和并后分支B不變,而分支A則變?yōu)榉种和B中較新的一個(gè)分支。
合并分支
合并分支是非常常見的操作:git merge命令用于合并指定分支到當(dāng)前分支。
git merge dev 把dev分支合并到當(dāng)前分支,不管在什么分支,都是把指定的分支合并到自己當(dāng)前的分支。
開發(fā)中常常在dev分支開發(fā),如果需要拉取master上的提交,通常就是在dev分支下,git merge master,這樣代碼就是最新的了。
如果你在dev當(dāng)前開發(fā)(提交)完成,確認(rèn)沒有問題的時(shí)候,如果要(可以)合并到master了,
這時(shí)候切換到master分支,git checkout master,然后git merge dev。
FastForward
使用fastforward會(huì)丟失分支信息。git 默認(rèn)是使用FastForward。一般禁止使用FastForward。
Fastforward就是直接將HEAD指向了dev最當(dāng)前的版本,沒有產(chǎn)生新的提交,并且看不到原來的分支信息。
不使用FastForward
將dev合并到master(當(dāng)前在master)
git merge --no-ff -m "merge with no-ff" dev
git就會(huì)在merge時(shí)生成一個(gè)新的commit,這樣,從分支歷史上就可以看出分支信息。


合并分支時(shí),加上--no-ff參數(shù)(ff就是fastforward)就可以用普通模式合并,合并后的歷史有分支,能看出來曾經(jīng)做過合并,而fast forward合并就看不出來曾經(jīng)做過合并。
解決分支沖突
當(dāng)Git無法自動(dòng)合并分支時(shí),就必須首先解決沖突。解決沖突后,再次提交,合并完成。一般JetBrains的IDE提供了很強(qiáng)大的可視化Merge功能。
推送分支
git push origin test
把當(dāng)前分支推送到 遠(yuǎn)程分支test
git push
直接推送本分支到遠(yuǎn)程已經(jīng)關(guān)聯(lián)的分支
推送分支的三種情況
推送本地分支local_branch到遠(yuǎn)程分支 remote_branch并建立關(guān)聯(lián)關(guān)系
| 遠(yuǎn)程remote_branch分支 | 本地已經(jīng)切換到local_branch | 遠(yuǎn)程關(guān)聯(lián)本地分支local_branch | 命令 |
|---|---|---|---|
| 已有 | 是 | 已經(jīng)關(guān)聯(lián) | git push |
| 已有 | 是 | 未關(guān)聯(lián) | git push -u origin/remote_branch |
| 沒有 | 是 | - | git push origin local_branch:remote_branch |
并不是一定要把本地分支往遠(yuǎn)程推送,那么,哪些分支需要推送,哪些不需要呢?
| 場(chǎng)景 | 是否需要 | 理由 |
|---|---|---|
| master分支是主分支 | 必須 | 要時(shí)刻與遠(yuǎn)程同步 |
| dev分支是開發(fā)分支 | 必須 | 團(tuán)隊(duì)所有成員都需要在上面工作,所以也需要與遠(yuǎn)程同步 |
| bug分支 | 可選 | 只用于在本地修復(fù)bug,就沒必要推到遠(yuǎn)程了,除非老板要看看你每周到底修復(fù)了幾個(gè)bug |
| feature分支 | 看情況 | 是否推到遠(yuǎn)程,取決于你是否和你的小伙伴合作在上面開發(fā) |
總之,就是在Git中,分支完全可以在本地,是否推送看自己!
臨時(shí)儲(chǔ)藏
Git還提供了一個(gè)stash功能,可以把當(dāng)前工作現(xiàn)場(chǎng)“儲(chǔ)藏”起來,等以后恢復(fù)現(xiàn)場(chǎng)后繼續(xù)工作
查看臨時(shí)現(xiàn)場(chǎng)
git stash list
恢復(fù)現(xiàn)場(chǎng)
有兩個(gè)辦法,一是用git stash apply恢復(fù),但是恢復(fù)后,stash內(nèi)容并不刪除,你需要用git stash drop來刪除;
另一種方式是用git stash pop,恢復(fù)的同時(shí)把stash內(nèi)容也刪了。
標(biāo)簽
git tag <name> 給當(dāng)前分支 打個(gè)標(biāo)簽
git tag v0.9 6224937 給歷史commit id加標(biāo)簽
git tag -a v0.1 -m "version 0.1 released" 3628164 加上標(biāo)簽時(shí)添加說明文字
git show <tagname> 查看標(biāo)簽內(nèi)容
git push origin <tagname> 推送標(biāo)簽到遠(yuǎn)程
git checkout -b/B <localbranch> <tagname> 拉取遠(yuǎn)程的Tag到本地分支localbranch
git push origin --tags 一次性推送全部尚未推送到遠(yuǎn)程的本地標(biāo)簽
刪除標(biāo)簽
如果標(biāo)簽已經(jīng)推送到遠(yuǎn)程,要?jiǎng)h除遠(yuǎn)程標(biāo)簽就麻煩一點(diǎn),先從本地刪除,然后,從遠(yuǎn)程刪除。
git tag -d <tagname>
或者
git push origin :refs/tags/<tagname>
冒號(hào)左邊是空的,含義就是用空的推過去,表示不要了。
附常用命令
git commit提交到本地緩存
git diff 比較文件
git status 查看文件版本狀態(tài)
git log 查看版本歷史
git reset --hard Hard^ 回滾上一個(gè)版本
git reflog 查看commit ID
用戶
查看用戶名和郵箱地址:
git config user.name
git config user.email
修改用戶名和郵箱地址:
git config --global user.name "username"
git config --global user.email "xxx@xxx.com"
清除認(rèn)證信息:
git credential-manager delete
這個(gè)命令適用于,當(dāng)你提交的時(shí)候總是失敗,但是確定密碼正確的時(shí)候。
提交失敗:
基本上就是因?yàn)闆]權(quán)限了。如果有,參考上面一條。
開源項(xiàng)目之路
多remote倉(cāng)庫(kù)
已知已經(jīng)克隆了一個(gè)自己的倉(cāng)庫(kù),遠(yuǎn)程倉(cāng)庫(kù)名字叫做origin
下面需要增加一個(gè)遠(yuǎn)程倉(cāng)庫(kù),命名github
git remote add github https://github.com/slankka/someRepo.git
這樣就有兩個(gè)遠(yuǎn)程倉(cāng)庫(kù)了。
git fetch github 可以拉取該分支的最新代碼到本地緩存,
合并需要用git pull github branchName
git fetch origin 可以拉取自己的倉(cāng)庫(kù)最新代碼。
rebase 合并多個(gè)提交
例子:把前面兩個(gè)提交合并到第三個(gè)commit,最早提交的那個(gè)。
# git log
commit 06cb6a26492319985aac59bd7fc8be8514925381 (origin/IPVE-2018-06-14-SPL, IPVE-2018-06-14-SPL)
Author: slankka <cor_twi@outlook.com>
Date: Tue Jun 19 10:21:22 2018 +0800
最終改進(jìn)
commit f5c61305441cc4266246539bc740647bd962c51f
Author: slankka <cor_twi@outlook.com>
Date: Fri Jun 15 18:48:31 2018 +0800
再次改進(jìn)
commit 5a46753bc04240786a68bb54cd1fcfa9dd9f857e
Author: slankka <cor_twi@outlook.com>
Date: Fri Jun 15 17:00:01 2018 +0800
我提交了一個(gè)特性
輸入:rebase -i 5a4675
然后會(huì)有一個(gè)文本被打開
pick f5c61305 再次改進(jìn)
pick 06cb6a26 最終改進(jìn)
# Rebase 5a46753b..06cb6a26 onto 5a46753b (2 commands)
意思就是 把這三個(gè)提交rebase到最早的提交(我提交了一個(gè)特性)這里。
把第二個(gè)pick改成s,或者是squash
pick f5c61305 再次改進(jìn)
s 06cb6a26 最終改進(jìn)
# Rebase 5a46753b..06cb6a26 onto 5a46753b (2 commands)
然后就rebase完成了,三個(gè)提交被合并成一個(gè)了
接下來輸入最新的commit message,可以只寫一句。
最終push 得時(shí)候帶上 --force,覆蓋遠(yuǎn)程分支,這樣提交記錄就很干凈了。
本文內(nèi)容基于廖雪峰的Git教程編寫