?????????Hello大家好!很高興我們又見面啦!給生活添點passion,開始今天的編程之路!
我的博客:<但凡.
我的專欄:《編程之路》、《數據結構與算法之美》、《C++修煉之路》、《Linux修煉:終端之內 洞悉真理》
感謝你打開這篇博客!希望這篇博客能為你帶來幫助,也歡迎一起交流探討,共同成長。
? ? ? ? 這一期我們主要來說一下git中版本回退和分支的概念。
目錄
1、版本回退
? ? ? ? 1.1、版本回退的操作
? ? ? ? 1.2、版本回退的理解?
2、撤銷修改
3、分支
? ? ? ? 3.1、分支基礎操作
? ? ? ? 3.2、分支深入理解
?????????3.2.1、合并沖突
? ? ? ? 3.2.2、合并模式
? ? ? ? ??3.2.3、bug分支
? ? ? ? 3.2.4、刪除臨時分支
1、版本回退
? ? ? ? 1.1、版本回退的操作
????????如果我們想恢復到上一次提交,我們該怎么做呢?
? ? ? ? 現在,我準備了一個readme文件,并且在文件中分三次提交了test1,test2,test3:
? ? ? ? 我們使用以下命令回退到上一個版本:
git reset --hard HEAD~1
? ? ? ? 但是,沒有那么簡單,我們有三點細節需要說明:
? ? ? ? 第一,我們以上的命令是把工作區,暫存區,版本庫全部回到了上一個版本,但是,在實踐中我們可能只向讓其中一個或兩個回退,那么這個回退的范圍是根據選項來區分的,其中--mixed是默認選項。
? ? ? ? ?那么我們怎么控制回退的版本呢?我們HEAD后面跟的數字就是回退的版本數,沒錯,我們可以一次性回退兩個版本。
? ? ? ? 我們恢復到最開始的樣子,再次回退,但是不回退工作區,只回退暫存區和版本庫:
? ? ? ? 接著使用命令查看工作區和暫存區的內容區別:
git diff
? ? ? ? 我們可以使用命令查看當前的本地倉庫內容,或者叫查看最后一次提交:
git show HEAD
? ? ? ? 我們再使用以下命令,打印版本庫和暫存區的區別:
git diff --cached HEAD
? ? ? ? ?第二,我們以上的更改都是對本地倉庫進行的修改,如果我們想遠端更新,就得在強制推送覆蓋遠端內容,使用以下命令:
git push --force origin <branch-name>
?????????但是,這樣很明顯是不安全的,在多協作場景下強制推送會導致其他開發者的進度丟失。我們可以使用以下命令代替:
git revert HEAD
? ? ? ? 我們就不實驗了,以后我們會詳細講。?
? ? ? ? 第三,如果我們版本更新了一百次,但是我們要回到第一次更新,怎么辦呢?
? ? ? ? 我們可以使用命令,打印出歷史上每次更新的commit id:
git log --pretty=oneline
? ? ? ? 接著執行以下命令,回退到指定版本:
git reset [選項] commit id
? ? ? ? 現在我們回退到test1提交。
? ? ? ? 然后我后悔了,這時候怎么辦呢?我們可以執行以下命令,查看我們想要回到的那個版本的commit id:
git reflog
? ? ? ? 接著復制commit id,和剛才一樣的操作,回到指定版本。?
? ? ? ? 1.2、版本回退的理解?
?????????git是如何實現以上版本版本回退的操作的呢?
? ? ? ? 我們可以發現,git的版本回退實際上速度是很快的。因為git內部有個指向當前分支的HEAD指針,在refs/heads/master文件中保存著master分支最新的commit id,當我們版本回退時,僅僅是更改一下指針的指向:
2、撤銷修改
? ? ? ? 有時候,我們想撤銷一些區域的修改,比如說我們想讓工作區的新增內容撤銷,而不改變暫存區和工作區。那么這種情況在版本回退中是沒有對應的指令的,此時我們該怎么辦呢?
? ? ? ? 我們分別討論以下三種情況:
? ? ? ? 情況一:
? ? ? ? 這種情況下我們可以選擇手動修改,不過更好的方式是使用以下指令:
git checkout -- 文件名
? ? ? ? 情況二:
? ? ? ? 這種情況我們可以直接使用git reset --hard。因為我們可以拿到上一次提交的commit id,然后恢復版本,這樣的話實際上版本庫是不進行更改的,而工作區和暫存區回退到上一個版本了。從整體來看,就是我們使用git reset回退到了當前版本。
? ? ? ? 或者我們使用git reset? --mixed,?此時就和情況一一樣了,然后我們再按照情況一的方法更改。
? ? ? ? ?情況三:
? ? ? ? 這種情況我們直接使用git reset --hard HEAD~1就好了。在這里還是要強調一下,我們這些修改都是針對本地倉庫來說的,對于遠程倉庫的操作我們以后再說。
3、分支
? ? ? ? 3.1、分支基礎操作
? ? ? ? Git 分支是開發中用于隔離不同工作流的獨立線路。每個分支代表一個獨立的提交歷史,便于并行開發、實驗性功能實現或問題修復,而不會影響主分支。
? ? ? ? Git的分支功能是一個非常強大的功能,分支功能的出現,就允許了一個團隊中的不同成員,同時進行項目不同部分的開發,并在開發完成之后,合并到主分支中。大家可以想一下,有了分支功能,我們的總體效率會大大的提高。
? ? ? ? 現在我們就先來簡單介紹一下如何創建分支和和并分支。
? ? ? ? ?首先我們使用以下命令查看當前的分支:
git branch
? ? ? ? 我們使用以下命令創建分支:
git branch 分支名
? ? ? ? 我們的HEAD默認是指向master的,HEAD被指向的分支就是當前工作的分支。
????????我們可以通過以下指令查看當前的HEAD指向哪個分支:
cat .git/HEAD
? ? ? ? 當然,直接branch也可以看當前在那個分支,分支前帶星號的就是當前分支:
? ? ? ? ?我們可以通過以下命令切換分支:
git checkout dev
? ? ? ? 現在,我們在dev分支上進行一些修改代碼,提交的操作,我們來理解一下這個過程:
? ? ? ? master和dev這兩個分支始終指向自己這個分支上最新的一次提交。如果我們在dev分支提交東西,那么dev分支創建出一個新的提交節點,并且指向他。?
? ? ? ? 接下來我們合并兩個分支:
git merge 分支名
? ? ? ? 需要注意的是我們不能在當前分支下合并自己。我們得先切換到master分支然后git merge dev。當然了我們其實也可以把master合并到dev上。
? ? ? ? 我們來看一下合并之后的狀態圖:
? ? ? ? 接下來我們介紹一下如何刪除分支:
git branch -d 分支名
? ? ? ? 我們不能刪除當前的分支。?
? ? ? ? 3.2、分支深入理解
?????????3.2.1、合并沖突
? ? ? ? 當我們合并的兩個分支內容發生沖突時,就會出現合并沖突的情況,比如,兩個分支分別在同一個文件中添了一行不同的代碼,此時如果進行合并操作,git就鬧不清我們到底該保留哪一行代碼了。
? ? ? ? 我們首先創建一個這樣的情景,在dev分支中,我們為readme文件添加一行“dev test”字符串,在master分支中添加一行"master test"。接著我們嘗試把dev合并到master上:
? ? ? ? 我們嘗試合并操作,他會提示合并失敗,接著我們打開readme文件:
? ? ? ? git已經給我們顯式出了沖突內容,我們需要手動刪除,保留需要更改的部分。接下來我們使用git add .和git commit就可以了。
? ? ? ? ?我們可以通過以下命令,查看我們合并過程的圖示:
git log --graph --abbrev-commit
? ? ? ? 3.2.2、合并模式
? ? ? ? ?其實merge的模式是可以選擇的。默認我們使用的都是ff(fast forward),這種模式的合并我們看不出來是merge出來的還是commit出來的。所以我們一般使用no-ff模式:
git merge --no-ff dev
Fast-Forward (FF) 模式
????????當目標分支(如 main
)的最新提交是當前分支(如 feature
)的直接祖先時,Git 默認會采用 FF 模式合并。這種合并不會創建新的合并提交,而是簡單地將 main
分支的指針移動到 feature
分支的最新提交上。歷史記錄保持線性,沒有分叉。
A --- B --- C (main)\D --- E (feature)
執行 git merge feature
后(FF 模式):
A --- B --- C --- D --- E (main)
No-Fast-Forward (--no-ff) 模式
????????通過 git merge --no-ff
強制禁用 FF 模式,即使滿足 FF 條件,Git 也會創建一個新的合并提交。這會保留分支的拓撲結構,明確顯示分支的合并點,便于追蹤歷史。
A --- B --- C (main)\D --- E (feature)
執行 git merge --no-ff feature
后:
A --- B --- C --------- F (main)\ /D --- E ------
? ? ? ? 為了我們的提交記錄更清晰,我們推薦使用no-ff模式。
? ? ? ? ??3.2.3、bug分支
? ? ? ? 在開發的過程中,我們經常利用臨時分支來修復bug。比如現在我們的master分支上就出現了一個bug,我們會新建一個分支,在這個分支上修復bug,最后再合并。
? ? ? ? 那么假設我們已經有了一個分支,并且正在這個分支上寫代碼,這時突然發現master上有bug,我們想用這個分支去修復bug,可是這個分支的開發內容剛進行了一半,我們也無法提交了,這時候該怎么辦呢?
? ? ? ? 在git中,我們可以使用git stash命令,對當前工作區信息進行存儲,被存儲的內容以后可以恢復出來。說白了,就是暫時保存一下當前分支的代碼:
git stash
?????????我們可以通過命令查看工作區:
git status
?????????接著我們就可以安心的切回到master分支,然后新建修改bug的臨時分支。
? ? ? ? 當我們修復完分支之后,可以切換回剛才的分支,我們剛才的代碼可以用以下命令查看:
git stash list
? ? ? ? 我們可以通過以下命令恢復現場:
git stash pop
? ? ? ? 我們可以使用以下命令來恢復現場:
git stash apply #恢復現場但不刪除stash內容
git stash drop #刪除stash內容
? ? ? ? 接著我們完成dev分支的任務,合并到master上。?
? ? ? ? 此時的狀態圖應該是這樣的:
? ? ? ? 但是我們不建議這樣修復bug!因為在最終dev合并到master上是可能會有沖突。我們手動解決沖突的話無法保證對于沖突問題一次性解決掉,因為在實際的項目中,代碼沖突不只一兩行那么簡單。
? ? ? ? 我們建議的是在合并時首先把master合并到dev上,在dev分支測試沒問題之后再合并到master上:
? ? ? ? 3.2.4、刪除臨時分支
?????????如果我們的分支已經完成了合并,那我們可以使用之前的刪除分支命令,可是如果這個分支還沒有完成合并,我們想要刪除他,就需要以下命令:
git branch -D 分支
? ? ? ? 好了,今天的內容就分享到這,我們下期再見!?