Git概述 | ① 什麼是版本管理系統 | ② Git和SVN的區別 |
③ Git的四個組成部分 | ④ Git中文件的幾個狀態 | |
⑤ Git中的四類對象 | ||
Git下載安裝配置 | ||
Git本地基本操做 | ① 配置「git config」 | ② 獲取幫助「git help」 |
③ 建立Git倉庫「git init」 | ||
④ 添加文件到暫存區「git add」 | ||
⑤ 讓Git不跟蹤特定文件「.gitignore文件」 | ||
⑥ 暫存區內容提交到本地倉庫「git commit」 | ||
⑦ 查看工做區與暫存區狀態「git status」 | ||
⑧ 內容變化,差別對比「git diff」 | ||
⑨ 查看歷史提交記錄「git log」 | ||
⑩ 查看某個文件的改動記錄「git blame」 | ||
⑪ 設置Git命令別名「git config --global alias」 | ||
⑫ 爲重要提交打標籤「git tag」 | ||
Git文件恢復與版本回退 | ① 文件恢復,未add「git checkout」 | |
② 文件恢復,已add未commit「git reset HEAD」 | ||
③ 版本回退,已commit「git reset --hard」 | ||
④ 查看輸入過的指令記錄「git reflog」 | ||
⑤ 撤銷某次提交「git revert」 | ||
⑥ 查看某次提交的修改內容「git show」 | ||
⑦ 查看分支最新commit的Hash值「git rev-parse」 | ||
⑧ 找回丟失對象的最後一點但願「git fsck」 | ||
Git本地分支 | ① 分支的概念 | ② 建立其餘分支的緣由 |
③ 一個簡單的分支管理策略 | ||
④ 分支的建立於切換「git branch」 | ||
⑤ 分支合併「git merge」 VS 「git rebase」 | ||
⑥ 解決合併衝突 | ⑦ 刪除分支 | |
⑧ 恢復誤刪分支「git log --branches」 | ⑨ 分支重命名 | |
⑩ 切換分支時暫存未commit的更改「git stash」 | ||
⑪ 把commit從一個分支挪到另外一個分支「git cherry-pick」 | ||
Git遠程倉庫 | ① 遠程倉庫概述 | |
② 本地倉庫與遠程倉庫創建關聯「git remote」 | ||
③ 推送本地倉庫到遠程倉庫「git push」 | ||
④ 克隆遠程倉庫「git clone」 | ||
⑤ 同步遠程倉庫更新「git fetch」VS「git pull」 | ||
⑥ git push 時的unrelated history問題 | ||
⑦ SSH Key避免每次push重複輸入帳號密碼 | ||
Git工做流 | ① 集中式工做流 | ② 功能分支工做流 |
③ Gitflow工做流 | ④ Forking工做流 | |
⑤ Pull Request工做流 | ||
其餘雜項 | ① 爲開源項目貢獻代碼 | ② SourceTree使用詳解 |
瞭解Git相關的概念,有助於後續命令的掌握~html
VCS(Version Control System),一種用於記錄一個或多個文件內容變化 歷史,以便未來能對特定版本的歷史記錄進行查看,更改,備份還原的系統。 能夠簡單類比爲「遊戲存檔」,打Boss前存下檔,沒過關,從新讀檔; 分支劇情,想體驗不一樣選擇觸發的不一樣劇情,能夠存多個檔, 想玩哪一個讀哪一個。linux
VCS通常分爲下述三類:git
使用簡單的數據庫來記錄文件的歷史更新差別,好比RCS。github
用一個服務器來保存全部文件的修訂版本,協同工做的人鏈接這個服務器, 獲取或提交文件更新,好比SVN。算法
這種協同方式有個兩個明顯的缺點: 1.「須要聯網」:同步和推送更新速度受帶寬限制,內網還好,外網可能會有點慢了(大文件); 2.「依賴中央服務器」:每一個人的本地只有之前所同步的版本,若是服務器宕(dang)機了,誰都沒法獲取或提交更新。shell
每一個用戶擁有完整的提交歷史,支持離線提交更改,查看歷史提交記錄等。中央服務器更多的只是用做更改合併,同步的工具,好比Git。數據庫
從根本上來講,Git是一個內存尋址的文件系統,根據文件的Hash值來定位文件。 這個40位的Hash值使用SHA1算法生成,由兩部分拼接: header = "<type>" + content.length + "\0" (參數依次爲:對象類型,數據字節長度,空字節(用於分隔header與content) hash = sha1(header+content),這裏的拼接是二進制級別的拼接,而非字符串拼接。vim
Git和SVN除了上面說的聯網需求不一樣外,還有「存儲差別」:windows
SVN關心:文件內容的具體差別;而Git關心:文件總體是否發生改變。 SVN每次提交記錄的是:「哪些文件進行了修改,修改了哪些行的哪些內容」。緩存
如圖,Version 2中記錄的是文件A和C的變化,而Version 3中記錄文件C的變化,以此類推; 而Git中,並不保存這些先後變換的差別數據,而是保存整個緩存區中的全部文件, 又稱快照,「有變化的文件保存,沒變化的文件不保存,而是對上次保存的快照作一個連接」, 由於這種不一樣的保存方式,使得Git切換分支的速度比SVN快上很多。
固然SVN也有它的優勢,好比「權限控制」,能夠設定每一個帳戶的讀寫權限,而Git中 則沒有響應的權限控制。至於用哪一個的,仍是看公司要求吧~
簡單說下Git的四個組成部分:
接下來講下這幾個部分是如何協同工做的:
工做區與暫存區:工做區更改,經過git add命令能夠把更改提交到暫存區; 也能夠git checkout命令使用暫存區內容覆蓋當前的工做區的內容。
暫存區與本地倉庫:能夠經過git commit命令把暫存區的內容提交到本地倉庫, 每次commit都會生成一個快照,快照使用Hash值編號。能夠經過git reset Hash值, 把某個快照還原到暫存區中。
工做區和本地倉庫:經過git checkout 快照編號,直接把某個快照還原到工做區中。
本地倉庫和遠程倉庫:能夠經過git push命令把commit推送到遠程倉庫,多人協做的 時候可能還須要進行一些衝突處理;還有經過git clone拉取某個遠程倉庫的項目到本地, 或經過git fetch拉取遠程倉庫的最新內容,檢查後決定是否合併到本地倉庫中。
工做區和遠程倉庫:這裏二者的協做通常是git pull,即把遠程主機的最新內容拉取下來後直接合並。
按照大類劃分,能夠分爲兩種狀態:Tracked(已跟蹤)和Untracked(未跟蹤), 依據是:「該文件是否已加入版本控制」?
文件狀態變化週期流程圖:
流程簡述:
假設某個項目已加入Git版本控制系統
Untracked
狀態;Tracked
狀態又或者說 此時這個文件已經被版本控制系統所跟蹤,並且他處於Staged
**(暫存)狀態;Unmodified
(未修改)狀態;Modified
**(修改)狀態;在Git系統中有四種類型的對象,幾乎全部的Git操做都是在這四種對象上進行的,依次爲: Blob
(塊)對象,Tree
(樹)對象,Commit
(提交)對象,Tag
(標籤)對象。 前三者的關係如圖所示:
接着咱們來詳解的講解這四類對象:
① 塊對象(Blob)
一塊二進制數據,「僅存放文件內容」,不包括文件名、權限等信息。Git會根據文件內容計算 出一個Hash值,以這個Hash值做爲文件索引保存起來。意味着,相同文件內容的文件,只會保存 一個,即共享同一個Blob對象。可使用:
git hash-object 文件名
來計算文件內容的Hash值。 若是你知道已經添加到Git中的某個文件的hash值,還能夠經過git cat-file hash值
來讀取數據 對象,可選參數:-p
(查看Git對象內容) ,-t
(查看Git對象類型),示例以下:
② 樹對象(Tree)
保存一個或多個塊對象的引用,每次commit對應一個樹對象,這裏生成一個commit, 而後調用**
git ls-tree Hash值
** 查看樹對象的內容:
利用上面的 git cat-file -p hash值
來查看blob塊的具體內容:
除了保存塊對象的引用外,樹對象還能夠引用「其餘樹對象」,從而構成一個「目錄層次結構」。 新建一個test目錄,複製一個1.txt文件到這個路徑下,提交一個commit,而後查看樹對象的內容:
能夠指向了另外一個tree對象,這個tree對象指向另外一個1.txt文件,樹對象解決了文件名的問題。 而對於提交的人、時間、說明信息等,咱們還須要經過提交對象進行了解。
③ 提交對象(Commit)
保存樹對象的Hash值,父Commit的Hash值,提交做者、時間、說明信息。 一樣可使用**
git cat-file
**命令查看commit對象:
④ 標籤對象(Tag)
通常會對某次重要的commit加TAG,以示重要,分爲兩種狀況:
.git/refs/tags/標籤名
,裏面保存TAG對象的引用。這裏爲咱們上面的兩個commit一次打上兩種標籤,而後看下具體的結果:
sudo apt-get install git
安裝便可。brew install git
進行安裝。安裝完後,使用Git還須要進行環境的配置,配置信息保存在gitconfig文件中,有三種級別:
C:\Program Files\Git\mingw64\etc\gitconfig
, 不一樣的系統可能不同,你能夠經過:git config -e --system
,底部能夠找到配置文件的路徑:
C:/Users/當前用戶/.gitconfig
, 一樣能夠採用上面的:git config -e --global
查看配置文件的位置。項目路徑/.git/config
配置生效優先級:local > global > system,經常使用命令:
# 配置
git config --global user.name "用戶名" # 配置用戶名
git config --global user.email "用戶郵箱" # 配置郵箱
git config --global core.editor 編輯器 # 配置編輯器,模式使用vi或者vim
# 查看配置
git config --global user.name # 查看配置的用戶名
git config --global user.email # 查看配置的郵箱
# 查看全部配置列表
git config --global --list # 查看全局設置相關參數列表
git config --local --list # 查看本地設置相關參數列表
git config --system --list # 查看系統配置參數列表
git config --list # 查看全部Git的配置(全局+本地+系統)
複製代碼
除了命令行的方式外,你還能夠直接去編輯對應的配置文件。
git help 命令 # 查看某個git命令的介紹,用法
git 命令 --help # 另外一種寫法
複製代碼
git init 倉庫名 # 建立一個新的帶Git倉庫的項目
git init # 爲已存在的項目生成一個Git倉庫
複製代碼
git add 文件名 # 將工做區的某個文件添加到暫存區。
git add -u # 添加全部被tracked文件中被修改或刪除的文件信息到暫存區,不處理untracked的文件
git add -A # 添加全部被tracked文件中被修改或刪除的文件信息到暫存區,包括untracked的文件
git add . # 將當前工做區的全部文件都加入暫存區
git add -i # 進入交互界面模式,按需添加文件到緩存區
複製代碼
不少人應該沒用過交互界面模式,這裏演示下用法:
流程簡述:
當咱們使用git add命令把未標記的文件添加到緩存區後,Git就會開始跟蹤這個文件。 對於一些好比:自動生成的文件,日誌,臨時編譯文件,應用簽名文件等,就不必進行跟蹤了, 咱們能夠編寫一個**「.gitignore文件」,把不須要跟蹤的文件和文件夾寫上,git就不會去 跟蹤這些文件了,另外:.gitignore文件與.git文件夾在同級目錄下**。
若是不想本身寫這個文件,能夠到 github.com/github/giti… 選擇對應的模板,複製粘貼。 也能夠自行編寫,支持簡化了的真這個表達式(規範與示例模板摘自:Git王者超神之路)
*
: 匹配零個或多個任意字符[abc]
:只匹配括號內中的任意一個字符[0-9]
:表明範圍,匹配0-9之間的任何字符?
:匹配任意一個字符**
:匹配任意的中間目錄,例如a/*/z能夠匹配:a/z,a/b/z,a/b/c/z等模板示例:
# 忽略全部以 .c結尾的文件
*.c
# 可是 stream.c 會被git追蹤
!stream.c
# 只忽略當前文件夾下的TODO文件, 不包括其餘文件夾下的TODO例如: subdir/TODO
/TODO
# 忽略全部在build文件夾下的文件
build/
# 忽略 doc/notes.txt, 但不包括多層下.txt例如: doc/server/arch.txt
doc/*.txt
# 忽略全部在doc目錄下的.pdf文件
doc/**/*.pdf
複製代碼
有一點要特別注意!!!!
配置.gitignore只對那些沒有添加到版本控制系統的文件生效(未Tracked的文件)!
舉個簡單的例子:
有A,B兩個文件,你先把他兩個add了,而後在.gitignore文件中 配置了不跟蹤這兩個文件,可是你會發現根本不會生效。
git add A
git add B
# 配置不跟蹤A和B
git add .gitignore
複製代碼
因此,最好的作法就是在項目剛開始的時候,先添加.gitignore文件。 固然,即便是發生了,仍是有解決方法的,能夠鍵入下述命令清除標 記狀態,而後先添加.gitignore,再添加文件便可:
git rm -r --cached . # 清除版本控制標記,.表明全部文件,也可指定具體文件
複製代碼
另外,若是你用的IDEA系列的代碼編輯器,能夠安裝一個「.ignore」的插件,手動 勾選不須要跟蹤的文件,直接生成.gitignore文件。
git commit -m "提交說明" # 將暫存區內容提交到本地倉庫
git commit -a -m "提交說明" # 跳過緩存區操做,直接把工做區內容提交到本地倉庫
複製代碼
若是不加-m 「提交說明」,git會讓用你讓默認編輯器(vi或vim)來編寫提交說明。 除此以外,有時可能想修改上次提交的內容:提交說明,修改文件等:
# 合併暫存區和最近的一次commit,生成新的commit並替換掉老的。若是緩存區沒內容,
# 利用amend能夠修改上次commit的提交說明。
#
# 注:由於amend後生成的commit是一個全新的commit,舊的會被刪除,因此別在公共的
# commit上使用amend!切記!!!
git commit --amend
git commit --amend --no-edit # 沿用上次commit的提交說明
複製代碼
git status # 查看工做區與暫存區的當前狀況
git status -s # 讓結果以更簡短的形式輸出
複製代碼
git diff # 工做區與緩存區的差別
git diff 分支名 # 工做區與某分支的差別,遠程分支這樣寫:remotes/origin/分支名
git diff HEAD # 工做區與HEAD指針指向的內容差別
git diff 提交id 文件路徑 # 工做區某文件當前版本與歷史版本的差別
git diff --stage # 工做區文件與上次提交的差別(1.6 版本前用 --cached)
git diff 版本TAG # 查看從某個版本後都改動內容
git diff 分支A 分支B # 比較從分支A和分支B的差別(也支持比較兩個TAG)
git diff 分支A...分支B # 比較兩分支在分開後各自的改動
# 注:若是隻想統計哪些文件被改動,多少行被改動,能夠添加--stat參數
複製代碼
git log # 查看全部commit記錄(SHA-A校驗和,做者名稱,郵箱,提交時間,提交說明)
git log -p -次數 # 查看最近多少次的提交記錄
git log --stat # 簡略顯示每次提交的內容更改
git log --name-only # 僅顯示已修改的文件清單
git log --name-status # 顯示新增,修改,刪除的文件清單
git log --oneline # 讓提交記錄以精簡的一行輸出
git log –graph –all --online # 圖形展現分支的合併歷史
git log --author=做者 # 查詢做者的提交記錄(和grep同時使用要加一個--all--match參數)
git log --grep=過濾信息 # 列出提交信息中包含過濾信息的提交記錄
git log -S查詢內容 # 和--grep相似,S和查詢內容間沒有空格
git log fileName # 查看某文件的修改記錄,找背鍋專用
複製代碼
除此以外,還能夠經過 –pretty 對提交信息進行定製,好比:
更多規則與定製以下(更多可參見:Viewing the Commit History) format對應的經常使用佔位符:(注:做者是指最後一次修改文件的人,提交者是提交該文件的人)
佔位符 | 說明 | 佔位符 | 說明 |
---|---|---|---|
%H |
提交對象(commit)的完整哈希字串 | %h |
提交對象的簡短哈希字串 |
%T |
樹對象(tree)的完整哈希字串 | %t |
樹對象的簡短哈希字串 |
%P |
父對象(parent)的完整哈希字串 | %p |
父對象的簡短哈希字串 |
%an |
做者(author)的名字 | %ae |
做者的電子郵件地址 |
%ad |
做者修訂日期(能夠用 –date= 選項定製格式) | %ar |
按多久之前的方式顯示 |
%cn |
提交者(committer)的名字 | %ce |
提交者的電子郵件地址 |
%cd |
提交日期 | %cr |
提交日期,按多久之前的方式顯示 |
%s |
提交說明 |
一些其餘操做:
選項 | 說明 |
---|---|
-p |
按補丁格式顯示每一個更新之間的差別 |
–stat |
顯示每次更新的文件修改統計信息(行數) |
–shortstat |
只顯示 –stat 中最後的行數修改添加移除統計 |
–name-only |
僅在提交信息後顯示已修改的文件清單 |
–name-status |
顯示新增、修改、刪除的文件清單 |
–abbrev-commit |
僅顯示 SHA-1 的前幾個字符,而非全部的 40 個字符 |
–relative-date |
使用較短的相對時間顯示(好比,「2 weeks ago」) |
–graph |
顯示 ASCII 圖形表示的分支合併歷史 |
–pretty |
格式定製,可選選項有:oneline,short,full,Fullerton和format(後跟指定格式) |
還有一些限制log輸出的選項:
選項 | 說明 |
---|---|
-(n) |
僅顯示最近的 n 條提交 |
–since, –after |
僅顯示指定時間以後的提交。 |
–until, –before |
僅顯示指定時間以前的提交。 |
–author |
僅顯示指定做者相關的提交。 |
–committer |
僅顯示指定提交者相關的提交。 |
–grep |
僅顯示含指定關鍵字的提交 |
-S |
僅顯示添加或移除了某個關鍵字的提交 |
git blame 文件名 # 查看某文件的每一行內容的做者,最新commit和提交時間
複製代碼
這裏爲了演示,先修改一波做者用戶名和郵箱,而後往1.txt中新增內容:
Tip:若是你用的IDEA系列的編譯器,右鍵行號,選擇Annotate也能夠實現一樣的效果。如:
在終端使用Git命令的時候,雖然能夠經過按兩次tab來自動補全。可是有些命令比較經常使用, 每次都要敲完就顯得有些繁瑣了,能夠爲這些命令起一個簡單的別名,好比: status爲st,checkout爲co ; commit爲ci ; branch爲br等,設置示例以下:
git config --global alias.st status
複製代碼
別名的設置保存在git的配置文件中:
對於某些提交,咱們能夠爲它打上Tag,表示此次提交很重要, 好比爲一些正式發佈大版本的 commit,打上TAG,當某個版本出問題了,經過TAG能夠快速找到這次提交對應的Hash值, 直接切換到這次版本的代碼去查找問題,比起一個個commit找省事多了。
Git中的標籤分爲兩種:輕量級標籤 和 附加標籤,命令以下:
git tag 標記內容 # 輕量級標籤
git tag -a 標記內容 -m "附加信息" # 附加標籤
複製代碼
若是想爲以前某次commit打TAG,能夠找出這次提交的Hash值,添加-a選項,示例以下:
git tag -a 標記內容 版本id # 好比:git tag -a v1.1 bcfed96
複製代碼
另外,git push 的時候默認不會把標籤推送到遠程倉庫,若是想把標籤頁推送到遠程倉庫,能夠:
git push origin 標記內容 # 推送某標籤到遠程倉庫
git push origin --tags # 刪除全部本地倉庫中不存在的TAG
複製代碼
除此以外還有下述常規操做:
git checkout -b 分支名 標記內容 # 新建分支的時候打上TAG
git show 標記內容 # 查看標籤對應的信息
git tag -d 標記內容 # 刪除本地TAG
git push origin --delete tag 標記內容 # 刪除遠程TAG
複製代碼
若是在工做區直接刪除已經被Git Tracked的文件,暫存區中還會存在此文件:
Git告訴你,工做區的文件被刪除了,你有兩種可選操做:「刪除緩存區文件」 或 「恢復被刪文件」:
# 刪除暫存區中的文件:
git rm 文件名
git commit -m "提交說明"
# 誤刪恢復文件(用暫存區的文件覆蓋工做區的文件)
git checkout -- 文件名
# Tip:git rm 等價於 git rm --cached 文件名 + rm 文件名
# 務必注意:git checkout會拋棄當前工做區的更改!!!不可恢復!!!務必當心!!!
複製代碼
若是更改已經add到暫存區中,想恢復原狀,能夠執行下述命令:
git reset HEAD 文件名
git checkout 文件名
複製代碼
文件已經commit,想恢復未上次commit的版本或者上上次,能夠:
git reset HEAD^ # 恢復成上次提交的版本
git reset HEAD^^ # 恢復成上上次提交的版本,就是多個^,以此類推或用
git reset HEAD~3 # 也能夠直接~次數
git reset --hard 版本號 # git log查看到的Hash值,取前七位便可,根據版本號回退
複製代碼
reset命令的做用其實就是:重置HEAD指針,讓其指向另外一個commit,而這個動做可能會對 緩存區形成影響,舉個例子:
原本的分支線:- A - B - C (HEAD, master),git reset B後:- A - B (HEAD, master) 解釋:看不到C了,可是他仍是存在的,能夠經過git reset C版本號找回,前提是 C沒有被Git當作垃圾處理掉(通常是30天)。
reset提供了三個可選參數:
Git會記住你輸入的每一個Git指令,好比上面的git reset 切換成一箇舊的commit,而後 git log後發現新提交的記錄沒了,想切換回新的那次commit, 能夠先調git reflog 獲取新commit的Hash值,而後git reset 回去。
git reflog
複製代碼
注:指令記錄不會永久保存!Git會定時清理用不到的對象!!!
有時可能咱們想撤銷某次提交所作的更改,可使用revert命令
git revert HEAD # 撤銷最近的一個提交
git revert 提交的Hash值 # 撤銷某次commit
複製代碼
注意!!!
不是真的把提交給撤銷了,而是生成一個新的提交來覆蓋舊的提交,被撤銷的提交 和新的提交記錄都會保存!!!若是不信的話,你能夠再鍵入git revert HEAD, 會發現被撤銷的更改又變回來了。簡單點說:「撤銷的只是文件變化,提交記錄依舊存在」。
git show 提交Hash值 # 查看某次commit的修改內容
複製代碼
git rev-parse 分支名 # 查看分支最新commit的Hash值,也能夠直接寫HEAD
複製代碼
由於你的某次誤操做致使commit丟失,若是git reflog都找不到,你可使用git fsck,找到丟失 的對象的版本Hash值,而後恢復便可。
git fsck --lost-found
複製代碼
分支並非Git對象,和輕量級的TAG對象相似,只包含對commit對象的索引。只是分支更新後, 索引會替換爲最新的commit,而TAG對象建立後索引就不在變化。分支文件保存與下述兩個路徑:
當前項目/.git/refs/heads/
當前項目/.git/refs/remotes/
說到分支,必然會說起HEAD,它指向「當前工做的本地分支」,對應文件:當前項目/.git/HEAD
下面經過示例和圖解的方式幫你們理解分支:
如法炮製,提交兩次:
從上面的圖中不難發現這樣的規律:每次commit,master都會向前移動,指向最新提交。 這個時候可能有些童鞋會問:commit之間的箭頭哪來的?或者說commit怎麼串成一條線的?
答:還記得一開始介紹的commit對象嗎?裏面有一個parent的值,指向父commit的Hash值。
經過兩個常見的場景來體會建立其餘分支的必要性:
項目通常都是一步步迭代升級的,有大版本和小版本的更新: 大版本通常是改頭換面的更新,好比 UI大改,架構大改,版本是: v2.0.0這樣;小版本的更新通常是UI小改,Bug修復優化等,版本是: v2.0.11這樣;只有一條master分支,意味着:你的分支線會 很是很是的長,假如你已經發布到了 第二個大版本,而後用戶反饋第一個版本有很嚴重的BUG,這時候想切回第一個版本改BUG, 而後改完BUG切回第二個大版本,想一想也是夠嗆的。 (PS:可能你說我能夠對重要的commit打tag, 而後找到這個tag 切回去,固然也行這裏是想告訴你引入其餘分支會給你帶來的便利)
若是隻有一個master分支的話,假如某次commit衝突了,而這個衝突很難解決或者解決不了, 那麼整個開發就卡在這裏,沒法繼續向後進行了。
爲了解決只有一個master分支引發的問題,能夠引入分支管理,最簡單的一種策略以下:
在master分支上開闢一個新的develop分支,而後咱們根據功能或者業務,再在develop 分支上另外開闢其餘分支,完成分支上的任務後,再將這個分支合併到develop分支上! 而後這個功能分支的任務也到此結束,能夠刪掉,而當發佈正式版後,再把develop分支 合併到master分支上,並打上TAG。
master與develop分支都做爲長期分支,而其餘建立的分支做爲臨時性分支! 簡述各個分支的劃分:
git branch 分支名 # 建立分支
git branch # 查看本地分支
複製代碼
咱們在master分支上建立一個develop分支,此時的版本線變成了這樣:
此時雖然已經建立了develop分支,可是HEAD仍是指向master,接着咱們來切換分支:
git checkout 分支名 # 切換分支
git checkout -b 分支名 # 建立分支同時切換到這個分支
複製代碼
切換到develop後,提交一次,此時的版本線:
再提交一次,而後切換爲master分支,此時的版本線:
切換回master後,提交一次,此時的版本線:
行吧,講到這裏,相信各位童鞋對Git中的分支已經有所瞭解了。
Git中,可使用「git merge」和「git rebase」兩個命令來進行分支的合併。
git merge合併分支
合併的方式分爲兩種:快速合併 和 普通合併,二者的區別在於: 「前者合併後看不出曾經作過合併,然後合併後的歷史會有分支記錄」 如圖所示:
快速合併,默認,快速合併有一個前提:「當前分支的每一個提交都在另外一個分支中」, Git不建立任何新的commit,只是將當前分支指向合併進來的分支。下面演示下快速合併, 執行git reset 切換到第四次commit,而後執行git merge develop合併master分支。
普通合併,添加**–no-ff**參數表示禁用快速合併。
另外有時會有這樣的場景:合併的分支中有不少commit記錄是無需在分支中體現的,一個commit 就夠了。能夠藉助**--squash**參數來壓縮提交,示例以下:
附:git merge的經常使用參數:
git merge -ff # 快速合併,默認參數
git merge -ff-only # 只有快速合併的狀況才合併
git merge --no-ff # 不使用快速合併
git merge -n 分支名 # 合併分支,不會在合併後顯示合併先後的不一樣狀態
git merge -stat 分支名 # 合併分支,合併結束後顯示合併先後的不一樣狀態
git merge -e 分支名 # 合併分支,合併前調用編輯器,可自行編寫commit
複製代碼
Tips: git-merge除了用來合併分支外,拉取遠程倉庫更新時也可用到(git fetch + git merge)
git reabse合併分支
rebase(衍合,變基),網上不少教程寫得很高深莫測,其實並無那麼複雜, 只是這種合併會讓樹整潔,易於跟蹤。以上面4中的結果爲例,先把master分支 和develop分支重置到最新的commit。
先走一波前面的merge合併方式:
接着再試試rebase合併方式:
Git會把每一個提交都取消掉,並把他們臨時保存爲補丁,好比通過一些衝突解決,生成新的commit, 舊的commit會被丟棄,還會被git的gc回收,這樣的結果就是一條直線的樹。
在分支的合併的時候,並非每次都能直接合並的,有時會遇到合併衝突,特別是在多人協做的時候。 出現合併衝突後,須要解決完衝突,才能繼續合併。
舉個簡單的例子,A和B在master分支上開闢出兩個分支來完成相關的功能, A作完了,把本身的分支合併到master分支,此時master分支向前移動了幾回commit, 接着B也完成了他的功能,想把本身分支合併到master分支,若是改動的文件和和A改動 的文件相同的話,此時就會合並失敗,而後須要處理完衝突,纔可以繼續合併!
接下來咱們來簡單的模擬合併衝突,先來試試merge:
merge分支後處理衝突
如圖,合併完A分支後合併B分支出現了衝突,接着鍵入:git status查看衝突的文件:
能夠看到未合併的兩個文件,1.txt和2.txt,打開其中一個文件:
<<< 和 >>>包裹着的就是衝突內容,保留本身想要的內容,處理完後刪掉<<<和>>>,修改完後:
2.txt文件也如法炮製,接着add,而後commit便可,合併結束。
rebase分支後處理衝突
如圖,A合併成功,在合併B的時候,出現了合併衝突,有三個可選的操做:
git rebase --continue # 處理完衝突後,繼續處理下一個補丁
git rebase --abort # 放棄全部的衝突處理,恢復rebase前的狀況
git rebase --skip # 跳過當前的補丁,處理下一個補丁,不建議使用,補丁部分的commit會丟失!
複製代碼
鍵入git status查看衝突文件:
接着處理1.txt文件中的衝突,解決完成後,先鍵入git add,接着鍵入git rebase --continue 處理下一個衝突:
處理接下來的衝突,直到沒有衝突爲止:
能夠看到使用rebase合併,最後的分支線是一條直線。另外,使用rebase合併中途出差錯, 可使用git rebase --abort恢復rebase前的狀態。
合併完的分支,基本沒什麼用了,可使用下述命令刪除:
git branch -d 分支名 # 刪除分支,分支上有未提交更改是不能刪除的
git branch -D 分支名 # 強行刪除分支,儘管這個分支上有未提交的更改
複製代碼
兩步:找出被刪分支最新的commit的Hash值,而後恢復分支:
git log --branches="被刪除的分支名" # 找到被刪分支最新的commit版本號
git branch 分支名 版本號(前七位便可) # 恢復被刪分支
複製代碼
有時咱們可能在某個分支上正編寫着代碼,而後有一些突發的狀況,須要 咱們暫時切換到 其餘分支上,好比要緊急修復bug,或者切換分支給同事 review代碼,此時若是直接切換 分支是會提示切換失敗的,由於這個分支 上作的更改尚未提交,你能夠直接add後commit, 而後再切換,不過咱們習慣寫完某個功能再提交,咱們想:
先暫存這個分支上的改動,切去其餘分支上搞完事,而後回來繼續 繼續在以前的改動上寫代碼。
那麼可使用:
git stash # 保存當前的改動
複製代碼
而後放心的切換分支,而後再切換回來,接着使用:
git stash apply # 恢復保存改動
複製代碼
另外有一點必定要注意!!!能夠stash多個改動!!若是你切換到另外一個分支 又stash了,而後切換回來stash apply是恢復成另外一個分支的stash!!! 若是你這樣stash了屢次的話,我建議你先鍵入:
git stash list # 查看stash列表
複製代碼
找到本身想恢復的那個
好比這裏恢復的應該是master上的stash,可使用下述命令進行恢復:
git stash apply stash@{1}
複製代碼
git branch -m 老分支名 新分支名 # 分支重命名
複製代碼
有時咱們可能須要把某個分支上的一次commit放到另外一個分支上,此時可使用git cherry-pick, 好比下面這樣兩個分支:
master分支:A -> B -> C feature分支:a -> b
如今想把feature分支上的b,放到master的後,能夠這樣操做:
在實際開發過程當中,基本都是團隊協做的形式進行,即多人一塊兒負責同一個項目,那如何共享同一份代碼並進行管理呢?能夠用到「Git遠程倉庫」。能夠本身搭建,或選擇專業的代碼託管平臺,好比:Github,Git@OSC,GitCafe,GitLab,coding.net,gitc,BitBucket,Geakit,Douban CODE 等。固然,若是有條件的話,確定是本身搭建的爽一些,可控,還能夠作一些訂製(集成編譯,機器人提醒等),簡單點的能夠試試「Gogs」,可玩性更高的能夠試試「GitLab」。
在Github上新建了一個項目倉庫,會生成對應的倉庫連接,如:
鍵入下述命令進行關聯:
git remote add origin 遠程倉庫地址
複製代碼
接着可鍵入下述命令查看關聯狀況:
git remote # 列出已經存在的遠程分支
git remote -v # 查看遠程倉庫的地址
複製代碼
創建完關聯後,咱們可使用git push命令把本地更改推送到遠程倉庫
git push -u origin master
複製代碼
-u參數:做爲第一次提交使用,做用是把本地master分支和遠程master分支關聯起來(設置默認遠程主機),後續提交不須要這個參數!
另外,若是想修改遠程倉庫地址,可經過下述命令:
# 直接修改遠程倉庫地址
git remote set-url origin 遠程倉庫地址
# 也能夠先刪除origin後再添加
git remote rm origin # 刪除倉庫關聯
git remote add origin 遠程倉庫地址 # 添加倉庫關聯
複製代碼
你還能夠直接修改「.git文件夾中的config文件」,直接替換圈住位置內容便可:
還有一點:「origin」並非固定的東西,只是後面「倉庫地址的一個別名」!!能夠寫成其餘的東西,而後你也能夠設置多個倉庫關聯,用不一樣的別名標誌,好比:
git remote add github https://github.com/coder-pig/SimpleTea.git
git remote add osc git@git.oschina.net:coder-pig/SimpleTea.git
複製代碼
把項目推送到遠程倉庫後,其餘開發者就能夠經過git clone命令把項目克隆到本地
git clone 倉庫地址 # 克隆項目到當前文件夾下
git clone 倉庫地址 目錄名 # 克隆項目到特定目錄下
# 注:git clone命令只會創建master分支,若是想克隆特定遠程分支,可在克隆後:
git checkout -t origin/dev
# 該命令等同於
git checkout -b dev origin/dev
# 除此以外,還能夠:
git fetch origin 遠程分支:本地分支 # 會在本地新建分支,但不會自動切換,還需checkout
git branch --set-upstream 本地分支 遠程分支 # 創建本地分支與遠程分支的連接
複製代碼
獲取遠程倉庫更新的方法有兩種:fetch 和 pull,簡要講解下二者的區別:
僅僅只是從遠處服務器獲取到最新版本到本地,假如你不去合併(merge),本地工做空間是不會發生變化的!好比:在Github上建立一個README.md文件,而後調 git fetch 去獲取遠程倉庫的更新。
一步到位,pull = fetch + merge,好比:一樣修改Github上的README.md 文件,而後git pull 同步遠程倉庫的更新:
區別顯而易見,使用git fetch會更安全一些,畢竟merge的時候,查看更新的狀況,再決定是否進行合併。
在Github建立新項目後,在repo處建立了README.md或其餘文件,而後關聯本地倉庫,push時會報錯: Push rejected: Push to origin/master was rejected,而後提示你pull一下,當你pull時又會報錯: 「refusing to merge unrelated histories」,緣由是兩個倉庫不一樣致使的,可以使用下述命令解決:
git pull origin master --allow-unrelated-histories
複製代碼
除此以外,你還能夠粗暴一點,直接用本地倉庫「強制覆蓋遠程倉庫」,可是 慎用!!!若是出問題了,只能看下其餘人的電腦中是否有原始的本地倉庫進行還原!!!
git push -f origin # 慎用!!!
複製代碼
私有項目,使用Https協議pull或push,都須要驗證帳號和密碼,有點繁瑣,若是想避免這種重複輸入的狀況,能夠考慮使用SSH協議。SSH,Secureshell(安全外殼協議),專爲遠程登錄會話與其餘網絡服務提供安全性的協議,而SSH傳輸的數據是能夠通過壓縮的,能夠加快傳輸的速度,出於安全性與速度,優先考慮使用SSH協議,而SSH的安全驗證規則又分爲基於密碼和基於密鑰兩種!這裏使用的是第二種,即在本地建立一對密鑰「公鑰(id_rsa.pub)和私鑰(id_rsa)」而後把公鑰內容貼到遠程倉庫設置中的ssh keys中,從而創建本地與遠程的認證關係。配置SSH Key的流程以下:
執行完ssh-keygen那個指令後,後面依次要你輸入文件名 直接回車 → 會生成兩個默認的祕鑰文件,接着提示輸入密碼, 直接回車 → 若是這裏你輸入密碼了的話,那麼push的時候你仍是須要輸入密碼,接着又輸多一次密碼 直接回車 → 出現最下面的這串東西就說明ssh key已經建立成功了! 接着能夠用編輯器打開id_rsa.pub文件或者鍵入下述命令複製內容:
clip <id_rsa.pub
複製代碼
打開Github,點擊頭像,選擇:Settings,而後點擊左側SSH Keys,而後New SSH Key
而後Github會給你發來一個提示建立了一個新ssh key的郵件,無視就好,接下來咱們能夠鍵入:
**ssh -T git@github.com**
複製代碼
而後若是上面設置過密碼則須要輸入密碼,不然直接輸入yes而後一直按回車就好!,最後出現Hi xxx那句話就說明ssh key配置成功了!
其餘遠程倉庫配置方法相似,另外若是想一個電腦管理多個SSH-Key,可移步至:
關於Git工做流,Github上有一篇圖文並茂寫得很好的文章,就不細說了,只是簡單介紹下,更多詳情可見:《Git Workflows and Tutorials》
相似於SVN,不過只有一條master分支,而後一羣人就在這條分支上嗨,好比有小A和小B:
和集中式分部流相比只是分支再不是隻有master,而是根據功能開闢新的分支而已,示例以下:
- 1.小A要開發新功能,git branch -b new-feature 開闢新分支
注:這裏的倉庫管理者是擁有倉庫管理權限的人
其實就是功能分支工做流作了一些規範而已,大概流程參見上面「一個簡單的分支管理策略」
分佈式工做流,每一個開發者都擁有本身獨立的倉庫,爲開源項目貢獻代碼經常使用,把項目fork到本身的遠程倉庫,完成相應更改,而後pull request到源倉庫,源倉庫管理者能夠決定是否合併。
和Forking工做流相似,Pull Requests是Bitbucket上方便開發者之間協做的功能
你能夠Clone別人的開源項目,在看別人代碼的時候,以爲做者某些地方寫得很差,寫錯,或者你有更好的想法,在本地修改後,想把修改push推送到開源項目上,是沒法直接Push推送更改的。參與開源項目的方式有兩種:
方法一: 是讓做者把你加爲寫做者,添加協做者流程: 點擊倉庫的Settings → Collaborators 而後輸入想添加的人的用戶名或者郵箱,點擊 添加便可。
方法二: 點擊Fork按鈕,把這個項目fork到本身的帳號下,而後Clone到本地,而後作你想作的修改,commit提交,而後push到本身帳號裏的倉庫,而後打開開源項目,點擊,而後新建一個「pull request」,接着設置本身的倉庫爲源倉庫,設置源分支,目標倉庫與目標分支,而後還有pull request的標題和描述信息,填寫完畢後,肯定。 這個時候開源項目的做者就會收到一個pullrequest的請求,由他來進行審覈,做者審查完代碼以爲沒問題的話,他能夠點擊一下merge按鈕便可將這個pull request合併到本身的項目中,假如做者發現了你代碼中還有些bug,他能夠經過Pull Request跟你說明,要修復了xxBUG才容許合併,那麼你再修改下BUG,提交,更改後的提交會進入Pull Request,而後做者再審覈這樣!
Tips:o(╯□╰)o假如做者不關閉或者merge你的這個Pull Request,你能夠一直commit騷擾主項目…
命令行雖酷炫可裝逼,可是有時用圖形化工具仍是能提升很多效率的,安利個巨好用的Git圖形化工具SourceTree,官網下載地址:www.sourcetreeapp.com/,網上教程滿天飛,筆者也不粘貼複製了,找到個寫得還行的,有興趣可移步至:《用SourceTree輕鬆Git項目圖解》。
後面有新的會更新,待續...
參考文獻與更多Git學習資料: