Git幾乎是每個程式設計師的標配,當然有時候也是噩夢,因為如果不是對他的各種命令非常熟悉的話,各種繞腦的命令會把我們弄暈,因為很多時候我們並不知道這個命令內部到底是怎麼樣的,如果每一個命令都有相對應的動畫,我們是不是理解起來更容易一些呢? 前不久,哥倫比亞的一位小姐姐寫了一篇這樣的文章《CS Visualized: Useful Git Commands》,文章裡她通過生動形象的動畫這樣直觀的方式,向開發者展示 Git 命令中的 merge、rebase、reset、revert、cherry-pick 等常用命令的具體原理。下面我們一起看看吧。
合併
擁有多個分支機構非常方便,以使新變更彼此分離,並確保您不會意外將未經批准或破損的變更推到生產中。更改獲得批准後,我們希望在生產部門中獲得這些更改!
將更改從一個分支轉移到另一個分支的一種方法是執行git merge!!Git可以執行兩種類型的合併:快進或無快進
現在這可能沒有多大意義,所以讓我們看一下差異!
快進(--ff)
一個快進合併相比,我們正在合併分支當前分支已經沒有多餘的提交可能發生。Git是... 懶惰,並且首先會嘗試執行最簡單的選擇:快速前進!這種類型的合併不會創建新的提交,而是會在我們當前分支中要合併的分支上合併這些提交)
完善!現在,我們dev可以在分支上獲得對master分支所做的所有更改。那麼,什麼都不是快進呢?
不速前進(--no-ff)
如果您當前的分支與您要合併的分支相比沒有任何額外的提交,那就太好了,但是不幸的是,這種情況很少!如果我們在當前分支上提交了要合併的分支所沒有的更改,則git將執行no-fast-forward合併。
通過無快進合併,Git 在活動分支上創建了一個新的合併提交。提交的父提交既指向活動分支又指向我們要合併的分支!
沒什麼大不了的,完美的合併! master現在,分支包含我們在dev分支上所做的所有更改。
合併衝突
儘管Git擅長決定如何合併分支並向文件中添加更改,但它不能總是自己一個人做出決定當我們嘗試合併的兩個分支在同一文件中的同一行上有更改時,可能會發生這種情況,或者一個分支刪除了另一個分支修改的文件,依此類推。
在這種情況下,Git將要求您幫助確定我們要保留的兩個選項中的哪一個!假設在兩個分支上,我們都編輯了第一行README.md。
如果要合併dev到master,將導致合併衝突:您希望標題是Hello!還是Hey!?
嘗試合併分支時,Git將向您顯示衝突發生的位置。我們可以手動刪除不想保留的更改,保存更改,再次添加更改的文件,然後提交更改
好極了!儘管合併衝突通常很煩人,但這是完全有意義的:Git不應僅假設我們要保留哪個更改。
變基
我們只是看到了如何通過執行可以將更改從一個分支應用於另一個分支git merge。將更改從一個分支添加到另一個分支的另一種方法是執行git rebase。
一個git rebase 副本從當前分支的提交,並提出這些複製提交指定的分支上。
太好了,我們現在可以在master分支上進行所有在分支上所做的更改dev!
與合併相比,Git的最大區別是Git不會嘗試找出要保留和不保留的文件。我們要重新定位的分支始終具有我們要保留的最新更改!這樣您就不會遇到任何合併衝突,並且可以保持良好的線性Git歷史記錄。
此示例顯示了在master分支上的基礎。但是,在較大的項目中,您通常不想這樣做。當為複製的提交創建新哈希時git rebase ,A會更改項目的歷史記錄!
每當您在Feature分支上工作時,Rebasing很棒,並且master分支已更新。您可以在分支上獲取所有更新,這將防止將來發生合併衝突!
互動基礎
在重新提交之前,我們可以對其進行修改!can我們可以通過交互式基礎來做到這一點。交互式基礎也可以在您當前正在使用的分支上使用,並且希望修改某些提交。
我們可以對基於基準的提交執行6個操作:
reword:更改提交消息edit:修改此提交squash:將提交合併到上一個提交中fixup:將提交合併到先前的提交中,而不保留提交的日誌消息exec:對要重新設置基準的每個提交運行命令drop:刪除提交太棒了!這樣,我們可以完全控制提交。如果我們想刪除一個提交,就可以drop了。
或者,如果我們要壓縮多個提交以獲取更清晰的歷史記錄,那沒問題!
交互式重定基使您可以控制要重新定基的提交,即使在當前活動分支上也是如此!
重設
可能發生了我們提交了以後不想要的更改。也許是一個WIP提交,或者一個引入了錯誤的提交!that在這種情況下,我們可以執行git reset。
一個git reset擺脫當前的所有籌備的文件,對我們的控制權,其中HEAD應指向。
軟重置
一個軟復位移動HEAD到指定的提交(或相對於提交的指數HEAD),沒有擺脫被引入於事後提交的變化!
假設我們不想保留9e78i添加style.css文件的提交,也不想保留035cc添加index.js文件的提交。但是,我們要保持最新添加style.css和index.js檔案!軟復位的理想用例。
鍵入時git status,您會看到我們仍然可以訪問對先前提交所做的所有更改。太好了,因為這意味著我們可以修復這些文件的內容,以後再提交!
硬重置
有時,我們不想保留某些提交所引入的更改。與軟重置不同,我們不再需要訪問它們。Git應該簡單地將其狀態重置為指定提交時的狀態:這甚至包括工作目錄和暫存文件中的更改!
Git放棄了在9e78i和上引入的更改035cc,並將其狀態重置為提交時的狀態ec5be。
正在還原
取消更改的另一種方法是執行git revert。通過還原某個提交,我們創建一個包含還原更改的新提交!
假設ec5be添加了一個index.js文件。後來,我們實際上意識到我們不再希望此提交引入此更改!讓我們還原ec5be提交。
完善!提交9e78i還原了提交所引入的更改ec5be。git revert為了撤消某個提交,而無需修改分支的歷史記錄,執行a 非常有用。
採摘櫻桃
當某個分支包含一個引入了我們活動分支所需的更改的提交時,我們可以執行cherry-pick該命令!通過cherry-pick提交,我們在活動分支上創建了一個新的提交,其中包含cherry-picked提交所引入的更改。
假設76d12在dev分支上的提交將更改添加到index.js我們想要在master分支中的文件。我們不想整個我們只關心這一次提交!
太酷了,master分支現在包含了76d12引入的更改!
正在取得
如果我們有一個遠程Git分支,例如Github上的一個分支,則可能發生該遠程分支具有當前分支所沒有的提交!也許另一個分支被合併了,您的同事提出了快速解決方案,依此類推。
通過git fetch在遠程分支上執行a,我們可以在本地獲取這些更改!它不會以任何方式影響您的本地分支機構:fetch只需下載新數據即可。
現在,我們可以看到自上次推送以來所做的所有更改!現在,我們可以在本地擁有新數據,然後決定要處理的數據。
拉動
儘管a git fetch對於獲取分支的遠程信息非常有用,但是我們也可以執行a git pull。A git pull實際上是兩個命令合二為一:a git fetch和a git merge。當我們從原點提取更改時,我們首先要像使用一樣獲取所有數據git fetch,之後最新的更改會自動合併到本地分支中。
太棒了,我們現在可以與遠程分支完美同步,並具有所有最新更改!
刷新日誌
每個人都會犯錯,那完全可以!有時,您可能覺得自己已經把git repo搞砸了,以致於只想完全刪除它。
git reflog這是一個非常有用的命令,用於顯示已執行的所有操作的日誌!這包括合併,重置,還原:基本上是對分支的任何更改。
如果您輸入有誤,可以HEAD根據reflog提供給我們的信息進行重置,輕鬆地重做!
假設我們實際上不想合併origin分支。當執行git reflog命令時,我們看到合併之前倉庫的狀態為HEAD@{1}。讓我們執行一次git reset將HEAD指向它所在的位置HEAD@{1}!
我們可以看到最新動作已被推送到reflog!