最近,有朋友私信讓我就`git 使用`做篇文章分享,分享一下我在日常工作中是如何使用`git`的。我當場就收費兩包辣條,最後討價還價,朋友用1.5包辣條騙到了這篇文章,等他欣喜的走了我打算直接分享出來,氣死這個吝嗇鬼,當然最終還是希望本文對你有所幫助。 ...
前言
最近,有朋友私信讓我就git 使用
做篇文章分享,分享一下我在日常工作中是如何使用git
的。我當場就收費兩包辣條,最後討價還價,朋友用1.5包辣條騙到了這篇文章,等他欣喜的走了我打算直接分享出來,氣死這個吝嗇鬼,當然最終還是希望本文對你有所幫助。
基礎概念
首先我們簡單的概述一下git
,git
有三個分區,分別是:
-
工作區(Working Directory):開發者直接編輯的地方,只要文件發生了更改,在這就會顯示出來,包含追蹤與未追蹤文件。通過
git add
將工作區文件添加到暫存區。 -
暫存區(Stage | Index):數據暫時存放的區域,通過
git commit
將暫存區文件添加到本地版本庫。 -
本地版本庫(Local Commit History):存放所有已經提交的數據,通過
git push
推送到遠程倉庫。
基礎命令
git status
查看工作區狀態,如果跟蹤的文件有做任何修改,都可以通過該命令來發現。 如:這裡通過git status
就發現在develop
分支上,README.md
文件發生了更改。
jere@JereMBP GitTest (develop) $ git status
On branch develop
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: README.md
no changes added to commit (use "git add" and/or "git commit -a")
git diff
查看具體修改內容,比如在上一步中,我們通過git status
發現README.md
文件發現了更改,這時我們可以通過git diff <file>
來查看具體的修改內容:
jere@JereMBP GitTest (develop) $ git diff README.md
diff --git a/README.md b/README.md
index 7eb4917..3d6d2a4 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,5 @@
# GitTest
For git command practice
+
+do something on develop branch
+
jere@JereMBP GitTest (develop) $
另外,你也可以直接使用git diff
,這樣就會顯示所有文件的所有修改內容。
git checkout
切換分支,比如我在feature-1
分支上切換到develop
分支上:
jere@JereMBP GitTest (feature-1) $ git checkout develop
Switched to branch 'develop'
jere@JereMBP GitTest (develop) $
在當前分支節點上新建
一個分支並且切換過去
,比如我在 main
分支上創建一個develop
新分支並且切換過去:
jere@JereMBP GitTest (main) $ git checkout -b develop
Switched to a new branch 'develop'
jere@JereMBP GitTest (develop) $ git branch
* develop
main
放棄工作區所作的修改,類似git restore <file>...
,比如:我現在想放棄README.md
中的修改
jere@JereMBP GitTest (develop) $ git status
On branch develop
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: README.md
modified: dev-file.txt
no changes added to commit (use "git add" and/or "git commit -a")
jere@JereMBP GitTest (develop) $ git checkout README.md
Updated 1 path from the index
jere@JereMBP GitTest (develop) $ git status
On branch develop
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: dev-file.txt
no changes added to commit (use "git add" and/or "git commit -a")
jere@JereMBP GitTest (develop) $
另外,如果你想放棄所有工作區中的修改,可以使用git checkout .
來放棄所有修改。
git branch
查看本地
分支情況:
jere@JereMBP GitTest (main) $ git branch
* main
查看遠程倉庫
分支情況:
jere@JereMBP GitTest (develop) $ git branch --remote
origin/HEAD -> origin/main
origin/main
在當前節點上創建一個新分支
,比如我在 develop
上創建一個feature-1
新分支:
jere@JereMBP GitTest (develop) $ git branch feature-1
jere@JereMBP GitTest (develop) $ git branch
* develop
feature-1
main
另外,關於創建分支還有一些常用的操作可以瞭解一下,比如:
# 基於某個分支上開出新分支
$ git branch <new-branch> <base-branch>
# 基於某個提交開出新分支
$ git branch <new-branch> commit_hash
# 基於某個tag開出有新分支
$ git branch <new-branch> v1.1
刪除分支
- 刪除本地分支:
git branch -d <branch-name>
。 - 刪除遠程分支:
git push -d origin <branch-name>
。
git add
將工作區所作的修改添加到暫存區,如將README.md
文件添加到暫存區:
jere@JereMBP GitTest (develop) $ git status
On branch develop
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: README.md
no changes added to commit (use "git add" and/or "git commit -a")
jere@JereMBP GitTest (develop) $ git add README.md
jere@JereMBP GitTest (develop) $ git status
On branch develop
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: README.md
jere@JereMBP GitTest (develop) $
另外,你也可以通過git add .
命令,這會將工作區所有的修改內容都添加到暫存區。
git commit
將暫存區中的內容保存到本地工作區,如上一步我們已經將README.md
文件添加到了暫存區,接下來就將它保存到本地工作區:
jere@JereMBP GitTest (develop) $ git commit -m "更改README文件"
[develop b18e4f1] 更改README文件
1 file changed, 3 insertions(+)
jere@JereMBP GitTest (develop) $ git status
On branch develop
nothing to commit, working tree clean
jere@JereMBP GitTest (develop) $
另外,你也可以通過git commit -am
來進行快速操作,其實它就是git add . & git commit -m
的結合體。
git push
將本地文件推送到遠程倉庫中,如:將上一步已經保存到本地的README.md
文件推送到遠程倉庫:
jere@JereMBP GitTest (develop) $ git push origin develop
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 12 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 371 bytes | 371.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To https://github.com/JereChen11/GitTest.git
1f7fb80..b18e4f1 develop -> develop
jere@JereMBP GitTest (develop) $
git fetch
查看遠程倉庫有沒有更新,有更新就下載下來,如果沒有更新就沒有任何反應,如:這裡通過git fetch
發現遠程倉庫中main
分支有了新提交,所以將其下載了下來。
jere@JereMBP GitTest (develop) $ git fetch
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
From https://github.com/JereChen11/GitTest
30f049e..d6ff31d main -> origin/main
jere@JereMBP GitTest (develop) $ git fetch
jere@JereMBP GitTest (develop) $
git merge
合併分支,如:在上一步中,我們通過git fetch
發現遠程 mian 分支
有了新提交,所以當前本地main分支
是落後的,所以這時候我們就應該將遠程 mian 分支
合併到我們的本地main分支
,來實現兩端同步。
jere@JereMBP GitTest (develop) $ git checkout main
Switched to branch 'main'
Your branch is behind 'origin/main' by 1 commit, and can be fast-forwarded.
(use "git pull" to update your local branch)
jere@JereMBP GitTest (main) $ git merge origin/main
Updating 30f049e..d6ff31d
Fast-forward
README.md | 2 ++
1 file changed, 2 insertions(+)
jere@JereMBP GitTest (main) $
git pull
拉取遠程倉庫,如果遠程倉庫有更新,則會將更新下載下來併合併到當前分支上,相當於git fetch
與git merge
的結合體。 如:跟上一步同樣,這次我們使用git pull
來拉取遠程 mian 分支
上的新提交。
jere@JereMBP GitTest (main) $ git pull
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 1), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
From https://github.com/JereChen11/GitTest
55e808c..4a1a531 main -> origin/main
Updating 55e808c..4a1a531
Fast-forward
README.md | 2 ++
1 file changed, 2 insertions(+)
業務場景
除了上面幾個基礎命令,現在我根據我們平時的業務場景,配合案例再介紹幾個指令。
解決衝突
關於衝突,一旦涉及分支合併,且這兩個分支有對同一個地方做更改,就會出現衝突。
比如:在上一步中我們將遠程mian分支
拉取了下來,發現他是對README.md
文件做了更改,而我們一開始的時候已經在develop
分支上對README.md
文件相同位置上做了更改,這時候,如果我們嘗試將develop
合併到main
分支上時,就會出現衝突。
jere@JereMBP GitTest (main) $ git merge develop
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.
jere@JereMBP GitTest (main) $ git status
On branch main
Your branch is up to date with 'origin/main'.
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Changes to be committed:
new file: dev-file.txt
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: README.md
jere@JereMBP GitTest (main) $
正是README.md
文件發生了衝突,我們需要打開該文件來查看具體衝突內容。
# GitTest
For git command practice
<<<<<<< HEAD
chagne README file on the main branch //內容1
=======
do something on develop branch //內容2
>>>>>>> develop
衝突的內容會被<<<<<<<
與>>>>>>>
所包圍,中間用=======
隔離開,也就如我所註釋的分成了內容1
與內容2
兩塊。
內容1
:是當前所在分支節點的內容,也就是mian
。內容2
:要合併進來分支的內容,也就是develop
。
選擇你要的內容,將<<<<<<<
、>>>>>>>
、=======
這些隔離符刪除掉,並保存,然後執行git add
、git commit
完成合併。
jere@JereMBP GitTest (main) $ vim README.md
jere@JereMBP GitTest (main) $ git status
On branch main
Your branch is up to date with 'origin/main'.
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Changes to be committed:
new file: dev-file.txt
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: README.md
jere@JereMBP GitTest (main) $ git commit -am "解決README衝突"
[main 8e08c23] 解決README衝突
jere@JereMBP GitTest (main) $
組員間同步開發進度
在實際項目中,我們都是多人配合協同開發,會將一些需求進行拆分,然後大家同時開發,開發完成後,各自將自己的代碼合併到develop
分支上。 在這過程中,如果某個組員已經開發完了並且將代碼合併到了develop
分支,而你還沒開發完,但是這時你想同步這個組員的代碼,這時應該怎麼做呢?
這裡我們就可以使用
git rebase
來做到。
git rebase
操作,稱之為變基操作,也就是移動你的分支的根節點。
舉個例子:
feature-1
與feature-2
都是基於develop
同一節點開出來的分支。- 隨著開發的進行,
feature-1
先開發完成,併合併到develop
分支。 - 此時
feature-2
利用git rebase origin develop
來同步feature-1
的代碼。
jere@JereMBP GitTest (feature-2) $ git rebase origin/develop
First, rewinding head to replay your work on top of it...
Applying: 添加 feature-22.txt 文件
Applying: 修改feature-22.txt
jere@JereMBP GitTest (feature-2) $
這三個狀態的節點分支情況如下圖所示:
初始狀態 | feature-1合併到develop | feature-2同步develop代碼 |
---|---|---|
整理合併提交
有時候,我們想對自己的提交進行合併操作。
我們可以通過git rebase -i HEAD~x
來合併(這裡 i
的意思為interactive
交互,HEAD~x
代表要合併HEAD
到前x
個歷史提交,如: HEAD~2
為歷史的前兩個提交,HEAD~4
就是歷史的前四個提交)。
舉個例子: 我們在feature-3分支
上對feature-3.txt
進行了兩次提交修改,分別是598cc68 修改feature-3.txt
與8561ef3 再次修改feature-3.txt
,現在我們要將這兩個提交進行合併。
- 執行
git rebase -i HEAD~2
。 - 這是會自動進入
vim
,顯示如下內容:
pick 598cc68 修改feature-3.txt
pick 8561ef3 再次修改feature-3.txt
...省略...
這裡我們要合併這兩個提交,所以將第二個pick
更改為s
,如下:
pick 598cc68 修改feature-3.txt
s 8561ef3 再次修改feature-3.txt
...省略...
保存退出,將自動打開另外一個vim
文件,用來修改提交文本信息,如下:
# This is a combination of 2 commits.
# This is the 1st commit message:
修改feature-3.txt
# This is the commit message #2:
再次修改feature-3.txt
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
這裡我們將其修改為最終版本,修改feature-3.txt
,保存退出。
jere@JereMBP GitTest (feature-3) $ git rebase -i HEAD~2
[detached HEAD 18296c5] 最終版本,修改feature-3.txt
Date: Wed Dec 1 10:21:05 2021 +0800
1 file changed, 2 insertions(+)
Successfully rebased and updated refs/heads/feature-3.
jere@JereMBP GitTest (feature-3) $
- 此時,你本地分支已經完成了合併,你嘗試將其推送到倉庫中時,會發現被拒絕。通過提示可知,拒絕理由是
our current branch is behind 你當前分支落後遠程分支
,這時,我們需要git push origin feature-3 -f
,強制推送,完成合併。
jere@JereMBP GitTest (feature-3) $ git push origin feature-3
To https://github.com/JereChen11/GitTest.git
! [rejected] feature-3 -> feature-3 (non-fast-forward)
error: failed to push some refs to 'https://github.com/JereChen11/GitTest.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
jere@JereMBP GitTest (feature-3) $ git push origin feature-3 -f
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 12 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 356 bytes | 356.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To https://github.com/JereChen11/GitTest.git
+ 8561ef3...18296c5 feature-3 -> feature-3 (forced update)
這三個狀態的節點分支情況如下圖所示:
執行 git rebase -i HEAD~2 |
採用squash 合併提交,並修改文本信息 |
強制推送到倉庫 |
---|---|---|
還記得我們將 pick
改為 s
這一步嗎?這裡的s
指的是squash
,意思是將該提交擠壓合併到上一個提交。 他還有一些其它選項操作可以瞭解一下:
p, pick <commit> = 使用提交
r, reword <commit> = 使用提交,但是會編輯提交文本信息
e, edit <commit> = 使用提交,在修改完成後,可以通過git commit --amend再次進行修改;修改滿意後再使用git rebase --continue
s, squash <commit> = 使用提交,擠壓合併到上一個提交
f, fixup <commit> = 類似"squash",會擠壓合併到上一個提交,但是會忽略修改提交文本信息這一步。
整理提交的必要性 如果你的分支上存在這樣的情況:提交1:finish login feature
,緊接著後面就是提交2:code review for login feature
。 這樣的操作其實很正常,也很合理,你在做好功能後,去做了code review
,但其實我們完全可以將這兩個提交合併成一個提交,方便自己以及同事查看你的代碼。
但註意:
你要在你自己的分支進行操作。
撤銷提交
這邊撤銷提交分為撤銷本地提交與撤銷遠程提交。
撤銷本地提交
當你提交了代碼到本地,但此時,你想撤回這個提交,重新編輯修改一下。這時你可以通過 git reset
來實現。
這個撤銷分為是否保留修改。
- 保留修改:
git reset --soft
,你之前所作的更改都在,這也稱為最安全的撤銷。 - 捨棄修改:
git reset --hard
,你之前所作的更改都會消失,所以要謹慎使用。
舉個例子: 當前你處於feature-4
分支上,你提了一個本地提交第二次修改
,這時你想撤銷回來繼續修改。
jere@JereMBP GitTest (feature-4) $ git reset --soft HEAD~
如果,我直接不要這個第二次修改
本地提交,則:
jere@JereMBP GitTest (feature-4) $ git reset --hard HEAD~
HEAD is now at 16960c7 第一次修改
這三個狀態的節點分支情況如下圖所示:
初始狀態 | git revert --soft |
git revert --hard |
---|---|---|
撤銷遠程提交(回滾操作)
當你將你的本地提交推送到了遠程倉庫中,這時,你發現你完全做錯了,你想進行回滾操作。
這時你就需要用到git revert
操作。
舉個例子: 我在feature-4
分支上提了兩個提交且都推送到了倉庫,分別是第一次修改
與第二次修改
,現在我想進行回滾操作,撤銷第二次修改
這個提交。
jere@JereMBP GitTest (feature-4) $ git revert HEAD
[feature-4 c73e361] Revert "第二次修改"
1 file changed, 1 deletion(-)
執行命令後,會自動打開一個vim
文件來讓你修改提交文本信息,預設在開頭加上revert
修飾,保存退出,操作結束。
撤銷前後這兩個狀態的節點分支情況如下圖所示:
撤銷前 | 撤銷後 |
---|---|
如圖所示,回滾操作後,會多一個revert xxx
提交,如果你不想要這個提交,不想讓人知道你進行了回滾,你可以使用上面介紹的git rebase -i HEAD~x
進行整理合併提交。
另外,你也可以通過git revert <commit_hash>
來對指定提交進行回滾,如果遇到衝突就先解決衝突,然後執行git revert --continue
繼續。
註意
:執行回滾操作需要註意環境,如果別人拉了你的代碼,這時你再執行回滾操作,那就不好了。
線上出Bug了,緊急修複
講個故事吧。
經過一段時間的開發,你們的產品終於上線了,版本為V1.0
,產品上線後你馬上投入到了V1.1
版本的需求開發。某天,運營與產品同時過來找你,說剛剛發現線上存在一個很嚴重的bug
,需要緊急修複一下。你馬上投入修複工作,經過緊張的排查與測試,最終你修複了這個問題,準備發版。 而此時,你才註意到,你是在develop
分支上進行的修複工作,而develope
分支已經包含了v1.1
的部分功能,這時,怎麼把這個緊急修複提交給到V1.0
呢?
可以通過git cherry-pick
做到,翻譯為挑選的意思,將某個提交挑選過來。
如:我們現在要將develop
分支上的d818f10 緊急修複線上bug
這個提交合併到我們main V1.0
上。先切換到main
分支上,然後將d818f10
這個提交挑選過來合併。
jere@JereMBP GitTest (develop) $ git co main
Switched to branch 'main'
Your branch is up to date with 'origin/main'.
jere@JereMBP GitTest (main) $ git cherry-pick d818f10
[main 55e808c] 緊急修複線上bug
Date: Wed Dec 1 15:49:48 2021 +0800
1 file changed, 2 insertions(+)
這三個狀態的節點分支情況如下圖所示:
初始狀態 | 在develop 上修複 |
將這個修複提交挑選到main |
---|---|---|
暫時保存手頭工作
某天你正在認真的開發需求中,測試過來找你讓你幫忙看一個線上問題。此時,你代碼也剛寫了一半,不想提交,這時怎麼辦?
此時我們可以通過git stash
來暫存我們代碼,然後切換到線上環境分支排查問題,解決後,切換回之前分支執行git stash pop
繼續開發。
如:我現在正在feature-5
分支上開發新需求,此時我需要暫存所有更改,切換到main
分支排查問題。排查結束,回到feature-5
,將暫存取出,繼續開發。
jere@JereMBP GitTest (feature-5) $ git status
On branch feature-5
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: feature-5.txt
no changes added to commit (use "git add" and/or "git commit -a")
jere@JereMBP GitTest (feature-5) $ git stash
Saved working directory and index state WIP on feature-5: 9bd4e1f 添加 feature-5.txt
jere@JereMBP GitTest (feature-5) $ git status
On branch feature-5
nothing to commit, working tree clean
jere@JereMBP GitTest (feature-5) $ git stash pop
On branch feature-5
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: feature-5.txt
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (1ec48d00e8d1bd5c0042d88d1209dbb9051815d4)
jere@JereMBP GitTest (feature-5) $
另外,git stash
還有一些常用操作。
# 保存到stash棧中,並加上自定義message修飾
$ git stash save "message"
# 列出stash棧中所有元素
$ git stash list
# 應用stash棧中的第x個元素,pop是應用的同時且從棧中刪除,而apply則是只應用不刪除
$ git stash apply stash@{x}
# 刪除stash棧中的第x個元素
$ git stash drop stash@{x}
上線發版啦
當我們產品開發完成,發現上線時,我們需要打個標簽來標註一下,以便下次更好的找它。
這時我們就可以通過git tag 標簽名
來打標簽。
舉個例子:我們的1.0
版本上線了,所以打個v1.0
。
jere@JereMBP GitTest (feature-5) $ git tag v1.0
jere@JereMBP GitTest (feature-5) $ git tag
v1.0
v1.0.1
另外,關於tag
的一些其它操作有:
# 查看所有標簽
$ git tag
# 刪除指定tag
$ git tag -d 標簽名
修改最近提交的文本信息
很多時候,我們提交的時候,可能會輸錯提交的文本信息,然後想修改一下。
這時,你可以通過git commit --amend
來修改最近的提交的文本消息。
當然,你也可以通過剛剛介紹的撤銷本地提交做到,這邊就不再次展示了。
git config 一些配置
通過git config --list
來查看你的git配置信息
。
配置別名
每次輸入我們都需要輸入完整的checkout
、commit
,很麻煩,我們可以通過設置別名來實現。
$ git config --global alias.co checkout
$ git config --global alias.br branch
$ git config --global alias.ci commit
$ git config --global alias.st status
設置完成後,你在通過git config --list
查看配置,就會發現:
alias.co=checkout
alias.br=branch
alias.ci=commit
alias.st=status
之後你就可以通過git co <branch>
、git st
來切換分支、查看狀態了..
配置代理
因為一些特殊網路原因,我們很多時候上github
很不穩定,有時候我們推送一些代碼會403
失敗。這時我們就可以通過設置代理來解決。
比如:我們設置一個本地代理。
git config --global http.proxy http://127.0.0.1:1080
git config --global https.proxy https://127.0.0.1:1080
git config --global http.proxy 'socks5://127.0.0.1:1080'
git config --global https.proxy 'socks5://127.0.0.1:1080'
設置完成後,你再通過git config --list
查看配置,就會發現:
http.proxy=http://127.0.0.1:1080
https.proxy=https://127.0.0.1:1080
設置代理成功後,某天,你想取消該代理,這時我們可以通過unset
來取消代理設置。
git config --global --unset http.proxy
git config --global --unset https.proxy
結尾:
OK,文章到此也就結束啦。
建議對git
命令還不太熟練的同學多上手試試,遇到問題不要慌,註意看它給的提示,相信很快就能掌握啦。
其實分享文章的最大目的正是等待著有人指出我的錯誤,如果你發現哪裡有錯誤,請毫無保留的指出即可,虛心請教。 另外,如果你覺得文章不錯,對你有所幫助,請給我點個贊,就當鼓勵,謝謝 ~Peace~!
轉自:Jere_Chen