簡介
分布式版本控制系統與集中式版本控制系統最大的區別就是它沒有“中央服務器”;每個人的電腦上都是一個完整的版本庫,同事之間只需要將自己的修改推送給對方,就可以互相看到對方的修改了。
不過在實際使用Git的時候,其實很少在兩個人之間的電腦互推。通常也有一臺充當“中央服務器”的電腦,這個服務器僅僅是用來方便同步大家的修改。
安裝Git
因為Xcode自帶的有Git所以就不在介紹了。
創建版本庫(repository)
git init #創建一個空的倉庫
注:init
后用ls -ah
命令可以看到當前目錄下多了一個.git
隱藏目錄。這個目錄是Git用來跟蹤管理版本庫的,不要隨意手動修改這個目錄里的任何文件。
把文件添加到版本庫(add)
git add . #把當前目錄下的所有文件添加到倉庫
注:add只是把文件修改添加到暫存區
把文件提交到倉庫(commit)
git commit -m "日志消息"
注:commit是把暫存區里的修改提交到當前分支
查看版本庫當前的狀態(status)
git status
查看文件修改(diff)
git diff README.md
git diff HEAD -- README.md #查看README.md文件在工作區和版本庫里面最新版本的區別
查看歷史記錄(log)
git log #顯示從最近到最遠的提交日志
git log --pretty=oneline #只顯示版本號和修改內容
回退版本(reset)
git reset --hard HEAD^ #回退到上一個版本
#注:當你回退到了某個版本后,又想恢復到新版本怎么辦?想回到新版本必須找到新版本的版本號。我們可以用`git reflog`來查詢。
git reflog #查詢每次提交的id
git reset --hard 3637964 #3637964是最新版本的版本號
撤銷暫存區的修改(reset)
git reset HEAD README.md #把暫存區的修改撤銷掉,重新放回工作區
撤銷工作區的修改(checkout)
git checkout -- README.md #把README.md文件在“工作區”的修改全部撤銷
#注:`--`一定要有,沒有`--`就變成了“切換到另一個分支”的命令
刪除文件(rm)
git rm README.md #刪除暫存區、工作區和分支上的文件
git rm --cached README.md #刪除暫存區和分支上的文件;工作區里的文件保留
遠程倉庫1-配置SSH Key:以GitHub為例
由于本地Git倉庫和GitHub倉庫之間的傳輸是通過SSH加密的,所以,需要一點設置:
第1步:創建SSH Key。在用戶主目錄下Finder前往~/.ssh
,看看有沒有.ssh
目錄如果有,再看看這個目錄下有沒有id_rsa和id_rsa.pub這兩個文件,如果已經有了,可直接跳到第2步。如果沒有就用以下命令創建
ssh-keygen -t rsa -C "youremail@example.com" #把郵件換成你自己的郵件地址,然后一路回車,無需設置密碼
#注:`.ssh`里有`id_rsa `和`id_rsa.pub `兩個文件,`id_rsa `是私鑰不能泄露出去,`id_rsa.pub `是公鑰,可以放心地告訴任何人。
第2步:登陸GitHub,打開“Settings”,“SSH and GPG keys”頁面:然后,點“New SSH Key”,填上任意Title,在Key文本框里粘貼id_rsa.pub文件的內容:然后點擊“Add SSH Key”,你就應該看到已經添加的Key:
遠程倉庫2-關聯和推送:以GitHub為例
情景:我們先有本地Git倉庫,后有遠程倉庫,需要將本地和遠程倉庫關聯。
第1步:關聯遠程倉庫(假如你在GitHub上已經新建了一個倉庫LearnGit)。
git remote add origin git@github.com:leo-lp/LearnGit.git
#注:把上面的`leo-lp`替換成你自己的GitHub賬戶名。
第2步:把本地庫的所有內容推送到遠程庫。
git push -u origin master #把當前分支master推送到遠程
#注:`-u`不但會把本地的master推送到遠程master分支,還會把本地的master和遠程的master關聯起來。第一次推時需要,以后再推/拉時就可以簡化了。
第一次推送有可能報以下錯誤:
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$
造成這個錯誤的原因是Git倉庫中已經有一部分代碼,所以它不允許你直接把你的代碼推送上去。于是我們有2個選擇方式:
1.強推,用你本地的代碼替代Git倉庫內的內容:
git push -f origin master #注:會覆蓋遠程倉庫里的內容
2.把服務器上的內容合并到本地在推送:git pull
可是這時又報錯了。
leodeMacBook-Pro:LearnGit leo$ git pull
fatal: refusing to merge unrelated histories
leodeMacBook-Pro:LearnGit leo$
這時我們需要用以下兩個命令配置.git/config
文件:
git config branch.master.remote origin #當本地是masterf分支, 默認的remote就是origin
git config branch.master.merge refs/heads/master #當本地是master分支使用git pull時,沒有指定remote分支,那么git就會采用默認的origin來merge在master分支上所有的改變
這時我們已經可以正常的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$
遠程倉庫3-克隆:以GitHub為例
情景:我們需要從零開發,那么最好的方式是先創建遠程倉庫,然后克隆。
第1步:登錄GitHub新建一個倉庫LearnGit。
第2步:克隆到本地:
git clone git@github.com:leo-lp/LearnGit.git
分支管理1-創建/切換分支(branch/checkout)
git branch MyBranch #創建分支MyBranch
git checkout MyBranch #切換到分支MyBranch
git checkout -b MyBranch #創建并切換到分支MyBranch
分支管理2-刪除/查看分支(branch)
git branch -d MyBranch #刪除MyBranch分支
git branch #查看當前分支
分支管理3-合并分支/解決沖突(merge)
git merge MyBranch #將MyBranch合并到當前分支
#注:如果可能Git會用Fast forward模式,這種模式下刪除分支后,會丟掉分支信息。
git merge --no-ff -m "merge with no-ff" MyBranch #將MyBranch合并到當前分支
#注:`--no-ff`強制禁用Fast forward模式,Git會在merge時生成一個新的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$
合并分支時README.md文件發生沖突,必須手動解決沖突后再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文件查看內容:
class ScanViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
<<<<<<< HEAD
print("Master -> viewDidLoad")
=======
print("MyBranch -> viewDidLoad")
>>>>>>> MyBranch
}
}
Git用<<<<<<<,=======,>>>>>>>標記出不同分支的內容,我們修改如下后保存:
class ScanViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
print("Master -> viewDidLoad")
}
}
再提交
git add README.md #添加到暫存區
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-創建BUG分支(stash)
情景:當你接到一個修復緊急bug的任務時,需要創建一個分支來工作。但是,你當前正在MyBranch分支上進行工作,而且工作只進行到一半還沒法提交。
這時,我們就需要用stash
功能,將當前工作現場“儲藏”起來,等bug解決了再恢復現場繼續工作。
git stash #把當前工作現場“儲藏”起來
#注:`stash`后,用`git status`查看工作區是干凈的,因此可以創建分支來修復bug了。
- 創建bug分支 -> 解決bug -> 解決完畢 -> 合并到主分支 -> 刪除bug分支
當bug解決完畢后需要切回到原來的MyBranch分支繼續工作:
git checkout MyBranch #切回到MyBranch分支
git stash list #查看被儲藏的工作區
git stash apply stash@{0} #恢復指定的工作區
git stash drop stash@{0} #刪除指定的stash內的記錄
or
git stash pop stash@{0} #恢復的同時把stash內的指定記錄也刪了
分支管理7-推送分支(push)
git remote #查看遠程倉庫的信息
git remote -v #查看遠程倉庫的更詳細信息
git push origin master #將本地master分支推送到遠程庫對應的遠程分支
git push origin MyBranch #將本地MyBranch分支推送到遠程庫對應的遠程分支
分支管理8-獲取分支(pull)
pull之前必須要先克隆:
git clone git@github.com:leo-lp/LearnGit.git
注:此時你只能看到本地的master分支,如果你想看到其他分支必須創建遠程origin的MyBranch到本地:
git checkout -b MyBranch origin/MyBranch
抓取分支
git pull #把最新的提交從origin/dev抓下來
#注:第一次抓取的時候有可能會報以下錯誤:
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>
這是因為本地MyBranch分支與遠程origin/MyBranch分支沒有關聯,根據提示設置關聯:
git branch --set-upstream MyBranch origin/MyBranch #設置MyBranch和origin/MyBranch的鏈接
標簽管理1-創建標簽(tag)
git tag v1.0 #打一個標簽v1.0
git tag #查看所有標簽
對歷史提交的版本打一個標簽
git log --pretty=oneline --abbrev-commit #找到歷史提交的commit id
git tag v1.0 6279237 #對commit id為6279237的版本打標簽
git tag #查看所有標簽
git tag -a v1.0 -m "version 1.0 released" #創建帶有說明的標簽
#注:`-a`指定標簽名,`-m`指定說明文字。
git show v1.0 #查看標簽v1.0的信息
標簽管理2-操作標簽(tag)
git push origin v1.0 #將標簽v1.0推送到遠程
git push origin --tags #將全部尚未推送的標簽推送到遠程
git tag -d v1.0 #刪除本地標簽v1.0
git push origin :refs/tags/v1.0 #刪除遠程標簽v1.0
Git的常用配置
git config --global color.ui true #讓Git在適當的地方顯示不同的顏色
配置別名:
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工作區的根目錄下創建一個.gitignore
文件,然后把要忽略的文件名填進去,Git就會自動忽略這些文件。
GitHub也為我們準備了各種配置文件:https://github.com/github/gitignore