一,git基礎概念
- Working Tree 當前的工作區域
- Index/Stage 暫存區域,和git stash命令暫存的地方不一樣。使用git add xx,就可以將xx添加近Stage裏面
- Repository 提交的歷史,即使用git commit提交後的結果
二,基本操作命令:
git status # 查看狀態
git add . # 將變動文件添加 從到工作區添加到 緩存區
git commit -m "提交信息" # 提交代碼到 本地倉庫
git push origin master # 將本地倉庫代碼 推送到 遠程倉庫
git pull # 默認參數爲 --merge 將遠程倉庫代碼 拉取到 本地倉庫後 merge 到本地代碼
git pull --rebase # 將遠程倉庫代碼 拉取到 本地倉庫後 rebase 到本地代碼
三,進階命令 - - - 包括分支切換、合併等操作:
1,git clean
命令用來從你的工作目錄中刪除所有沒有tracked過的文件
用法:
git clean -n
是一次clean的演習, 告訴你哪些文件會被刪除。記住他不會真正的刪除文件,只是一個提醒。
git clean -f
刪除當前目錄下所有沒有track過的文件。他不會刪除.gitignore文件裏面指定的文件夾和文件, 不管這些文件有沒有被track過。
git clean -d
刪除指定路徑下的沒有被track過的文件夾。
git clean -df
刪除當前目錄下沒有被track過的文件和文件夾。
git clean -xf
刪除當前目錄下所有沒有track過的文件,不管他是否是.gitignore文件裏面指定的文件夾和文件。
git reset --hard和git clean -f是一對好基友. 結合使用他們能讓你的工作目錄完全回退到最近一次commit的時候。
git clean -df && git reset --hard && git pull --rebase
2,git reset
參考自:https://www.jianshu.com/p/c2ec5f06cf1a
適用場景: 如果想恢復到之前某個提交的版本,且那個版本之後提交的版本我們都不要了,就可以用這種方法。
原理: git reset的作用是修改HEAD的位置,即將HEAD指向的位置改變爲之前存在的某個版本,如下圖所示,假設我們要回退到版本。
1)reset --hard (重置stage區和工作目錄)
你的stage區和工作目錄裏的內容會被完全重置爲和HEAD的新位置相同的內容。換句話說,就是你的沒有commit的修改會被全部擦掉。
使用場景:
- (1) 要放棄目前本地的所有改變時,即去掉所有add到暫存區的文件和工作區的文件,可以執行 git reset -hard HEAD 來強制恢復git管理的文件夾的內容及狀態;
- (2) 真的想拋棄目標節點後的所有commit(可能覺得目標節點到原節點之間的commit提交都是錯了,之前所有的commit有問題)。
注意:
此命令爲重置 工作區域和緩存區域的已有文件的修改,對工作區域內的新增文件不做處理,對緩存區域的新增文件進行重置。這是因爲add是將文件納入版本管理並緩存修改。如果沒有納入版本控制是不會進行緩存修改的。
# 查看版本號的兩種方法
git log
git reflog
git reset --hard
git reset --hard HEAD # 刪除當前版本中 工作區域和緩存區域的新增文件
git reset --hard HEAD^ # 切換到上一個commit版本
git reset --hard 版本號 # 切換到指定的版本號
2)reset --soft:保留工作目錄和暫存區,並把重置 HEAD 所帶來的新的差異放進暫存區
此模式下會保留 working tree工作目錄的內容,不會改變到目前所有的git管理的文件夾的內容;也會保留 index暫存區的內容,讓index 暫存區與 working tree 工作目錄的內容是一致的。就只有 repository 中的內容的更變需要與 reset 目標節點一致,因此原始節點與reset節點之間的差異變更集合會存在與index暫存區中(Staged files),所以我們可以直接執行 git commit 將 index暫存區中的內容提交至 repository 中。當我們想合併「當前節點」與「reset目標節點」之間不具太大意義的 commit 記錄(可能是階段性地頻繁提交)時,可以考慮使用 Soft Reset 來讓 commit 演進線圖較爲清晰點。
使用場景:
原節點和reset節點之間的【差異變更集】會放入index暫存區中(Staged files),所以假如我們之前工作目錄沒有改過任何文件,也沒add到暫存區,那麼使用reset --soft後,我們可以直接執行 git commit 將 index暫存區中的內容提交至 repository 中。爲什麼要這樣呢?這樣做的使用場景是:假如我們想合併「當前節點」與「reset目標節點」之間不具太大意義的 commit 記錄(可能是階段性地頻繁提交,就是開發一個功能的時候,改或者增加一個文件的時候就commit,這樣做導致一個完整的功能可能會好多個commit點,這時假如你需要把這些commit整合成一個commit的時候)時,可以考慮使用reset --soft來讓 commit 演進線圖較爲清晰。總而言之,可以使用–soft合併commit節點。
git reset --soft 版本號 # 切換到指定的版本,保留當前工作區、緩存區數據,
# 並把版本之間差異存入到緩存區中。
3)reset 不加參數(mixed):保留工作目錄,並清空暫存區
reset 如果不加參數,那麼默認使用 --mixed 參數。它的行爲是:保留工作目錄,並且清空暫存區。也就是說,工作目錄的修改、暫存區的內容以及由 reset 所導致的新的文件差異,都會被放進工作目錄。簡而言之,就是「把所有差異都混合(mixed)放在工作目錄中」。
使用場景:
- (1)使用完reset --mixed後,我們可以直接執行 git add 將這些改變果的文件內容加入 index 暫存區中,再執行 git commit 將 Index暫存區 中的內容提交至Repository中,這樣一樣可以達到合併commit節點的效果(與上面–soft合併commit節點差不多,只是多了git add添加到暫存區的操作);
- (2)移除所有Index暫存區中準備要提交的文件(Staged files),我們可以執行 git reset HEAD 來 Unstage 所有已列入 Index暫存區 的待提交的文件。(有時候發現add錯文件到暫存區,就可以使用命令)。
- (3)commit提交某些錯誤代碼,或者沒有必要的文件也被commit上去,不想再修改錯誤再commit(因爲會留下一個錯誤commit點),可以回退到正確的commit點上,然後所有原節點和reset節點之間差異會返回工作目錄,假如有個沒必要的文件的話就可以直接刪除了,再commit上去就OK了。
git reset 版本號
git reset --mixed 版本號
git reset --mixed 與git reset --soft之間的差異:
工作目錄的內容和 –soft 一樣會被保留,但和 –soft 的區別在於,它會把暫存區清空,並把原節點和reset節點的差異的文件放在工作目錄,總而言之就是,工作目錄的修改、暫存區的內容以及由 reset 所導致的新的文件差異,都會被放進工作目錄
4)總結
a> reset 的本質:
移動 HEAD 以及它所指向的 branch
b>區別:
- 1,–hard: 重置位置的同時,直接將 working Tree工作目錄、 index 暫存區及 repository 都重置成目標Reset節點的內容,所以效果看起來等同於清空暫存區和工作區。
- 2,–soft: 重置位置的同時,保留working Tree工作目錄和index暫存區的內容,只讓repository中的內容和 reset 目標節點保持一致,因此原節點和 reset 節點之間的【差異變更集】會放入index暫存區中(Staged files)。所以效果看起來就是工作目錄的內容不變,暫存區原有的內容也不變,只是原節點和 Reset 節點之間的所有差異都會放到暫存區中。
- 3,–mixed(默認): 重置位置的同時,只保留 Working Tree 工作目錄 的內容,但會將 Index暫存區 和 Repository 中的內容更改和reset目標節點一致,因此原節點和Reset節點之間的【差異變更集】會放入Working Tree工作目錄中。所以效果看起來就是原節點和Reset節點之間的所有差異都會放到工作目錄中。
3,git stash
git stash這個命令可以將當前的工作狀態保存到git棧,在需要的時候再恢復
1)git stash
保存當前的工作區與暫存區的狀態,把當前的工作隱藏起來,等以後需要的時候再恢復,git stash 這個命令可以多次使用,每次使用都會新加一個stash@{num},num是編號。
git stash # 緩存
git stash save "add test_njh" # 緩存並mark
2)git stash pop
默認恢復git棧中最新的一個,也可以指定緩存stash@{num},pop後將自動刪除選中緩存。
git stash pop # 默認爲最新的緩存
git stash pop stash@{0} # 指定最新的緩存
3)git stash list
查看所有被隱藏的文件列表
git stash list
4)git stash apply
恢復被隱藏的文件,但是git棧中的這個不刪除,用法:git stash apply stash@{0},如果我們在git stash apply 的時候工作目錄下的文件一部分已經加入了暫存區,部分文件沒有,
當我們執行git stash apply之後發現所有的文件都變成了未暫存的,如果想維持原來的樣子,即暫存過的依舊是暫存狀態,那麼可以使用 git stash apply --index。pop後將繼續保存選中緩存。
git stash apply stash@{0}
5)git stash drop
刪除指定的一個進度,默認刪除最新的進度,使用方法如git stash drop stash@{0}
git stash drop stash@{0}
6)git stash clear
刪除所有存儲的進度
git stash clear
7)git stash show
顯示stash的內容具體是什麼,使用方法如 git stash show stash@{0}
git stash show stash@{0}
git stash show stash@{1}
8)查看幫助
git stash --help
4,git revert
適用場景: 如果我們想撤銷之前的某一版本,但是又想保留該目標版本後面的版本,記錄下這整個版本變動流程,就可以用這種方法。
原理: git revert是用於“反做”某一個版本,以達到撤銷該版本的修改的目的。比如,我們commit了三個版本(版本一、版本二、 版本三),突然發現版本二不行(如:有bug),想要撤銷版本二,但又不想影響撤銷版本三的提交,就可以用 git revert 命令來反做版本二,生成新的版本四,這個版本四里會保留版本三的東西,但撤銷了版本二的東西。
# 1,查看log版本
git log # 或者git reflog
# 2,revert版本
git revert -n 版本號
# 3,commit提交
git commit -m "***"
# 4,push
git push origin devlop:devlop
5,git diff
1)git diff < filename >
意義:查看文件在工作目錄與暫存區的差別。工作目錄 vs 暫存區
git diff <filename>
也可查看和另一分支的區別。
git diff <branch> <filename>
2)git diff < commit > < filname >
意義:查看工作目錄同Git倉庫指定 commit 的內容的差異。工作目錄 vs Git倉庫
<commit>=HEAD
時:查看工作目錄同最近一次 commit 的內容的差異。
git diff <commit> <filename>
3)git diff --cached
意義:表示查看暫存區與本地倉庫內容的差異。暫存區 vs Git倉庫
git diff --cached <filename>
也可查看和另一分支的區別。
git diff --cached <commit> <filename>
4)git diff < commit > < commit >
意義:Git倉庫任意兩次 commit 之間的差別。Git倉庫 vs Git倉庫
git diff <commit> <commit>
5)擴展:
以上命令可以不指定 ,則對全部文件操作。
以上命令涉及和 Git倉庫 對比的,均可使用git log 或者 git reflog 指定 commit 的版本。
- HEAD 最近一次 commit
- HEAD^ 上次提交
- HEAD~100 上100次提交
- 每次提交產生的哈希值
6,git checkout
Git 中的 HEAD 可以理解爲一個指針,我們可以在命令行中輸入 cat .git/HEAD 查看當前 HEAD 指向哪兒,一般它指向當前工作目錄所在分支的最新提交。
cat .git/HEAD
# -----
ref: refs/heads/devlop # 指針指向devlop分支
1)git checkout(後面不加任何參數)
意義:表示查看工作區和緩存區中,加入到版本管理的文件的修改。
2)git checkout filename
意義:表示當沒有提交版本號時將工作區的指定文件的內容恢復到暫存區的狀態.
git checkout .
將工作區的所有文件的內容恢復到暫存區的狀態。(工作區新增的文件不做修改)
3)git checkout + 分支名
意義:表示切換分支.
4)git checkout -b 分支名
意義:表示以當前分支的當前狀態創建新分支並切換到新分支 -b 表示創建新分支
5)git checkout -b 分支名 commitID
意義:表示以當前分支的commitID提交節點創建新的分支並切換到新分支。此時工作區的內容和切換分之前commitID提交節點的內容一樣。
6)git checkout commitID
意義:是以指定的提交節點創建了一個臨時性分支,此臨時性分支可用於做實驗性修改。
7)git checkout < commit > filename
意義:當有提交版本號時,表示將工作區和暫存區都恢復到版本庫指定提交版本的指定文件的狀態,此時HEAD指針不變,此時的狀態相當於把工作區的內容修改到指定版本的文件內容後,再把修改的內容添加到暫存區。因此git checkout < commit > filename後,可以直接執行git commit而不需要先執行git add。
7,git merge 和 git rebase
在分支合併時,有兩種方式:git merge 和git rebase
# git merge:
git merge 分支名
# git rebase:
git rebase 分支名
例如:
現在在master分支上創建一個dev分支,然後在dev分支上進行兩次提交,添加dev1.txt,dev2.txt,日誌信息如下:
同時在master分支上進行兩次提交,添加master1.txt,master2.txt,日誌信息如下:
現在要把dev分支合併到master分支
使用merge命令合併:git merge dev
使用rebase命令合併:git rebase dev
Git 會從兩個分支的共同祖先8eda20d開始提取 master 分支(當前所在分支)上的修改,即 e0779e1、ae0decb,再將 master 分支指向 dev的最新提交(目標分支)即 e45d38f處,然後將剛剛提取的修改依次應用到這個最新提交後面。操作會捨棄 master 分支上提取的 commit,同時不會像 merge 一樣生成一個合併修改內容的 commit,相當於把 master 分支(當前所在分支)上的修改在 dev分支(目標分支)上原樣複製了一遍。
總結
- merge 是一個合併操作,會將兩個分支的修改合併在一起
- merge 的提交歷史忠實地記錄了實際發生過什麼,關注點在真實的提交歷史上面
- rebase 並沒有進行合併操作,只是提取了當前分支的修改,將其複製在了目標分支的最新提交後面
9,git fetch
1)git fetch <遠程主機名>
git fetch <遠程主機名>
上面命令將某個遠程主機的更新,全部取回本地;通常用來查看其他人的代碼進程,因爲它取回的代碼對你本地的開發代碼沒有影響;
2)git fetch <遠程主機名> <分支名>
git fetch <遠程主機名> <分支名>
上面命令取回特定分支的更新;
例如(取回origin主機的master分支 ):
git fetch origin master
# 取回的更新,在本地主機上要用"遠程主機名/分支名"的形式讀取。
# 比如origin主機的master,就要用origin/master讀取;
3)代碼合併
## 在本地新建一個temp分支,並將遠程origin倉庫的master分支代碼下載到本地temp分支;
$ git fetch origin master:temp
## 比較本地代碼與剛剛從遠程下載下來的代碼的區別;
$ git diff temp
## 合併temp分支到本地的master分支;
$ git merge temp
## 如果不想保留temp分支,刪除;
$ git branch -d temp
4) 總結
git fetch
創建並更新本地遠程分支。即創建並更新origin/xxx 分支,拉取代碼到origin/xxx分支上;
在FETCH_HEAD中設定當前支-origin/當前分支對應,如直接到時候git merge就可以將origin/abc合併到abc分支上;
git fetch origin
手動指定了要fetch的remote。在不指定分支時通常默認爲master;
git fetch origin dev
指定遠程remote和FETCH_HEAD,並且只拉取該分支的提交;
5)參看文檔如下:
https://www.cnblogs.com/runnerjack/p/9342362.html
https://www.jianshu.com/p/d07f5a8f604d
10,git pull
意義:git pull包含有兩個操作,一個是fetch遠程的代碼,一個是將本地當前的代碼和遠程代碼進行merge,即git fetch + git merge。
其實git pull還有一個參數可以加,即git pull -rebase,其最終效果和git pull一樣,也會fetch到遠程代碼。即git pull默認使用的是merge模式,那麼git pull -rebase指定使用rebase模式。
git pull
git pull --rebase / gitpull -r / git pull origin devlop --rebase
11,git branch
1)git branch
意義:查看本地所有分支和所在分支
2) git branch -r
意義:查看遠程所有分支
3) git branch -a
意義:查查看本地和遠程分支
4)git branch
意義:新建分支
5)git branch -d 分支名
意義:刪除分支
6)git branch -d -r
意義:刪除遠程分支,刪除後還需推送到服務器
7)git push origin --delete 分支名
意義:刪除遠程的分支
8)git branch -m
意義:重命名本地分支
四,常見問題解決
1,版本回退
方法一:git reset
原理: git reset的作用是修改HEAD的位置,即將HEAD指向的位置改變爲之前存在的某個版本,如下圖所示,假設我們要回退到版本。
適用場景: 如果想恢復到之前某個提交的版本,且那個版本之後提交的版本我們都不要了,就可以用這種方法。
1)git log 或 git reflog
查看commit提交版本
2)git reset --hard 版本號
命令版本回退到目標版本號
3)git push -f 強制推送
使用git push -f 強制推送
注意:
1, git push 直接提交會報錯。
2, 主幹master上不能執行此操作。
方法二:git revert
原理: git revert是用於“反做”某一個版本,以達到撤銷該版本的修改的目的。比如,我們commit了三個版本(版本一、版本二、 版本三),突然發現版本二不行(如:有bug),想要撤銷版本二,但又不想影響撤銷版本三的提交,就可以用 git revert 命令來反做版本二,生成新的版本四,這個版本四里會保留版本三的東西,但撤銷了版本二的東西。
適用場景: 如果我們想撤銷之前的某一版本,但是又想保留該目標版本後面的版本,記錄下這整個版本變動流程,就可以用這種方法。
1)查看版本號:
使用 git log 查看版本
2)使用“git revert -n 版本號”反做,並使用“git commit -m 版本名”提交:
(1)revert,使用“git revert -n 版本號”命令。
git revert -n 0f7f2bdffa3775b65561625f4d7a68dfeccd6c69
注意: 這裏可能會出現衝突,那麼需要手動修改衝突的文件。而且要git add 文件名。
(2)提交,使用“git commit -m 版本名”,如:
git commit -m "revert add b.py"
3)使用“git push”推上遠程庫:
git push origin devlop:devlop
2,處理 git pull 時 報錯信息:There is no tracking information for the current…
1)問題現象如下:
# 報錯信息如下:
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details
2)問題原因
出現該問題因爲 在進行git pull / push操作時 沒有指定branch而產生的報錯信息。
3)解決方法
git branch --set-upstream master origin/master
git branch --set-upstream develop origin/develop
或者:
git pull origin develop --rebase
git pull origin master --rebase
3,遠程倉庫已經刪除了分支,本地git branch -r 還可以顯示出來問題
1)查看remote地址,遠程分支,還有本地分支與之相對應關係等信息
git remote show origin
2)刪除那些遠程倉庫不存在,本地還存在的分支。
git remote prune origin