文章目錄
- 分支的三個版本
- 倉庫與版本庫
- 工作區、暫存區、版本區
- .git 目錄概覽
- 本地倉庫與遠程倉庫
- 基於遠程倉庫的分支創建本地分支
- 基於 master 創建本地分支並推送到遠程倉庫
- git pull 的兩種模式:rebase 和 merge
- 合併分支
- git diff
- 撤銷修改
- 合併 commit
- 對比文件修改歷史
- 歷史日誌 log
- 格式化顯示日誌
- 刪除 untracked files
- cherry-pick
- 撤銷合併
- 刪除本地分支
- 刪除遠程分支
- 基於已有分支創建新分支
- 提交
- git flow
- 批量刪除分支
- 從倉庫中刪除已跟蹤的文件(將文件變成untracked,不跟蹤)
- 刪除遠程不存在的“本地遠程分支“
- 同時推送到多個源
- 換行符問題(mac、windows、linux混合開發時可能遇到)
分支的三個版本
- 遠程版本庫,如 github.com;
- 遠程快照,使用
git branch -r
查看到的 origin/branch-name,相關信息在.git/refs/remotes
中; - 本地分支,使用
git branch
查看到的分支,相關信息在.git/refs/heads
中。一般本地分支會關聯到對應的遠程分支;
倉庫與版本庫
可理解爲:倉庫 = 版本庫 + 工作區。版本庫即 .git 文件夾內容,版本庫以外的都是工作區內容。
工作區、暫存區、版本區
- 工作區:即我們能看到的目錄和文件(除了 .git 這個隱藏目錄),對代碼的修改發生在工作區;
- 暫存區:使用
git add .
將工作區的修改轉移到暫存區。暫存區是工作區和版本庫(分支)的中轉站; - 版本庫:使用
git commit -m
將暫存區的內容轉移到版本庫中,並生成提交記錄;
.git 目錄概覽
- 幾個
HEAD
:- FETCH_HEAD:
git fetch
用到的,記錄了遠程倉庫每個分支的 HEAD 指向; - HEAD:本地倉庫所在的版本;
- ORIG_HEAD:針對一些危險操作(如 git reset --hard),git 記錄了上次 HEAD 的值以防回退(如可以執行 git reset --hard ORIG_HEAD 回退剛剛執行的 reset 操作);
- FETCH_HEAD:
- config:配置信息;
- hooks/:鉤子 shell 腳本;
- logs/:操作日誌;
- objects/:git 對象;
- refs:引用;
本地倉庫與遠程倉庫
- git 是分佈式版本管理系統,大體上分爲本地倉庫 和 遠程倉庫。一個本地倉庫可以關聯 0 個或多個遠程倉庫。最常用的遠程倉庫默認命名爲 origin。
- 創建倉庫的幾種方式:
- 基於遠程倉庫創建本地倉庫(clone):
git clone [email protected]:linvanda/cache2go.git
; - 在本地創建一個空的倉庫:
mkdir proj & cd proj & git init
;(git init 與 git init --bare 的區別:git init --bare 生成的是裸版本庫,不帶工作區,相當於 git init 生成的 .git 內容);
- 基於遠程倉庫創建本地倉庫(clone):
- 本地倉庫與遠程倉庫的關聯:
- 創建本地倉庫:
mkdir proj & cd proj & git init
; - 添加遠程倉庫關聯:
git remote add origin [email protected]:linvanda/cache2go.git
; - 可以添加多個遠程倉庫關聯,再加一個:
git remote add other [email protected]:linvanda/cache2go-other.git
,操作時可指定倉庫,如git push other
將推送到 other 倉庫;
- 創建本地倉庫:
- 遠程倉庫源的一些操作:
- 查看遠程源列表:
git remote -v
; - 添加遠程源:
git remote add origin [email protected]:linvanda/cache2go.git
; - 移除遠程源:
git remote remove origin
; - 重命名遠程源:
git remote rename origin new-origin
;
- 查看遠程源列表:
基於遠程倉庫的分支創建本地分支
git fetch
:將 遠程倉庫分支 fetch 到本地的遠程倉庫快照中;git checkout branch-name
:自動基於origin/branch-name
快照創建本地分支並切換到該分支;
基於 master 創建本地分支並推送到遠程倉庫
git checkout master
:切換到 master 分支;git pull --rebase
:更新 master 分支到最新版本;git checkout -b branch-name
:基於 master 創建開發分支;git add . & git commit -m "commit reason"
,開發並提交修改;git push -u origin branch-name
:將該分支推送到遠程並在兩者之間創建關聯(這樣後面就可以直接執行git push
推送分支);
git pull 的兩種模式:rebase 和 merge
- merge 模式:直接執行
git pull
默認就是該模式。該模式是將遠程分支fetch
下來,然後將其merge
到相應的本地分支,並在 log 中生成一條 commit。使用該模式下,git log
查看 commit 會發現大量的 merge origin/branch-name into branch-name 的無意義的合併日誌。 - rebase 模式:
git pull --rebase
。推薦使用的模式。將遠程分支fetch
下來後,將其rebase
到本地分支,相當於“追加”,不會生成 commit。
合併分支
合併分支的最佳實踐(以將 feature-order 開發分支合併到 test 測試分支爲例):
git checkout feature-order
,進入 feature-order 分支;git pull --rebase
,同步當前分支到最新版本;git checkout test
,進入 test 分支;git pull --rebase
,同步 test 分支到最新版本;git merge --no-ff feature-order
,將 feature-order 合併到 test 分支;git push
,推到遠程;
注:
- 爲啥加
--no-ff
:no ff 是 no fast forward 的縮寫。git merge 默認是fast forward(快進) 模式,該模式下可能不會生成單獨的 commit,這對歷史查看和回滾都不便。加 --no-ff 則強制生成獨立的合併 commit; - 出現衝突咋辦?出現衝突時一定要找衝突相關人一起解決,解決完畢後執行
git add . & git commit
即可。如果無法解決衝突,則要撤銷此次合併:git merge --abort
;
git diff
git diff A B
B相對於A有什麼不同。如果不指定B,則B默認是工作區;如果同時不指定A,則A默認是暫存區。git diff
相當於 git diff stage workspace 。 工作區相對於暫存區 有哪些不同。git diff HEAD
相當於 git diff HEAD workspace 。 工作區相對於HEAD區 有哪些不同。git diff commitId
相當於 git diff commitId workspace。 工作區相對於commitId那次提交 有哪些不同。git diff commitIdA commitIdB
commitIdB相對於commitIdA有哪些不同git diff master
相當於 git diff master workspace: 當前工作區相對於master分支的最近提交有哪些不同。git diff master HEAD
當前的HEAD相對於master分支最近提交有哪些不同git show commitID
本次提交相對於上次提交有何不同
撤銷修改
- 撤銷 workspace 中某個文件的修改:
git checkout < filename >
。
變體:git checkout
:撤銷工作區所有文件的修改。 - 撤銷 stage 中某個文件的修改(將其放入 workspace):
git reset HEAD <filename>
變體:git reset HEAD
撤銷暫存區所有文件修改到工作區 git reset --hard HEAD
撤銷修改並丟棄(不放回工作區), 此時工作區內容和HEAD中的相同。
合併 commit
有時我們在本地開發時會經常地 commit,但又不想將這些瑣碎的 commit 提交到遠程倉庫,則可以將它們合併提交。合併本地多次 commit 爲一條 commit:
1. git rebase -i HEAD~4
2. 彈出文本,將第二行開始的pick改爲s(或squash)
3. 保存,退出
4. 推到遠程:git push -f
對比文件修改歷史
查看某個文件每行的修改歷史,一般在需要對某個文件做詳細變化追蹤時用到:
git blame filename
歷史日誌 log
git log --grep="test"
搜索提交信息中包含 test 的git log -S abc
搜索修改內容包含"abc"的 commitgit log --date=relative
以相對日期格式顯示日誌(如2 hours ago)git log —oneline
一行緊湊顯示提交id和註釋git log --abbrev-commit
顯示短 commit idgit log -5
顯示最近5條提交git log —all
顯示所有分支的提交歷史(默認只顯示當前分支的)git log —graph
圖形顯示分支git log --pretty=format:'…'
格式化顯示
格式化顯示日誌
git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative
可設置別名:
git config --global alias.lg "log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative”
刪除 untracked files
刪除未跟蹤(未納入到版本管理)的文件:
- 刪除文件:
git clean -f
- 連 untracked 的目錄也一起刪掉:
git clean -fd
cherry-pick
將一個分支的某個 commit 的改動應用到另一個分支。
如在分支 A 做了些修改並提交後,想把這些修改應用到分支 B,但又不能直接 merge A 到 B,又不想手動 copy,此時可以用 cherry-pick:
- 切換到分支 B:
git checkout B
; - 將 A 的某個 commit 應用到 B:
git cherry-pick commitid-from-A
;
撤銷合併
- 查看合併提交詳情:git show mergecommitid,會有如下一行:Merge: 022ff6f b2cd947,其中022ff6f和 b2cd947分別是兩個分支合併前最近提交的commitId。
- 撤銷合併時用-m指定需要以誰爲準(主幹mainline):
git revert -m 1 mergecommitid
,這樣就回退到 022ff6f身上(丟棄掉被合併分支的一系列提交)。 - 撤銷合併前用
git log —graph
能很清晰的看出分支合併關係以及將要撤銷掉的提交系列。 - 一般情況下,我們都是錯誤合併後需要撤銷到合併之前的狀態,因而一般都是
git revert -m 1 …
刪除本地分支
git branch -D branch-name
刪除遠程分支
git push origin :branch_name
或
git push --delete origin branch_name
基於已有分支創建新分支
git checkout -b branch_a origin/branch_a
: 創建本地分支 branch_a 並追蹤到遠程分支 origin/branch_a;git checkout -b branch_a
:基於當前分支(如master)創建新分支 branch_a, 不會追蹤任何遠程分支,此時要用git push -u origin branch_a:branch_a
追蹤並推送到遠程倉庫。
提交
git commit -am '…'
-a:add 將未暫存的文件也提交(注意此方式不適用新創建的文件,新建的文件仍然要 git add .
)。
git flow
一種不錯的分支管理策略,我們公司就是基於 git flow 設計的分支管理策略。
介紹
安裝: apt-get install git-flow
批量刪除分支
實際開發過程中,長時間不清理分支後,存在大量的開發分支,造成分支查找困難,我們需要不定期清理不需要的分支。
- 批量刪除本地分支:
git branch |grep release|xargs git branch -D
(刪除本地release分支) - 批量刪除遠程分支:
git branch -r|awk -F '[/]' '/release/ {printf "%s\n", $2}'|xargs -I {} git push --delete origin {}
(刪除遠程release分支)
從倉庫中刪除已跟蹤的文件(將文件變成untracked,不跟蹤)
有時候把 vendor、IDE 配置文件(如 .vscode 等)誤加到版本控制裏面了,需要移除掉。
git rm --cached $file_name
git rm --cached -r $dir_name
刪除遠程不存在的“本地遠程分支“
很多時候其他人刪除了遠程分支,但我們自己電腦上還有一大堆 origin/… 這些“本地遠程分支”,可執行以下指令同步刪除:
git remote prune origin
或者git pull -p
同時推送到多個源
比如我們自己開發了一個代碼庫,想同時推送到公司 gitlab 和自己的 github 倉庫。
添加新的源:git remote set-url --add --push origin https://github.com/linvanda/wecarswoole.git
這樣 git push 的時候就會 push 到多個源。
換行符問題(mac、windows、linux混合開發時可能遇到)
有幾種配置策略:
git config --global core.autocrlf true
(提交時自動將CRLF轉成LF,檢出時將LF轉成CRLF)git config --global core.autocrlf input
(提交時自動將CRLF轉成LF,檢出時不處理(意味着檢出時是LF))
(以上兩個都是保證git倉庫中是LF)git config --global core.autocrlf false
(關閉,不處理,是啥就是啥)