Git版本控制工具:進入學習
在某個月黑風高的晚上,一臉愁容的女朋友突然跟我說,Git 老搞不明白,有什麼比較好的經驗可以分享下嗎,說時遲,那時快,二話不說,立馬開始奮筆疾書......
在平時的 Coding 過程中,我們還是需要一定的 Git 操作的能力的。但是總還是存在一些場景自己突然想不起來,某個場景,應該使用什麼 Git 命令可以滿足自己的訴求,這個時候又需要開啟 Google / Baidu,各種搜尋一番,與其把時間消磨在這一次次的重複工作中,倒不如好好研究一下我們常用的命令的玩法。在這裡,本文也將提供一系列的案例,為大家介紹這些常用的 Git 的體系和命令的應用場景以及大體的使用方式。
當然,除了我們需要了解 Git 的命令使用方式之外,我們也應該來了解下 Git 是的整個體系結構是怎麼樣的,這樣才能更加清晰的知道我們每天操作的命令都是在做什麼。
如有表述不當之處,感謝指正!
開局一張圖,結論先靠猜。
遠端倉庫區
:也就是我們程式碼最終提交的歸宿,沒啥好說的。遠端分支本地副本
:這個其實主要儲存了遠端倉庫各分支資料在原生的一個副本,你可以開啟你 Git 專案下的 .git 檔案,裡面有個 refs/remotes,這裡就主要存的就是遠端倉庫的分支資訊,一般你執行 push 或者 pull、fetch 都會往這裡進行更新。本地分支
:這裡就是我們經常會打交道的區域,你在執行 commit 之後,本質上就是提交到了這個區域,你可以檢視你的 .git 目錄下的 refs/heads 目錄,裡面存的就是我們原生的分支程式碼資訊。暫存區
:這個區域就是我們每次執行 git add 之後會存到的區域,用來與本地倉庫之間做一個快取,同時也是 Git 底層設計上來說也算是比較重要的一個區域,它能幫助 Git 在做 diff 的時候提高查詢效能。工作區
:這個一般就是我們寫程式碼的地方,比如你的 vscode 開啟的專案,你可以進行程式碼編輯的地方。除此之外,還有一個特殊的區域,那就是原生的 git 儲存區,它是用來幹嘛的呢?一般來說你可能在某些場景下會用到它,我們有的時候本地改了程式碼,但是突然有個人過來問你另一個分支的問題,同時這個時候你在實現某個功能,實現一半,又不想提交到 Git 倉庫中,那麼你就可以考慮使用 git stash save "臨時存一下"
,這個時候它就會幫你存到這個儲存區,你去其他分支做完事情回來,再 git stash pop
就好了。
但筆者還是不是很建議使用這個功能,因為哪天你切走了再切回來,忘記了這個儲存,又寫了點其他的,這個時候你到時候被坑一把就哭吧。當然了,這個功能還是很有用的,但是的確需要細心點用。
日常工作中,我們可能在 Git 使用上頻繁互動的流程大致會是這樣的(不同規範下會有一些區別,但是大差不大):
git add
將程式碼提交到暫存區。git commit
將程式碼提交到本地倉庫git push
將程式碼提交到遠端分支以上流程大致概括了一般常規的 Git flow 流程,不同的公司可能會設計自己的規範,這裡就不過多指示了。
git stash
git clone
git init
git remote
git branch
git checkout
git add
git commit
git rm
git push
git pull
git fetch
git merge
git log
git reset
git reflog
git revert
git cherry-pick
git tag
git rebase
乍一看,眼花繚亂,當場決定放棄,還是用視覺化工具吧。莫慌,且讓筆者為你娓娓道來。
一般來說,我們本地如果想要使用 Git 管理一些資原始檔,首先我們需要有一個倉庫才行。常用的方式莫過於,第一去 Gitlab / Github 先建立一個倉庫,然後再拉到本地,那這個時候我們就可以用到我們的 clone 命令了。
上面也有初步介紹這個命令的用法,就是用來臨時存一下不想被提交的程式碼變更的,常用命令如下:
git stash save 'xxx'
: 儲存變更git stash list
: 檢視儲存區所有提交列表git stash pop
: 彈出並應用最近的一次儲存區的程式碼提交git stash drop stash@{n}
: 刪除某次儲存記錄git stash clear
: 清楚所有 stash 資訊它的資料將被存在你倉庫 .git 檔案下的 refs/stash 裡。
最基礎也是最常用的用法莫過於直接使用
git clone xxx.git
這樣就能輕鬆把一個倉庫程式碼拉到本地了,但僅僅知道這一點似乎還不太夠。一般我們直接 clone 下來不帶引數的話,它會預設停留在 master 分支,有的時候我們依舊需要一些其他訴求,比如怎麼拉到本地之後自動切到指定分支呢?
git clone xxx.git -b branch1
有了倉庫之後,我們總不能一直在 master 分支搞事吧,一般是不是都需要開個新分支改程式碼,再最後完事了再合到 master,那就需要用到下面介紹 git branch 命令了,不過呢,在講到具體的分支操作之前呢,筆者還是要先補一下有關於本地倉庫的初始化的流程。
除了我們從遠端建倉庫,有的時候我們自己本地也是可以自己初始化一個 Git 倉庫來操作的,這個時候我們就直接使用 git init 就能輕鬆為當前目錄建立一個 git 倉庫,也就能開始對當前目錄的改動納入版本管理庫了。
不過本地 init 的倉庫沒法和遠端進行互動,所以我們還是需要去 github/gitlab 建立一個遠端倉庫,然後關聯一下,也就是 git remote
命令了。
用於和遠端倉庫進行關係繫結處理等等操作。
git remote add
: 新增一個遠端版本庫關聯git remote rm
: 刪除某個遠端版本庫關聯比如我們本地有個初始化好的倉庫,同時還有一個建立好的遠端空倉庫,那麼我們就可以執行一下操作讓他們關聯起來:
git remote add origin xxx.git
先新增到本地倉庫git push -u origin master
:表示把當前倉庫的 master 分支和遠端倉庫的 master 分支關聯起來,後面我們執行 push 或者 pull 都可以非常方便的進行操作了。在拿到一個專案之後,你首先還是應該看一下當前倉庫現在有哪些分支,不要待會建立新分支發現名字重複之類的問題,那這個時候我們就可以使用 git branch
來檢視一下相關的分支了。
git branch
:檢視本地所有分支資訊git branch -r
:檢視遠端倉庫所有分支git branch -a
:檢視本地和遠端倉庫所有分支一般來說如果分支太多的話,還是建議使用視覺化工具來檢視分支資訊,比如 vscode 或者 source tree 等軟體等等。
當然 IDEA 也是可以的。
如果我們想以當前分支為基準,建立一個新的分支並切換過去,可以使用如下命令。
git checkout -b branch1
我們在某個分支更改了程式碼之後,想要把它提交一下,那麼你第一步要做的就是,執行 git add
git add [file1] [file2]
: 新增一個或多個檔案到暫存區一般我們平時在使用的時候,用的比較多的應該還是:
git add .
:把當前目錄下得所有檔案改動都新增到暫存區git add -A
:把當前倉庫內所有檔案改動都新增到暫存區對筆者來說,用的最多的還是這個 git add -A 命令,因為大多數情況,我們都應該把所有變更都加到暫存區裡,如果沒有,那大概率是忘了。
檔案新增到暫存區之後,我們就可以執行下一步操作了。
git commit [file1] ... -m [message]
:將暫存區的內容提交到本地 git 版本倉庫中git add -A
,你就不用再 add 一下了;對於未被 git 管理過的(也就是新增的檔案),那麼還是需要你先執行一下 git add -A
,才能正確被 commit 到本地 git 庫。通常情況下,我們用的比較多得應該是 git commit -m 'feat: do something'
,設定當前提交的資訊。當然,如果你沒有強訴求需要 git add
和 git commit
一定要分開,那你大可選擇 git commit -am
,方便又快捷。
這個其實也挺有用的,比如我們專案中有個檔案叫 .env,這個檔案是一個私有的,不能被提交到遠端的,但是我們不小心提交到了本地倉庫中,這個時候我們把這個檔案新增到 .gitignore 檔案中,表示需要被 git 忽略提交,但是由於我們已經提交到本地倉庫了,所以如果不先從 git 倉庫刪除是沒用的。
如果直接右鍵刪除,那麼這個檔案的記錄還是會被儲存到遠端倉庫,別人還是能看得到你這個資訊,所以我們需要先從 git 倉庫中刪掉這個檔案才行。
git rm .env
:執行完這個命令就表示 .env 檔案從 git 倉庫中刪除了,配合 .gitignore 就能保證以後所有的 .env 檔案變更都不用擔心被提交到遠端倉庫。
git rm -r dist
:如果我們要刪除的是一個目錄,那麼加上 -r 引數就好了。
接下來我們想要把剛建立好得分支推播到遠端,一般來說我們可能會需要用到 git push,但我們這是個新分支,根本沒和遠端倉庫建立任何聯絡,那麼我們就需要加點引數,讓他們關聯上:
git push --set-upstream origin branch1
完事之後我們可以再去遠端倉庫看一眼就會發現我們建立的新分支已經推上去了。接下來可能會有小夥伴要問了,那如果遠端倉庫已經有了這個分支名咋整?
這裡就分兩種:
通常情況下,如果當前分支已經和遠端分支建立了聯絡,那麼我們想要合併一下遠端分支,只需要執行 git pull
就好了,不用帶其他引數,但如果和上面提到的 git push 時產生了衝突,還沒有建立聯絡的時候,我們就需要指定需要拉取哪個分支的程式碼下來進行合併了。
git pull origin branch1
這裡的 origin 是我們對遠端倉庫的命名,想改也是可以的,不過一般都是用的 origin。
回到上面提到的衝突問題,我們可以直接使用 git pull 然後指定合併當前本地分支想要建立聯絡的遠端分支,然後本地解決一下衝突,然後提交一下改動,再執行 git push --set-upstream origin branch1
命令就大功告成了。
瞭解完上面描述的 git pull
,命令之後,其實這個命令也很好理解了,特定時候,可能我們只是想把遠端倉庫對應分支的變更拉到本地而已,並不想自動合併到我的工作區(你當前正在進行程式碼變更的工作區),等晚些時候我寫完了某部分的程式碼之後再考慮合併,那麼你就可以先使用 git fetch
。
fetch 完畢之後,我提交了自己當前工作去的變更到本地倉庫,然後想合併一下遠端分支的更改,這個時候執行一下 git merge origin/[當前分支名]
(預設一般是用 origin 表示遠端的分支字首)即可。
合併指定分支程式碼到當前分支。一般來說,我們用的比較多的場景可能是,遠端倉庫 master 分支有變更了,同時這個時候我們準備提 MR 了,那麼就需要先合一下 master 的程式碼,有衝突就解決下衝突,那這個時候我們可以做以下操作:
同理,上面介紹的 git merge origin/xxx 也是一樣的用法。
顧名思義,就是紀錄檔的意思,執行這個命令之後,我們能看到當前分支的提交記錄資訊,比如 commitId 和提交的時間描述等等,大概長下面這樣:
commit e55c4d273141edff401cbc6642fe21e14681c258 (HEAD -> branch1, origin/branch1)
Author: 陌小路 <[email protected]>
Date: Mon Aug 1 23:16:11 2022 +0800
Initial commit複製程式碼
登入後複製
這個時候可能有讀者會問了,這個都用來幹啥的,簡單的用法呢就是看看有誰提交了啥,還有更重要的用法呢就是進行程式碼版本的回滾,或者其他有意思的操作,且聽筆者為你微微道來。
以下解析均基於後接引數為 HEAD^,也就是git reset HEAD^
。
--soft
: 重置你最新一次提交版本,不會修改你的暫存區和工作區。--mixed
: 預設引數,用於重置暫存區的檔案與上一次的提交(commit)保持一致,工作區檔案內容保持不變。--hard
: 重置所有提交到上一個版本,並且修改你的工作區,會徹底回到上一個提交版本,在程式碼中看不到當前提交的程式碼,也就是你的工作區改動也被幹掉了。說了半天似乎不是很好理解,我們舉個栗子理解下:
比如:
git add
,這個時候你檢視暫存區,會發現這次改動被提交進去了,同時被 vscode 標記為已被提交至暫存區git commit
,這個時候就完成了一次提交接下來我們想撤回這次提交,以上三種引數所體現的表現會是這樣的:
--soft
:我們對 README 的更改狀態現在變成已被提交至暫存區,也就是上面 2 的步驟。--mixed
: 我們對 README 的更改變成還未被提交至暫存區,也就是上面 1 的步驟。--hard
:我們對 README 的所有更改全沒了,git log 中也找不到我們對 README 剛剛那次修改的痕跡。預設情況下我們不加引數,就是 --mixed,也就是重置暫存區的檔案到上一次提交的版本,檔案內容不動。一般會在什麼時候用到呢?
可能大部分情況下,比如 vscode 其實大家更習慣於使用視覺化的復原能力,但是呢,這裡我們其實也可以稍微瞭解下這其中的奧祕,其實也很簡單:
git reset
git reset HEAD
其實一二都是一樣,如果 reset 後面不跟東西就是預設 HEAD。
當你某個改動提交到本地倉庫之後,也就是 commit 之後,這個時候你想撤回來,再改點其他的,那麼就可以直接使用 git reset HEAD^
。這個時候你會驚奇的發現,你上一版的程式碼改動,全部變成了未被提交到暫存區的狀態,這個時候你再改改程式碼,然後再提交到暫存區,然後一起再 commit 就可滿足你的需求了。
除了這種基礎用法,我們還可以配合其他命令操作一下。
某一天你老闆跟你說,昨天新加的功能不要了,給我切回之前的版本看看效果,那麼這個時候,你可能就需要將工作區的程式碼回滾到上一個 commit 版本了,操作也十分簡單:
git log
檢視上一個 commit 記錄,並複製 commitIdgit reset --hard commitId
直接回滾。如果某一個你開發需求正開心呢,突然發現,自己以前改的某個東西怎麼不見了,你想起來好像是某次合併,沒注意被其他提交沖掉了,你心一想,完了,寫了那麼多,怎麼辦?很簡單,回到有這份程式碼的那個版本就好了(前提你提交過到本地倉庫)。
假設我們有這麼兩個提交記錄,我們需要下面那個 365 開頭 commitId 的程式碼:
commit e62b559633387ab3a5324ead416f09bf347d8e4a (HEAD -> master)
Author: xiaohang.lin <[email protected]>
Date: Sun Aug 14 18:08:56 2022 +0800
merge
commit 36577ea21d79350845f104eee8ae3e740f19e038 (origin/master, origin/HEAD)
Author: 陌小路 <[email protected]>
Date: Sun Aug 14 15:57:34 2022 +0800
Update README.md複製程式碼
登入後複製
git log
找到有你這個程式碼的那個 commitId(也就是 36577ea21d79350845f104eee8ae3e740f19e038)git reset --hard commitId
這個時候你想把複製好的程式碼寫回去,該怎麼辦呢,你可能會再 git log 看一下我們 reset 之前的 commitId,你會發現,完了,之前的 commitId 都沒了,只有這個 365 了。
commit 36577ea21d79350845f104eee8ae3e740f19e038 (origin/master, origin/HEAD)
Author: 陌小路 <[email protected]>
Date: Sun Aug 14 15:57:34 2022 +0800
Update README.md複製程式碼
登入後複製
不要慌,請記住一句話,只要你不刪你原生的 .git 倉庫,你都能找回以前所有的提交。
git log 看不到的話,我們就可以祭出我們的絕招了:git reflog
36577ea (HEAD -> master, origin/master, origin/HEAD) HEAD@{0}: reset: moving to 36577ea21d79350845f104eee8ae3e740f19e038
e62b559 HEAD@{1}: reset: moving to e62b559633387ab3a5324ead416f09bf347d8e4a複製程式碼
登入後複製
這裡我們可以看到兩行記錄,一個是我們執行 reset 到 365 的記錄,另一條不知道是啥,不重要,我們想回到我們剛剛 reset 之前的狀態也很簡單,直接複製它上一次的變動也就是這個 e62b559,然後執行 git reset --hard e62b559
,然後你會驚奇的發現,你之前的程式碼又回來了。
接下來把你以前版本的程式碼,再 Ctrl + v 放進來就完成了。
介紹:用來檢視你的所有操作記錄。
既然 git log 看不到我之前 commitId 了,那麼就回到 reset 之前的狀態吧!
當然了,如果是針對 master 的操作,為了安全起見,一般還是建議使用 revert 命令,他也能實現和 reset 一樣的效果,只不過區別來說,reset 是向後的,而 revert 是向前的,怎麼理解呢?簡單來說,把這個過程當做一次時光穿梭,reset 表示你犯了一個錯,他會帶你回到沒有犯錯之前,而 revert 會給你一個彌補方案,採用這個方案之後讓你得到的結果和沒犯錯之前一樣。
舉個栗子: 假設你改了 README 的描述,新增了一行文字,提交上去了,過一會你覺得這個寫了有問題,想要復原一下,但是又不想之前那個提交消失在當前歷史當中,那麼你就可以選擇使用 git revert [commitId],那麼它就會產生一次新的提交,提交的內容就是幫你刪掉你上面新增的內容,相當於是一個互補的操作。
PS D:\Code\other\git-practice> git revert 3b18a20ad39eea5264b52f0878efcb4f836931ce
On branch branch2
Your branch is ahead of 'origin/branch2' by 1 commit.
(use "git push" to publish your local commits)
登入後複製
這個時候,它會提示你可以把新的改動 push 上去了。
其實你如果在 gitlab 進行 mr 之後,想要回滾這個 mr,一般它會給你一個 revert 的按鈕選項,讓你進行更安全的回滾操作。
其實對於我們工作中大部分場景下應該用不到這個功能,但是呢有的時候這個命令又能挽救你於水火之間,那就是當某個倒黴蛋忘記切分支,然後在 master 分支上改了程式碼,並且提交到了本地倉庫中,這個時候使用git cherry-pick
簡直就是神器了。
git cherry-pick
:將執行分支的指定提交合併到當前分支。一聽介紹就來精神了,雀氏有點東西,比如我在 master 分支提交了某個需求的程式碼,同時還沒提交到遠端分支,那麼你就可以先 git log
檢視一下當前的提交,找到 master 分支正常提交之後的所有 commitId,然後複製出來,然後再切到你建好的開發分支,接著執行 git cherry-pick master commitId1 commitId2 commitId4
。
完事之後記得清理一下作案現場,把你的 master 分支程式碼恢復到正常的提交上去。
顧名思義,也就是打標籤的意思。一般可能會在你釋出了某個版本,需要給當前版本打個標籤,你可以翻閱 vite 的官方 git 倉庫,檢視它的 tag 資訊,它這裡就標註了各個版本釋出時候的 tag 標籤。
它有兩種標籤形式,一種是輕量標籤,另一種是附註標籤。
git tag v1.0.0
它有點像是對某個提交的參照,從表現上來看,它又有點像基於當前分支提交給你建立了一個不可變的分支,它是支援你直接 checkout 到這個分支上去,但是它和普通分支還是有著本質的區別的,如果你切換到了這個 tag "分支",你去修改程式碼同時產生了一次提交,亦或者是 reset 版本,這對於該 tag 本身不會有任何影響,而是為你生成了一個獨立的提交,但是卻在你的分支歷史中是找不到的,你只能通過 commitId 來切換到本次提交,看圖:
那如果你從其他分支通過 commitId 切換到這個改動上,它會提示你以下內容:
Note: switching to 'be276009'.
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:
git switch -c <new-branch-name>
Or undo this operation with:
git switch -
登入後複製
大致意思就是你可以選擇丟棄或者保留當前更改,如果需要保留的話直接使用下面的 git switch
命令建立一個新分支即可。
git tag -a v1.0.1 -m "釋出正式版 1.0.1"
參照官方檔案的描述:
而附註標籤是儲存在 Git 資料庫中的一個完整物件, 它們是可以被校驗的,其中包含打標籤者的名字、電子郵件地址、日期時間, 此外還有一個標籤資訊,並且可以使用 GNU Privacy Guard (GPG)簽名並驗證。
從概念上看,輕量標籤更像是一個臨時的標籤,而附註標籤更加正式一點,能夠保留更多的資訊。它建立的方式和輕量標籤區別主要是 -a 和 -m 引數,如果你的 -m 引數不傳,那麼編輯器會讓你手動填寫。
打完標籤之後,我們可以使用 git show
命令來看看這兩種標籤最終體現的資訊有哪些。
commit dcbd335be87f51eaa0cc1852400e64e9f46e84d8 (HEAD -> test-branch1, tag: v1.0.2, tag: v1.0.1)
Author: STDSuperman <[email protected]>
Date: Tue Aug 16 22:54:36 2022 +0800
xx
diff --git a/README.md b/README.md
index 715766a..b4cdea6 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,3 @@-# git-practice\ No newline at end of file
+# git-practice
+
+test tag
登入後複製
tag v1.0.1
Tagger: STDSuperman <[email protected]>
Date: Tue Aug 16 22:58:27 2022 +0800
釋出正式版 1.0.0
commit dcbd335be87f51eaa0cc1852400e64e9f46e84d8 (HEAD -> test-branch1, tag: v1.0.1)
Author: STDSuperman <[email protected]>
Date: Tue Aug 16 22:54:36 2022 +0800
xx
diff --git a/README.md b/README.md
index 715766a..b4cdea6 100644
--- a/README.md
+++ b/README.md
登入後複製
從資訊豐富度上來說,附註標籤能保留的資訊會更多。
git push origin tagName
$> git push origin v1.0.1Enumerating objects: 6, done.
Counting objects: 100% (6/6), done.
Delta compression using up to 12 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (4/4), 448 bytes | 448.00 KiB/s, done.
Total 4 (delta 0), reused 0 (delta 0), pack-reused 0
To github.com:STDSuperman/git-practice.git
* [new tag] v1.0.1 -> v1.0.1
登入後複製
當然,附註標籤和輕量標籤都是可以被推播到遠端的。
git tag
git tag -l v1.0.1
git tag -d v1.0.1
git push origin --delete v1.0.2
git push origin :refs/tags/v1.0.1
這塊其實涉及的玩法會相對來說複雜一點,可能還是需要拿來和 merge 做一下對比才更加有意義,東西有點多,先擱置一下。
WIP...
以上就是還沒玩轉Git?立刻安排!的詳細內容,更多請關注TW511.COM其它相關文章!