簡介
分布式版本控制系統(tǒng)與集中式版本控制系統(tǒng)最大的區(qū)別就是它沒有“中央服務(wù)器”;每個(gè)人的電腦上都是一個(gè)完整的版本庫褥影,同事之間只需要將自己的修改推送給對(duì)方醇滥,就可以互相看到對(duì)方的修改了识窿。
不過在實(shí)際使用Git的時(shí)候,其實(shí)很少在兩個(gè)人之間的電腦互推第步。通常也有一臺(tái)充當(dāng)“中央服務(wù)器”的電腦疮装,這個(gè)服務(wù)器僅僅是用來方便同步大家的修改。
安裝Git
因?yàn)閄code自帶的有Git所以就不在介紹了粘都。
創(chuàng)建版本庫(repository)
git init #創(chuàng)建一個(gè)空的倉庫
注:init
后用ls -ah
命令可以看到當(dāng)前目錄下多了一個(gè).git
隱藏目錄廓推。這個(gè)目錄是Git用來跟蹤管理版本庫的,不要隨意手動(dòng)修改這個(gè)目錄里的任何文件翩隧。
把文件添加到版本庫(add)
git add . #把當(dāng)前目錄下的所有文件添加到倉庫
注:add只是把文件修改添加到暫存區(qū)
把文件提交到倉庫(commit)
git commit -m "日志消息"
注:commit是把暫存區(qū)里的修改提交到當(dāng)前分支
查看版本庫當(dāng)前的狀態(tài)(status)
git status
查看文件修改(diff)
git diff README.md
git diff HEAD -- README.md #查看README.md文件在工作區(qū)和版本庫里面最新版本的區(qū)別
查看歷史記錄(log)
git log #顯示從最近到最遠(yuǎn)的提交日志
git log --pretty=oneline #只顯示版本號(hào)和修改內(nèi)容
回退版本(reset)
git reset --hard HEAD^ #回退到上一個(gè)版本
#注:當(dāng)你回退到了某個(gè)版本后樊展,又想恢復(fù)到新版本怎么辦?想回到新版本必須找到新版本的版本號(hào)堆生。我們可以用`git reflog`來查詢专缠。
git reflog #查詢每次提交的id
git reset --hard 3637964 #3637964是最新版本的版本號(hào)
撤銷暫存區(qū)的修改(reset)
git reset HEAD README.md #把暫存區(qū)的修改撤銷掉,重新放回工作區(qū)
撤銷工作區(qū)的修改(checkout)
git checkout -- README.md #把README.md文件在“工作區(qū)”的修改全部撤銷
#注:`--`一定要有淑仆,沒有`--`就變成了“切換到另一個(gè)分支”的命令
刪除文件(rm)
git rm README.md #刪除暫存區(qū)涝婉、工作區(qū)和分支上的文件
git rm --cached README.md #刪除暫存區(qū)和分支上的文件厢破;工作區(qū)里的文件保留
遠(yuǎn)程倉庫1-配置SSH Key:以GitHub為例
由于本地Git倉庫和GitHub倉庫之間的傳輸是通過SSH加密的唇敞,所以拴鸵,需要一點(diǎn)設(shè)置:
第1步:創(chuàng)建SSH Key展融。在用戶主目錄下Finder前往~/.ssh
,看看有沒有.ssh
目錄如果有渔工,再看看這個(gè)目錄下有沒有id_rsa和id_rsa.pub這兩個(gè)文件锌钮,如果已經(jīng)有了,可直接跳到第2步涨缚。如果沒有就用以下命令創(chuàng)建
ssh-keygen -t rsa -C "youremail@example.com" #把郵件換成你自己的郵件地址,然后一路回車策治,無需設(shè)置密碼
#注:`.ssh`里有`id_rsa `和`id_rsa.pub `兩個(gè)文件脓魏,`id_rsa `是私鑰不能泄露出去,`id_rsa.pub `是公鑰通惫,可以放心地告訴任何人茂翔。
第2步:登陸GitHub,打開“Settings”履腋,“SSH and GPG keys”頁面:然后珊燎,點(diǎn)“New SSH Key”,填上任意Title遵湖,在Key文本框里粘貼id_rsa.pub文件的內(nèi)容:然后點(diǎn)擊“Add SSH Key”悔政,你就應(yīng)該看到已經(jīng)添加的Key:
遠(yuǎn)程倉庫2-關(guān)聯(lián)和推送:以GitHub為例
情景:我們先有本地Git倉庫,后有遠(yuǎn)程倉庫延旧,需要將本地和遠(yuǎn)程倉庫關(guān)聯(lián)谋国。
第1步:關(guān)聯(lián)遠(yuǎn)程倉庫(假如你在GitHub上已經(jīng)新建了一個(gè)倉庫LearnGit)。
git remote add origin git@github.com:leo-lp/LearnGit.git
#注:把上面的`leo-lp`替換成你自己的GitHub賬戶名迁沫。
第2步:把本地庫的所有內(nèi)容推送到遠(yuǎn)程庫芦瘾。
git push -u origin master #把當(dāng)前分支master推送到遠(yuǎn)程
#注:`-u`不但會(huì)把本地的master推送到遠(yuǎn)程master分支,還會(huì)把本地的master和遠(yuǎn)程的master關(guān)聯(lián)起來集畅。第一次推時(shí)需要近弟,以后再推/拉時(shí)就可以簡化了。
第一次推送有可能報(bào)以下錯(cuò)誤:
leodeMacBook-Pro:LearnGit leo$ git push -u origin master
To github.com:leo-lp/LearnGit.git
! [rejected] master -> master (fetch first)
error: failed to push some refs to 'git@github.com:leo-lp/LearnGit.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
leodeMacBook-Pro:LearnGit leo$
造成這個(gè)錯(cuò)誤的原因是Git倉庫中已經(jīng)有一部分代碼挺智,所以它不允許你直接把你的代碼推送上去祷愉。于是我們有2個(gè)選擇方式:
1.強(qiáng)推,用你本地的代碼替代Git倉庫內(nèi)的內(nèi)容:
git push -f origin master #注:會(huì)覆蓋遠(yuǎn)程倉庫里的內(nèi)容
2.把服務(wù)器上的內(nèi)容合并到本地在推送:git pull
可是這時(shí)又報(bào)錯(cuò)了赦颇。
leodeMacBook-Pro:LearnGit leo$ git pull
fatal: refusing to merge unrelated histories
leodeMacBook-Pro:LearnGit leo$
這時(shí)我們需要用以下兩個(gè)命令配置.git/config
文件:
git config branch.master.remote origin #當(dāng)本地是masterf分支, 默認(rèn)的remote就是origin
git config branch.master.merge refs/heads/master #當(dāng)本地是master分支使用git pull時(shí)谣辞,沒有指定remote分支,那么git就會(huì)采用默認(rèn)的origin來merge在master分支上所有的改變
這時(shí)我們已經(jīng)可以正常的pull
和push
了沐扳。完整操作如下:
leodeMacBook-Pro:LearnGit leo$ git config branch.master.remote origin
leodeMacBook-Pro:LearnGit leo$ git config branch.master.merge refs/heads/master
leodeMacBook-Pro:LearnGit leo$ git pull
Already up-to-date.
leodeMacBook-Pro:LearnGit leo$ git push origin master
Counting objects: 26, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (21/21), done.
Writing objects: 100% (26/26), 12.68 KiB | 0 bytes/s, done.
Total 26 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), done.
To github.com:leo-lp/LearnGit.git
f01930f..0892bfe master -> master
leodeMacBook-Pro:LearnGit leo$
遠(yuǎn)程倉庫3-克履啻印:以GitHub為例
情景:我們需要從零開發(fā),那么最好的方式是先創(chuàng)建遠(yuǎn)程倉庫沪摄,然后克隆躯嫉。
第1步:登錄GitHub新建一個(gè)倉庫LearnGit纱烘。
第2步:克隆到本地:
git clone git@github.com:leo-lp/LearnGit.git
分支管理1-創(chuàng)建/切換分支(branch/checkout)
git branch MyBranch #創(chuàng)建分支MyBranch
git checkout MyBranch #切換到分支MyBranch
git checkout -b MyBranch #創(chuàng)建并切換到分支MyBranch
分支管理2-刪除/查看分支(branch)
git branch -d MyBranch #刪除MyBranch分支
git branch #查看當(dāng)前分支
分支管理3-合并分支/解決沖突(merge)
git merge MyBranch #將MyBranch合并到當(dāng)前分支
#注:如果可能Git會(huì)用Fast forward模式,這種模式下刪除分支后祈餐,會(huì)丟掉分支信息擂啥。
git merge --no-ff -m "merge with no-ff" MyBranch #將MyBranch合并到當(dāng)前分支
#注:`--no-ff`強(qiáng)制禁用Fast forward模式,Git會(huì)在merge時(shí)生成一個(gè)新的commit帆阳,這樣哺壶,從分支歷史上就可以看出分支信息。
leodeMacBook-Pro:LearnGit leo$ git checkout master #切回master分支
leodeMacBook-Pro:LearnGit leo$ git merge MyBranch #將MyBranch合并到master
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.
leodeMacBook-Pro:LearnGit leo$
合并分支時(shí)README.md文件發(fā)生沖突蜒谤,必須手動(dòng)解決沖突后再commit山宾。
用git status
也可以查看沖突的文件:
leodeMacBook-Pro:LearnGit leo$ git status
On branch master
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: README.md
no changes added to commit (use "git add" and/or "git commit -a")
leodeMacBook-Pro:LearnGit leo$
打開README.md文件查看內(nèi)容:
class ScanViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
<<<<<<< HEAD
print("Master -> viewDidLoad")
=======
print("MyBranch -> viewDidLoad")
>>>>>>> MyBranch
}
}
Git用<<<<<<<,=======鳍徽,>>>>>>>標(biāo)記出不同分支的內(nèi)容资锰,我們修改如下后保存:
class ScanViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
print("Master -> viewDidLoad")
}
}
再提交
git add README.md #添加到暫存區(qū)
git commit -m "conflict fixed" #提交到master分支
分支管理5-查看分支的合并情況(log)
git log --graph #查看分支合并圖
git log --graph --pretty=oneline --abbrev-commit #查看本次分支的合并情況
leodeMacBook-Pro:LearnGit leo$ git log --graph --pretty=oneline --abbrev-commit
* 6deee3e Fix conflicts
|\
| * de23acd MyBranch
* | 76c6451 master
|/
* 873c772 ..
leodeMacBook-Pro:LearnGit leo$
分支管理6-創(chuàng)建BUG分支(stash)
情景:當(dāng)你接到一個(gè)修復(fù)緊急bug的任務(wù)時(shí),需要?jiǎng)?chuàng)建一個(gè)分支來工作阶祭。但是绷杜,你當(dāng)前正在MyBranch分支上進(jìn)行工作,而且工作只進(jìn)行到一半還沒法提交濒募。
這時(shí)鞭盟,我們就需要用stash
功能,將當(dāng)前工作現(xiàn)場“儲(chǔ)藏”起來瑰剃,等bug解決了再恢復(fù)現(xiàn)場繼續(xù)工作懊缺。
git stash #把當(dāng)前工作現(xiàn)場“儲(chǔ)藏”起來
#注:`stash`后,用`git status`查看工作區(qū)是干凈的培他,因此可以創(chuàng)建分支來修復(fù)bug了鹃两。
- 創(chuàng)建bug分支 -> 解決bug -> 解決完畢 -> 合并到主分支 -> 刪除bug分支
當(dāng)bug解決完畢后需要切回到原來的MyBranch分支繼續(xù)工作:
git checkout MyBranch #切回到MyBranch分支
git stash list #查看被儲(chǔ)藏的工作區(qū)
git stash apply stash@{0} #恢復(fù)指定的工作區(qū)
git stash drop stash@{0} #刪除指定的stash內(nèi)的記錄
or
git stash pop stash@{0} #恢復(fù)的同時(shí)把stash內(nèi)的指定記錄也刪了
分支管理7-推送分支(push)
git remote #查看遠(yuǎn)程倉庫的信息
git remote -v #查看遠(yuǎn)程倉庫的更詳細(xì)信息
git push origin master #將本地master分支推送到遠(yuǎn)程庫對(duì)應(yīng)的遠(yuǎn)程分支
git push origin MyBranch #將本地MyBranch分支推送到遠(yuǎn)程庫對(duì)應(yīng)的遠(yuǎn)程分支
分支管理8-獲取分支(pull)
pull之前必須要先克隆:
git clone git@github.com:leo-lp/LearnGit.git
注:此時(shí)你只能看到本地的master分支舀凛,如果你想看到其他分支必須創(chuàng)建遠(yuǎn)程origin的MyBranch到本地:
git checkout -b MyBranch origin/MyBranch
抓取分支
git pull #把最新的提交從origin/dev抓下來
#注:第一次抓取的時(shí)候有可能會(huì)報(bào)以下錯(cuò)誤:
remote: Counting objects: 1, done.
remote: Compressing objects: 100% (1/1), done.
remote: Total 1 (delta 0), reused 1 (delta 0)
Unpacking objects: 100% (1/1), done.
From github.com:leo-lp/LearnGit
fc338631..201bea8 MyBranch -> origin/MyBranch
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details
git pull <remote> <branch>
If you wish to set tracking information for this branch you can do so with:
git branch --set-upstream dev origin/<branch>
這是因?yàn)楸镜豈yBranch分支與遠(yuǎn)程origin/MyBranch分支沒有關(guān)聯(lián)俊扳,根據(jù)提示設(shè)置關(guān)聯(lián):
git branch --set-upstream MyBranch origin/MyBranch #設(shè)置MyBranch和origin/MyBranch的鏈接
標(biāo)簽管理1-創(chuàng)建標(biāo)簽(tag)
git tag v1.0 #打一個(gè)標(biāo)簽v1.0
git tag #查看所有標(biāo)簽
對(duì)歷史提交的版本打一個(gè)標(biāo)簽
git log --pretty=oneline --abbrev-commit #找到歷史提交的commit id
git tag v1.0 6279237 #對(duì)commit id為6279237的版本打標(biāo)簽
git tag #查看所有標(biāo)簽
git tag -a v1.0 -m "version 1.0 released" #創(chuàng)建帶有說明的標(biāo)簽
#注:`-a`指定標(biāo)簽名,`-m`指定說明文字猛遍。
git show v1.0 #查看標(biāo)簽v1.0的信息
標(biāo)簽管理2-操作標(biāo)簽(tag)
git push origin v1.0 #將標(biāo)簽v1.0推送到遠(yuǎn)程
git push origin --tags #將全部尚未推送的標(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在適當(dāng)?shù)牡胤斤@示不同的顏色
配置別名:
git config --global alias.co checkout #為checkout配置別名co
git config --global alias.ci commit #為commit配置別名ci
git config --global alias.br branch #為branch配置別名br
git config --global alias.st status #為status配置別名st
忽略特殊文件(.gitignore)
在Git工作區(qū)的根目錄下創(chuàng)建一個(gè).gitignore
文件馋记,然后把要忽略的文件名填進(jìn)去,Git就會(huì)自動(dòng)忽略這些文件懊烤。
GitHub也為我們準(zhǔn)備了各種配置文件:https://github.com/github/gitignore