目錄
- git日常使用
- git 基礎用法(本地)
- git branch
- git checkout
- git merge
- git rebase
- HEAD ,在提交樹上移動
- 相對引用
- 強制修改分支位置
- 撤銷變更
- 整理提交記錄
- 提交技巧
- Git Tags
- Git Describe
- git 基礎用法(遠程)
- git fetch
- git pull
- git push
- 偏離的提交歷史,十分重要!!!
- 配置參數選項
- merge 與 rebase的選擇
- 更新倉庫提交歷史
- 合并多個commit提交記錄
- 刪除意外調試的測試代碼
- 如何處理工作中斷
git日常使用
參考網站:Git 實用技巧記錄
和學習git
日常使用git的流程如下
當修改完代碼,將本次修改的代碼提交到遠端流程:
# 工作區 -> 暫存區
git add <file/dir>
# 暫存區 -> 本地倉庫 + 注釋
git commit -m "memo"
# 本地倉庫 -> 遠程倉庫
git push origin master # 本地 master 分支推送到遠程 origin 倉庫
拉取遠端最新版本代碼到本地流程:
# 本地倉庫 <- 遠程倉庫
git clone <git_url> # 克隆遠程倉庫
git fetch upstream master # 拉取遠程代碼到本地但不應用在當前分支
git pull upstream master # 拉取遠程代碼到本地并且應用在當前分支
git pull --rebase upstream master # 如果平時使用 rebase 合并代碼則加上
# 暫存區 <- 本地倉庫
git reset HEAD <file> # 本地倉庫文件內容覆蓋暫存區文件內容
# 工作區 <- 暫存區
git checkout -- <file> # 暫存區文件內容覆蓋工作區文件內容
將本地倉庫代碼覆蓋到工作區的流程:
# 工作區 <- 本地倉庫
git reset <commit> # 本地倉庫覆蓋到工作區(保存回退文件內容修改)
git reset --mixed <commit> # 同上
git reset --soft <commit> # 本地倉庫覆蓋到工作區(保留修改并加到暫存區)
git reset --hard <commit> # 本地倉庫覆蓋到工作區(不保留修改直接刪除掉)
git 基礎用法(本地)
git branch
創建一個新的分支
git branch your-branch-name
git checkout
創建一個新的分支的同時切換到新創建的分支:
git checkout -b your-branch-name
git merge
將兩個分支合并在一起
下面這個是將bugFix分支合并到master上
git checkout master
git merge bugFix (把bugFix合并到當前分支上)
如果你出現這個情況:
可以使用命令:
git reflog expire --expire=now --all
刪除所有隱藏的版本
git rebase
還有一種合并分支的方法是git rebase,實際上就是取出一系列的提交記錄,復制它們,然后在另外一個地方逐個放下去。
我們想要把 bugFix 分支里的工作直接移到 master 分支上。移動以后會使得兩個分支的功能看起來像是按順序開發,但實際上它們是并行開發的。注意,提交記錄 C3 依然存在(樹上那個半透明的節點),而 C3’ 是我們 Rebase 到 master 分支上的 C3 的副本。
git rebase master
之后切換master然后把它rebase到bugFix分支上。
HEAD ,在提交樹上移動
HEAD 是一個對當前檢出記錄的符號引用 —— 也就是指向你正在其基礎上進行工作的提交記錄。
HEAD 總是指向當前分支上最近一次提交記錄。大多數修改提交樹的 Git 命令都是從改變 HEAD 的指向開始的。
使用git checkout hashvalue
可以指向對應的版本
相對引用
通過指定提交記錄哈希值的方式在 Git 中移動不太方便,實際使用時你就不得不用 git log 來查查看提交記錄的哈希值。并且哈希值在真實的 Git 世界中也會更長。Git 對哈希的處理很智能。你只需要提供能夠唯一標識提交記錄的前幾個字符即可。
使用相對引用的話,你就可以從一個易于記憶的地方(比如 bugFix 分支或 HEAD)開始計算。使用方法如下:
- 使用 ^ 向上移動 1 個提交記錄
- 使用 ~ 向上移動多個提交記錄,如 ~3
強制修改分支位置
相對引用使用的最多的就是移動分支,可以使用 -f 讓分支指向另一個提交:
# 將master分支強制指向HEAD的第3級父提交
git branch -f master HEAD^3
撤銷變更
主要有兩種方法用來撤銷變更:
一是 git reset
,還有就是 git revert
。
git reset 通過把分支記錄回退幾個提交記錄來實現撤銷改動。你可以將這想象成“改寫歷史”。git reset 向上移動分支,原來指向的提交記錄就跟從來沒有提交過一樣。
在reset后, 之前 所做的變更還在,但是處于未加入暫存區狀態。
雖然在你的本地分支中使用 git reset 很方便,但是這種“改寫歷史”的方法對大家一起使用的遠程分支是無效的。
為了撤銷更改并分享給別人,我們需要使用git revert HEAD
在我們要撤銷的提交記錄后面多了一個新提交。這是因為新提交記錄 C2’ 引入了更改 —— 這些更改剛好是用來撤銷 C2 這個提交的。也就是說 C2’ 的狀態與 C1 是相同的。revert 之后就可以把你的更改推送到遠程倉庫與別人分享啦。
整理提交記錄
開發人員有時會說“我想要把這個提交放到這里, 那個提交放到剛才那個提交的后面”, 而接下來就講的就是它的實現方式。
第一個命令:
git cherry-pick <提交號>
如果你想將一些提交復制到當前所在的位置(HEAD)下面的話, Cherry-pick 是最直接的方式了。
將 side 分支上的工作復制到 master 分支:
git cherry-pick C2 C4
![]() | ![]() |
當我們不清楚提交記錄的哈希值時,可以利用交互式rebase:
交互式 rebase 指的是使用帶參數 --interactive
的 rebase 命令, 簡寫為 -i
如果你在命令后增加了這個選項, Git 會打開一個 UI 界面并列出將要被復制到目標分支的備選提交記錄,它還會顯示每個提交記錄的哈希值和提交說明,提交說明有助于你理解這個提交進行了哪些更改。
在實際使用時,所謂的 UI 窗口一般會在文本編輯器 —— 如 Vim —— 中打開一個文件。
當 rebase UI界面打開時, 你能做3件事:
- 調整提交記錄的順序(通過鼠標拖放來完成)
- 刪除你不想要的提交(通過切換 pick 的狀態來完成,關閉就意味著你不想要這個提交記錄)
- 合并提交。 它允許你把多個提交記錄合并成一個。
git rebase -i HEAD~4
然后我們在gui中沒有選中任何節點
![]() | ![]() |
提交技巧
情景一:
你之前在 newImage
分支上進行了一次提交,然后又基于它創建了 caption
分支,然后又提交了一次。
此時你想對的某個以前的提交記錄進行一些小小的調整。
我們可以通過下面的方法來克服困難:
- 先用
git rebase -i
將提交重新排序,然后把我們想要修改的提交記錄挪到最前 - 然后用
commit --amend
來進行一些小的修改 - 接著再用
git rebase -i
來將他們調回原來的順序 - 最后把master以到修改的最前端就可以了
例如下面:
使用命令:
git rebase -i HEAD~2
# 然后調整順序
git commit --amend
git rebase -i HEAD~2
# 然后調整順序
git branch -f master caption
![]() | ![]() |
情景二
仍然是上面的要求,不過rebase的問題就是要進行兩次排序,而這有可能造成由 rebase 而導致的沖突。下面我們使用git cherry-pick
:
cherry-pick
可以將提交樹上任何地方的提交記錄取過來追加到 HEAD 上(只要不是 HEAD 上游的提交就沒問題)。
git checkout master
git cherry-pick C3 C2
git commit --amend
git checkout C1
git cherry-pick master C3'
git branch -f master HEAD
![]() | ![]() |
Git Tags
tag主要用于發布版本的管理,一個版本發布之后,我們可以為git打上 v.1.0.1 v.1.0.2 …這樣的標簽。
建立一個標簽,指向提交記錄C1,表示這是我們的1.0版本
git tag v1 C1
注意,如果你不指定提交記錄,Git 會用 HEAD 所指向的位置。
![]() | ![]() |
Git Describe
標簽在代碼庫中起著“錨點”的作用,Git 還為此專門設計了一個命令用來描述離你最近的錨點(也就是標簽),它就是 git describe
語法如下:
git describe <ref>
可以是任何能被git識別成提交記錄的引用,如果沒有指定的話,會以目前所檢出的位置(HEAD)
輸出結果為:
<tag>_<numCommits>_g<hash>
tag
表示的是離ref
最近的標簽,numCommits
表示的是這個ref
與tag
相差多少個提交記錄,hash
表示的是你所給定的 ref
所表示的提交記錄哈希值的前幾位。
我們對如下分支進行describe:
git describe master
output: v1_2_gC2
git describe side
output: v2_1_gC4
git 基礎用法(遠程)
Git 遠程倉庫相當的操作實際可以歸納為兩點:向遠程倉庫傳輸數據以及從遠程倉庫獲取數據。既然我們能與遠程倉庫同步,那么就可以分享任何能被 Git 管理的更新.
git fetch
git fetch 做了些什么呢?
- 從遠程倉庫下載本地倉庫中缺失的提交記錄
- 更新遠程分支指針
實際上將本地倉庫中的遠程分支更新成了遠程倉庫相應分支的最新狀態。遠程分支反映了遠程倉庫在你最后一次與它通信時的狀態,git fetch 就是你與遠程倉庫通信的方式。
git fetch
并不會改變你本地倉庫的狀態。它不會更新你的 master
分支,也不會修改你磁盤上的文件。
git fetch 的理解為單純的下載操作。
git pull
當遠程分支中有新的提交時,你可以像合并本地分支那樣來合并遠程分支:
git cherry-pick origin/master
git rebase origin/master
git merge origin/master
實際上,由于先抓取更新再合并到本地分支這個流程很常用,因此 Git 提供了一個專門的命令來完成這兩個操作。它就是 git pull
下圖的左側是遠程倉庫。
我們通過命令:
git fetch
git merge origin/master
先下載C3,然后通過merge合并了這一個提交記錄,這樣我們的master分支就包含了遠程倉庫中的更新。
git pull
其實就是git fetch
和git merge <just-fetched-branch>
的縮寫
git push
git push 與 git pull 相反,負責將你的變更上傳到指定的遠程倉庫,并在遠程倉庫上合并你的新提交記錄。一旦 git push 完成, 你的朋友們就可以從這個遠程倉庫下載你分享的成果。
偏離的提交歷史,十分重要!!!
假設你周一克隆了一個倉庫,然后開始研發某個新功能。到周五時,你新功能開發測試完畢,可以發布了。但是 —— 天啊!你的同事這周寫了一堆代碼,還改了許多你的功能中使用的 API,這些變動會導致你新開發的功能變得不可用。但是他們已經將那些提交推送到遠程倉庫了,因此你的工作就變成了基于項目舊版的代碼,與遠程倉庫最新的代碼不匹配了。
此時git是不允許你push變更的,它會強制你先合并并遠程最新的代碼,然后才能分享你的工作。
最直接的方法就是通過 rebase 調整你的工作
如果我們在push之前做rebase的話
git fetch
git rebase o/master
git push
![]() | ![]() |
git fetch 更新了本地倉庫中的遠程分支,然后用rebase將我們的工作移動到最新的提交記錄下面,最后在git push推送到遠程倉庫。
也可以精簡指令為:
git pull --rebase
git push
我們還可以使用merge
盡管git merge
不會移動工作(它會創建新的合并提交),但是它會告訴git 你已經合并了遠程倉庫的所有變更。這是因為遠程分支現在是你本地分支的祖先,也就是說你的提交已經包含了遠程分支的所有變化。
git fetch
git merge o/master
git push
我們用 git fetch 更新了本地倉庫中的遠程分支,
然后合并了新變更到我們的本地分支(為了包含遠程倉庫的變更),
最后我們用 git push 把工作推送到遠程倉庫
![]() | ![]() |
配置參數選項
全局配置
# 用戶信息
git config --global user.name "your_name"
git config --gloabl user.email "your_email"# 文本編輯器
git config --global core.editor "nvim" # 分頁器 分頁器作用詳見 https://blog.csdn.net/chuandao4139/article/details/100814046
git config --global core.pager "more"# 別名
git config --gloabl alias.gs "git status"# 糾錯
git config --global help.autocorrect 1
個人配置
# 不加 --global 參數的話,則為個人配置
git config --list
git config user.name
git config user.name "your_name"# 如果在項目中設置,則保存在 .git/config 文件里面
cat .git/config
[user]name = "your_name"
......
merge 與 rebase的選擇
只對尚未推送或分享給他人的本地修改執行rebase操作操作清理歷史。
從不對已經推送到倉庫的提交記錄執行rebase操作。
更新倉庫提交歷史
合并多個commit提交記錄
當為了完成一個功能提交多個commit記錄,在提交PR之前,需要整理這些提交記錄。包括合并、刪除等操作
# 調整最近五次的提交記錄
git rebase -i HEAD~5
git rebase -i xxxxx # 往前第六次的commit版本號
reword xxxx3 3rd commit
squash xxxx4 4th commit
pick xxxx5 5th commit
fixup xxxx6 6th commit
drop xxxx7 7th commit# 查看提交歷史記錄
git log
* ce813eb - (HEAD -> master) 5th commit
* aa2f043 - 3rd commit -> modified
* 6c5418f - 2nd commit
* c8f7dea - 1st commit
對于各個參數的解釋:
編號 | 選項列表 | 對應含義解釋 |
---|---|---|
1 | p/pick | 使用這個記錄 |
2 | r/reword | 使用這個記錄,并且修改提交信息 |
3 | e/edit | 使用這個記錄,rebase時會暫停允許你修改這個commit |
4 | s/squash | 使用這個記錄,將當前commit與上一個commit合并 |
5 | f/fixup | 與squash相同,但是不會保存當前commit的提交信息 |
6 | x/exec | 執行其他shell命令 |
7 | d/drop | 移除這個commit記錄 |
刪除意外調試的測試代碼
有時提交之后,我們才發現提交的歷史記錄中存在這一些問題,但是此時又不希望新生成一個commit記錄。此時可以修改之前的commit提交記錄。
git add filename
# 更改當前最新一次提交記錄
git commit --amend
# 改變且不改變提交信息
git commit --amend --no-edit
# 如果想改變提交最新一次提交記錄并修改信息
git commit --amend -m "memo"
如何處理工作中斷
現在我們正在一個分支上為項目添加一個小功能,此時,線上環境的有一個bug需要讓我們修復,但是我們添加的小功能并沒有完成。
如果此時,我們直接切換到主干分支,會將之前分支沒有來得及提交的內容全部都帶到了主干分支上,這是我們不想看到的情況。
此時我們需要保存上個分支的工作狀態,在我們修改完成線上bug之后,再繼續工作。
git中可以使用stash子命令幫助我們當前工作區、暫存區當中修改都保存到堆棧之中。等我們需要處理的時候,再彈出堆棧中的內容,我們再次開發
# 存儲當前的修改但不提交
git stash
# 保存當前狀態 包括 untracked的文件
git stash -u
# 展示所有 stashes 信息
git stash list
# 回到某個 stash 狀態
git stash apply <stash@{n}>
# 刪除儲藏區
git stash drop <stash@{n}>
# 回到最后一個 stash 的狀態并刪除這個 stash 信息
git stash pop
# 刪除所有的 stash 信息
git stash clear
# 從 stash 中拿出某個文件的修改
git checkout <stash@{n}> -- <file-path>
比較保險的做法是將當前所有修改進行push并保存到遠程倉庫中,這樣不要害怕本地文件丟失的問題。等到我們需要繼續開發的時候,拉下對應內容,再想辦法進行補救。
# 將工作區和暫存區覆蓋最近一次提交
git commit --amend
git commit --amend -m "memo"# 會退到指定版本并記錄修改內容(--mixed)
# 本地倉庫覆蓋到工作區(保存回退文件內容修改)
git reset xxxx(某個版本號)
git reset HEAD~ 退回到上一個版本
git reset HEAD~2 退回到上兩個版本
# 本地倉庫覆蓋到工作區(不保留修改直接刪除掉)
git reset --soft <commit/reference>
# 本地倉庫覆蓋到工作區(保留修改并加到暫存區)
git reset --hard <commit/reference>