Git Cheatsheet

基本使用

配置用戶名郵箱

$ git config --global user.name "Your Name"
$ git config --global user.email "[email protected]"

本地創建倉庫

$ mkdir demo_repo && cd demo_repo
$ git init

添加文件

$ git add readme.txt
$ git add dummy1.txt
$ git add dummy2.txt

提交到倉庫

$ git commit -m "commit 1 readme file, 2 dummy file"

工作區,暫存區(stage), 分支commit(快照)歷史

$ git add    #工作區文件添加到暫存區
$ git commit #暫存區文件提交commit

查看倉庫狀態,當前分支,文件修改等

$ git status

查看具體修改內容

$ git diff readme.txt 
$ git diff HEAD -- readme.txt #比較工作區和最新commit 

版本回退、切換

從近到遠顯示commit歷史, commit id, author,message等等

$ git log
$ git log --pretty=oneline #清爽信息

回退

$ git reset --hard HEAD^     #回退到前1個commit
$ git reset --hard HEAD^^    #回退到前2個commit
$ git reset --hard HEAD~100  #回退到前100個commit
$ git reset --hard 1094a     #切換到指定commit id

誤刪commit, 如何恢復
查看命令記錄,找回誤刪的commit id

$ git reflog
$ git reset --hard xxxx

丟棄工作區文件的修改

$ git checkout -- readme.txt #回退到暫存區的狀態
$ git checkout -- readme.txt #如果暫存區乾淨回退到最新commit的狀態

丟棄暫存區的修改

$ git reset HEAD <file>  #回退到最新commit的狀態

刪除文件

$ rm test.txt
$ git rm test.txt #刪除版本庫中版本
$ git commit -m "remove test.txt" #提交刪除

誤刪回退

$ git checkout -- test.txt 

本地分支管理

HEAD指向當前分支,分支指向commit

    HEAD
      \
    master
      \
O--O--O

創建,切換分支

$ git branch dev         #創建分支
$ git checkout dev       #切換分支       $git switch  dev
$ git checkout -b dev    #創建並切換分支 $git switch -c dev
    master
      \
O--O--O
      |
     dev
      | 
    HEAD

查看當前分支

$ git branch

切換分支發生的事

$ git add readme.txt                #在dev分支上 add
$ git commit -m "on branch dev"     #在dev分支上 commit
    master
      |
O--O--O~~O
         |
        dev
         | 
        HEAD
$ git checkout master               #切換回master
    HEAD
      \
    master
      \
O--O--O~~O
         |
        dev

在當前分支上合併分支

Fast-forward合併分支

$ git merge dev     #在master上合併dev
#實際是Fast-forward類型的合併
         HEAD
           \
         master
           \
O--O--O--~~O
           |
          dev

強制禁用 fast forward,會創建新的commit

$ git merge --no-ff -m "merge with no-ff" dev
         HEAD
           \
         master
            \
O--O--O------O
        \   /
         O
         |
        dev

刪除分支

$ git branch -d dev
         HEAD
           \
         master
           \
O--O--O--~~O

合併衝突的解決

當前分支狀態

         HEAD
           \
         master
            |
            O
           /
O--O--O--O
          \
           O
           |
          feature1

在當前分支(master)

$ git merge feature1
Auto-merging...
CONFLICT (content)
...
#發生了衝突

查看衝突,手動修改

$ git status
手動修改衝突文件
$ vi ...

然後在當前分支

$ git add foo.bar
$ git commit -m "fix conflict"
                 HEAD
                  |  
                 master
                   /
O--O--O--O --O -- O
          \     /
           O---/
           |
          feature1

查看合併情況

$ git log --graph --pretty=oneline --abbrev-commit

刪除分支

$ git branch -d feature1

分支數目和用途的設置

廖雪峯給的一個管理策略,未必就是最佳實踐
master:應當很穩定,僅用來發布新版本,不用來開發
dev:分支用來開發,發佈新版本時候,在master分支合併dev
平時開發:從dev上創建新分支合併。。。

修復bug的流程示例

在dev分支上,接到任務修bug

$ git status #查看當前分支,比如dev
$ git stash  #暫存當前工作區

加入從master分支着手修復bug

$ git switch master
$ git checkout -b issue-101 #bug分支

在issue-101分支上

$ git add readme.txt 
$ git commit -m "fix bug 101"
[issue-101 4c805e2] fix bug 101

修復完成後,回到master合併修復內容

$ git switch master
$ git merge --no-ff -m "merged bug fix 101" issue-101

回到dev繼續幹活

$ git switch dev
#查看工作現場
$ git stash list
$ git stash apply #恢復工作區
$ git stash drop  #刪除保存的狀態
$ git stash pop   #先恢復,然後刪除保存的狀態

cherry-pick “複製”一個commit到當前分支
dev是從master過來的,可能這個bug在dev上也有
cherry-pick只複製commit,不用merge

$ git branch
* dev
  master
$ git cherry-pick 4c805e2  #修bug的commit  [issue-101 4c805e2] fix bug 101
[master 1d4b803] fix bug 101
 1 file changed, 1 insertion(+), 1 deletion(-)

開發新feature的流程示例

從dev創建新分支feature,開發完成後在合併到dev
中間feature取消的話可以強制刪除

$ git branch -D <name>

遠程倉庫及多人協作問題

基本操作

以某種方式創建遠程倉庫 e.g. github
在本地

$ cd demo_repo
$ git remote add origin [email protected]:username/demo_repo.git
#添加了遠程庫 名字: origin, 地址 git@,,,.git

推送本地內容至遠程庫

$ git push -u origin master

-u參數,
不僅把本地的master分支內容推送的遠程新的master分支,
還會把本地的master分支和遠程的master分支關聯起來,
在以後的推送或者拉取時就可以簡化命令

$ git push origin master #關聯後的簡化命令

克隆遠程倉庫

$ git clone [email protected]:username/demo_repo.git

多人協作

git clone 遠程倉庫時,自動把本地master和遠程master對應,遠程倉庫默認爲origin
查看遠程倉庫

$ git remote
$ git remote -v #verbose

推送分支:把本地分支上的commit推送到遠程庫

$ git push origin master  #指定本地分支master, 推送到遠程庫的對應分支
$ git push origin dev   #推送本地的dev分支

用戶b在a之前推送更新到遠程倉庫

# user_b執行clone遠程倉庫
user_b@ubuntu$ git clone [email protected]:username/demo_repo.git
# 默認只有master分支
$ git branch
# clone遠程倉庫後,在本地使用遠程分支
user_b@ubuntu$ git checkout -b dev origin/dev    #在本地創建遠程分支
...git add...git commit...
user_b@ubuntu$ git push origin dev               #推送到遠程分支

推送更新,以及衝突解決

user_a本地也作了修改,也想push到origin/dev

# 當前在dev分支
user_a@ubuntu$ git push origin dev
# 推送失敗,兩個推送有衝突,因爲當前分支落後了

1)user_a 拉取最新內容

#git pull <remote> <branch> <=> git fetch; git merge
user_a@ubuntu$ git pull 
# 拉取失敗,當前的dev分支和origin/dev分支沒有指明鏈接
user_a@ubuntu$ git branch --set-upstream-to=origin/dev dev   #指明鏈接
user_a@ubuntu$ git pull      #可以拉取
#顯示有衝突

2)手動解決衝突的文件
3)然後添加commit,推送

user_a@ubuntu$ git add foo.bar
user_a@ubuntu$ git commit -m "fix conflict"
# 然後推送到dev分支
user_a@ubuntu$ git push origin dev

完成。

rebase

rebase & squash

on master: 
1--2--3
on master:
git checkout -c feature
on master:
		  master
			|
1--2--3--4--5
on feature:
			   feature
			     |
1--2--3~~10~~11~~12

merge

$ git checkout feature
$ git merge master
		  master
			|
1--2--3--4--5----------|
	   \~~10~~11~~12~~20
	   				   |
	   			   feature
  • pros :操作簡單熟悉;保存提交歷史和時間順序;保存分支的上下文
  • cons:大量的merge commit會污染提交記錄;git bisect困難

rebase

$ git checkout feature
$ git rebase master
		  master
			|
1--2--3--4--5~~10~~11~~12
	   					|
	   			 	feature
$ git rebase -i master # interactive mode
squash 10xxxxx Commit message#1
squash 11e8a9b Commit message#2
# pick
# squash
# fix up
# 清理歷史,壓縮commit
可能的結果
		  master
			|
1--2--3--4--5~~12
	   			|
	   		feature
  • pros: 簡化複雜的提交歷史;單個提交容易進行;避免merge的提交污染歷史;清處中間commit,有利於DevOps 團隊
  • cons: 壓縮大量提交會隱藏上下文;團隊合作時,rebase 公開repo可能是危險的;需要更多工作,feature branch需要持續更新;rebase遠程分支需要force push

The biggest problem people face is they force push but haven’t set git push default. This results in updates to all branches having the same name, both locally and remotely, and that is dreadful to deal with.

如何選擇呢? 取決於團隊

pr

把開發分支向dev目標分支創建pull request
可以在開發dev的時候,持續開發,持續得到dev和目標分支的比較,可以用做代碼review

標籤管理

標籤是某分支上某commit的別名

$ git tag  v0.1 #爲當前分支的最新commit打tag
$ git tag -a v0.1 -m "version 0.1 released" 1094adb 
#爲指定的commit打tag,並加註釋

查看tag

$ git tag
$ git show v0.9

推送標籤到遠程倉庫

$ git push origin v1.0	 #推送單個
$ git push origin --tags #推送全部

刪除標籤

$ git tag -d v0.1                   # 1)先從本地刪除
$ git push origin :refs/tags/v0.9   # 2)然後刪除遠程

打patch

引用鏈接
patch中存儲的是對代碼的修改
生成patch就是記錄你對代碼的修改並將其保存在patch文件中
打patch就是將patch文件中對代碼的修改,應用到源代碼,從而把對代碼的修改應用到code中

diff和patch兩個命令可以生成patch和打patch,但是對多個文件不方便;沒辦法保存commit信息

下面的方法可以以project爲單位;可以保存commit信息;靈活,可以獲取任意commit之間的patch集

$ git format-patch
$ git am
$ git format-patch HEAD^
#生成最近的1次commit的patch
$ git format-patch HEAD^^               
#生成最近的2次commit的patch
$ git format-patch <r1>..<r2>
#生成兩個commit間的修改的patch(包含兩個commit. <r1>和<r2>都是具體的commit號)
$ git format-patch -1 <r1>
#生成單個commit的patch
$ git format-patch <r1>
#生成某commit以來的修改patch(不包含該commit)
$ git format-patch --root <r1>
#生成從根到r1提交的所有patch

git am

$ git apply --stat 0001-limit-log-function.patch
# 查看patch的情況
$ git apply --check 0001-limit-log-function.patch
# 檢查patch是否能夠打上,如果沒有任何輸出,則說明無衝突,可以打上
(注:git apply是另外一種打patch的命令,
其與git am的區別是,
git apply並不會將commit message等打上去,
打完patch後需要重新git add和git commit,
而git am會直接將patch的所有信息打上去,
而且不用重新git add和git commit,
author也是patch的author而不是打patch的人)

$ git am 0001-limit-log-function.patch
# 將名字爲0001-limit-log-function.patch的patch打上
$ git am --signoff 0001-limit-log-function.patch
# 添加-s或者--signoff,還可以把自己的名字添加爲signed off by信息,作用是註明打patch的人是誰,因爲有時打patch的人並不是patch的作者
$ git am ~/patch-set/*.patch
# 將路徑~/patch-set/*.patch 按照先後順序打上
$ git am --abort 
# 當git am失敗時,用以將已經在am過程中打上的patch廢棄掉
#(比如有三個patch,打到第三個patch時有衝突,那麼這條命令會把打上的前兩個patch丟棄掉,返回沒有打patch的狀態)
#$ git am --resolved
#當git am失敗,解決完衝突後,這條命令會接着打patch

patch衝突的解決

(1) 根據git am失敗的信息,找到發生衝突的具體patch文件,
然後用命令git apply --reject <patch_name>,強行打這個patch,
發生衝突的部分會保存爲.rej文件
(例如發生衝突的文件是a.txt,那麼運行完這個命令後,發生conflict的部分會保存爲a.txt.rej),
未發生衝突的部分會成功打上patch
(2) 根據.rej文件,通過編輯該patch文件的方式解決衝突。
(3) 廢棄上一條am命令已經打了的patch:git am --abort
(4) 重新打patch:git am ~/patch-set/*.patchpatch

本文大部分內容是對這篇教程二次整理所得

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章