本文已經收錄到Github倉庫,歡迎大家圍觀、star。此倉庫用於分享Java核心知識,包括Java基礎、MySQL、SpringBoot、Mybatis、Redis、RabbitMQ等等,面試必備。

github地址:https://github.com/Tyson0314/Java-learning

如果github訪問不了,可以訪問gitee倉庫。

gitee地址:https://gitee.com/tysondai/Java-learning

Git 簡介

Git 是一個開源的分散式版本控制系統,可以有效、快速的進行專案版本管理。Git 是 Linus Torvalds 為了幫助管理 Linux 核心開發而開發的一個開放原始碼的版本控制軟體。

Git工作流程

Git工作流程如下:

  • 從遠端倉庫中克隆資源作為本地倉庫;
  • 在本地倉庫中進行程式碼修改;
  • 在提交本地倉庫前先將程式碼提交到暫存區;
  • 提交修改,提交到本地倉庫。本地倉庫中儲存修改的所有歷史版本;
  • 在需要和團隊成員共享程式碼時,可以將修改的程式碼push到遠端倉庫。

Git 的工作流程圖如下:

圖片來源:https://blog.csdn.net/ThinkWon/article/details/94346816

儲存原理

Git 在儲存專案狀態時,它主要對全部檔案製作一個快照並儲存這個快照的索引,如果檔案沒有被修改,Git 不會重新儲存這個檔案,而是隻保留一個連結指向之前儲存的檔案。

Git 快照

快照就是將舊檔案所佔的空間保留下來,並且儲存一個引用,而新檔案中會繼續使用與舊檔案內容相同部分的磁碟空間,不同部分則寫入新的磁碟空間。

三種狀態

Git 的三種狀態:已修改(modified)、已暫存(staged)和已提交(committed)。已修改表示修改了檔案,但還沒儲存到資料庫。已暫存表示對一個已修改檔案的當前版本做了標記,使之包含在下次提交的快照中。已提交表示資料已經安全的儲存到本地資料庫。

基本的 Git 工作流程:在工作目錄修改檔案;暫存檔案,將檔案快照放到暫存區域;提交更新到本地庫。暫存區儲存了下次將要提交的檔案列表資訊,一般在 Git 倉庫目錄中。

圖片來源:https://img2018.cnblogs.com/blog/1252910/201907/1252910-20190726163829113-2056815874.png

配置

設定使用者名稱和郵箱地址:

git config --global user.name "dabin"
git config --global user.email [email protected]

如果使用了 --global 選項,那麼該命令只需要執行一次,因為之後無論你在該系統上做任何事情,Git 都會使用那些資訊。 當你想針對特定專案使用不同的使用者名稱稱與郵件地址時,可以在那個專案目錄下執行沒有 --global 選項的命令來配置。

檢視配置資訊:git config --list

檢視某一項配置:git config user.name

獲取幫助

獲取 config 命令的手冊:git help config

Git 基礎

獲取 Git 倉庫

在現有目錄中初始化倉庫:進入專案目錄並輸入git init

克隆現有的倉庫:git clone https://github.com/...

檔案狀態

檢視檔案狀態:git status

圖片來源:https://img2018.cnblogs.com/blog/1252910/201907/1252910-20190726163854195-886320537.png

狀態簡覽:

新新增的未跟蹤檔案前面有 ?? 標記,新新增到暫存區中的檔案前面有 A 標記,修改過的檔案前面有 M 標記,如下圖,MM Rakefile出現兩個M,其中出現在靠左邊的 M 表示該檔案被修改了並放入了暫存區,出現在右邊的 M 表示該檔案被修改了但是還沒放入暫存區。

$ git status -s
M README # 右邊的 M 表示該檔案被修改了但是還沒放入暫存區
MM Rakefile # 左邊的 M 表示該檔案被修改了並放入了暫存區;右邊的 M 表示該檔案被修改了但是還沒放入暫存區
A lib/git.rb # A表示新新增到暫存區中的檔案
?? LICENSE.txt # ??表示新新增的未跟蹤檔案

配置別名

有些人可能經常敲錯命令,通過配置別名可以簡化命令:

通過命令 git config --global alias.st status git status 簡化為 git st

$ git config --global alias.st status

$ git st
On branch master
Your branch is up to date with 'origin/master'. nothing to commit, working tree clean

工作區

檢視工作區修改:git diff

$ git diff
diff --git a/md/leetcode刷題筆記.md b/md/leetcode刷題筆記.md
deleted file mode 100644
index 63a7c90..0000000
--- a/md/leetcode刷題筆記.md
+++ /dev/null

撤銷工作區修改:git checkout -- file_name,會撤銷工作區的修改,不可恢復,不會撤銷暫存區修改。

撤銷修改還可以使用 restore 命令(git2.23版本引入)。

git restore --worktree demo.txt //撤銷檔案工作區的修改
git restore --staged demo.txt //撤銷暫存區的修改,將檔案狀態恢復到未add之前
git restore -s HEAD~1 demo.txt //將當前工作區切換到上個 commit 版本,-s相當於--source
git restore -s hadn12 demo.txt //將當前工作區切換到指定 commit id 的版本

暫存區

通過git add filename 將工作區的檔案放到暫存區。

git add README.md

檢視暫存區修改:git diff --staged。可以看到暫存區中有 README.md 檔案,說明README.md檔案被放到了暫存區。

$ git diff --staged
diff --git a/README.md b/README.md
index ecd6c7a..653f001 100644
--- a/README.md
+++ b/README.md

撤銷暫存區修改/unstage:git reset HEAD file_name,將檔案修改移出暫存區,放到工作區。

git reset 加上 --hard 選項會導致工作目錄中所有修改丟失。

提交

任何未提交的修改丟失後很可能不可恢復。提交命令:git commit -m "add readme.md"

git commit -a -m "xxx" 相當於git addgit commit -m "xxx",將 tracked 的檔案直接提交。untracked 的檔案無法使用此命令直接提交,需先執行 git add 命令,再執行 git commit。

單獨執行git commit,不帶上-m引數,會進入 vim 編輯器介面:

此時應該這麼操作:

  1. 按下字母鍵iao,進入到可編輯狀態
  2. 輸入commit資訊之後,按下Esc鍵就可退出編輯狀態,回到一般模式
  3. 輸入:wq (儲存退出)或 :wq!(強行退出,不儲存)

修改commit資訊

如果提交後發現漏掉某些檔案或者提交資訊寫錯,使用git commit --amend重新提交:

git commit -m 'initial commit'
git add forgotten_file
git commit --amend

檢視提交歷史

git log列出所有提交的更新。

git log -p -2,-p 用來顯示每次提交的內容差異,-2表示顯示最近兩次提交。

git log --stat每次提交下面都會列出所有被修改的檔案、有多少檔案被修改和哪些行被修改等。

git log --pretty=oneline將每個提交放在一行顯示。

git log --pretty=format:"%h %s" --graph format 表示格式化輸出,%h 提交物件的簡短雜湊串,%s 是提交說明,--graph 可以更形象的展示分支、合併歷史。

$ git log --pretty=format:"%h %s" --graph
* 75f8b36 update
* cd72e4f 刪除查詢效能優化
* 6bddc95 MySQL總結整理
* f8ace0e java常見關鍵字總結
* 0c4efeb 刪除android
* 4844de5 mysql執行計劃
* 635c140 redis分散式鎖
* 7b65bc3 update
* e563eec update
* 67e1cf7 update readme
* 218f353 調整目錄結構
* 9428314 整理Java基礎內容

git log --since=2.weeks 按照時間作限制。

版本回退

版本回退使用git reset命令。

git reset --hard commit_id
git reset --hard HEAD^ # 回退所有內容到上一個版本
git reset --hard HEAD^^ # 回退所有內容到上上一個版本
git reset --hard HEAD~100 # 回退到之前第100個版本
git reset HEAD readme.txt # 把暫存區的修改撤銷掉(unstage), 重新放到工作區

stash

將未提交的修改儲存起來。用於後續恢復當前工作目錄。

git stash
git stash pop stash@{id} //恢復後刪除
git stash apply stash@{id} //恢復後不刪除,需手動刪除
git stage drop
git stash list //檢視stash 列表
git stash show -p stash@{0} //檢視stash具體內容,-p檢視diff,stash@{0}可以省略

rm和mv

git rm readme.md:檔案未被修改過,從暫存區移除檔案,然後提交,相當於 rm readme.mdgit add .。如果只是簡單地從工作目錄中手工刪除檔案,執行 git status 時就會在 “Changes not staged for commit”。

git rm --cached README.md:讓檔案保留在工作區,但是不想讓 Git 繼續跟蹤。可以使用 --cached 選項來實現。檔案被修改過,還沒有放進暫存區,則必須要用強制刪除選項 -f ,以防止誤刪還沒有新增到暫存區的資料,這樣的資料不能被 Git 恢復。

git rm 支援正則表示式:git rm log/\*.log

對檔案改名:git mv README.md README

相當於執行一下三條命令:

mv README.md README
git rm README.md
git add README

忽略檔案

.gitignore 只能忽略未跟蹤狀態的檔案。

如果遠端倉庫已經有了logs資料夾,git rm --cached logs/xx.log 可以刪除檔案的跟蹤狀態,此時本地工作區修改還在。然後更新 .gitignore 檔案,最後git add . & git commit -m "xx" & git push 就可以刪除遠端倉庫對應的檔案。

skip-worktree和assume-unchanged

skip-worktree:

  • git update-index --skip-worktree [file] 可以實現修改本地檔案不會被提交,但又可以拉取最新更改的需求。適用於一些不經常變動,但是必須本地化設定的檔案。

  • 取消skip-worktree:git update-index --no-skip-worktree [file]

  • 檢視 skip-worktree 列表:git ls-files -v | grep '^S\ '

assume-unchanged:

  • git update-index --assume-unchanged [file] 該命令只是假設檔案沒有變動,使用reset時,會將檔案修改回去。當遠端倉庫相應的檔案被修改時,pull更新之後,--assume-unchanged 會被清除。

  • 取消忽略:git update-index --no-assume-unchanged file/path

  • 檢視忽略了哪些檔案:git ls-files -v | grep '^h\ '

遠端倉庫

遠端倉庫是指託管在網路中的專案版本庫。

檢視遠端倉庫

檢視遠端倉庫地址:

$ git remote -v
origin https://github.com/schacon/ticgit (fetch)
origin https://github.com/schacon/ticgit (push)

新增遠端倉庫

執行 git remote add <shortname> <url> 新增遠端 Git 倉庫,同時指定一個簡寫名稱。

git remote add pb https://github.com/paulboone/ticgit

如上命令,可以在命令列中使用字串 pb 來代替整個 URL。如git fetch pb

如果使用 clone 命令克隆了一個倉庫,命令會自動將其新增為遠端倉庫並預設以 origin 為預設簡寫名稱。

取消關聯Git倉庫 git remote remove origin

如果想要給origin設定兩個遠端倉庫地址(git add會報錯),可以使用git remote set-url --add origin url來設定。

$ git remote add origin  xxx.git
fatal: remote origin already exists. $ git remote set-url --add origin xxx.git
#success

修改遠端倉庫

修改遠端倉庫地址:

git remote set-url origin [email protected]:Tyson0314/Blog.git

pull 和 fetch

從遠端倉庫獲取資料:git fetch [remote-name]

git fetch 命令將資料拉取到本地倉庫,但它並不會自動合併到本地分支,必須手動將其合併本地分支。

git pull 通常會從遠端倉庫拉取資料並自動嘗試合併到當前所在的分支。

git pull = git fetch + git merge FETCH_HEAD
git pull --rebase = git fetch + git rebase FETCH_HEAD

本地倉庫上傳git伺服器

git init # 將目錄變成本地倉庫
git add .
git commit -m 'xxx' # 提交到本地倉庫
git remote add origin https://github.com/Tyson0314/profile # 關聯遠端倉庫
git branch --set-upstream-to=origin/master master # 本地分支關聯遠端分支
git pull origin master --allow-unrelated-histories # 允許合併不相關的歷史
git push -u origin master # 如果當前分支與多個主機存在追蹤關係,則-u會指定一個預設主機,這樣後面就可以不加任何引數使用git push。

推送到遠端倉庫

推送使用命令:git push [remote-name] [branch-name]

git push origin master

檢視遠端倉庫

git remote show origin

遠端倉庫移除和命名

移除遠端倉庫:

git remote rm paul

重新命名遠端倉庫:

git remote rename old-name new-name

標籤

給歷史的某個提交打標籤,如標記釋出節點(v1.0等)。

tag標籤可以幫助我們回退到某個版本的程式碼,我們通過tag的名稱即可回退,而不需要根據某個提冗長的commit ID來回退:

  • 檢視本地tag:git tag
  • 新建tag:git tag -a v2.0 -m 'msg'
  • 推送指定tag至遠端:git push origin v2.0
  • 推送本地所有tag至遠端:git push origin --tags
  • 刪除本地tag:git tag -d v2.0
  • 刪除遠端tag:git push origin --delete tag 2.0
  • 本地檢視不同tag的程式碼:get checkout v1.0
  • 檢視標籤詳情(包含commitId):git show v1.0
  • 回退到某個版本:git reset --hard commitId
  • 獲取遠端分支:git fetch origin tag V2.0

建立標籤

Git 使用兩種主要型別的標籤:輕量標籤(lightweight)與附註標籤(annotated)。一個輕量標籤很像一個不會改變的分支 - 它只是一個特定提交的引用。然而,附註標籤是儲存在 Git 資料庫中的一個完整物件。 它們是可以被校驗的;其中包含打標籤者的名字、電子郵件地址、日期時間;還有一個標籤資訊;並且可以使用 GNU Privacy Guard (GPG)簽名與驗證。 通常建議建立附註標籤。

建立的標籤都只儲存在本地,不會自動推送到遠端。

附註標籤

git tag -a v1.4 -m 'my version 1.4' -m 選項指定了一條將會儲存在標籤中的資訊。

使用 git show v1.4 命令可以看到標籤資訊與對應的提交資訊。

輕量標籤

git tag v1.4-tyson 此時執行 git show v1.4-tyson不會看到額外的標籤資訊,只顯示提交資訊。

推送標籤

推送某個標籤到遠端,使用命令git push origin <tagname>

一次性推送全部尚未推送到遠端的本地標籤 git push origin --tags

刪除遠端標籤(先刪除本地標籤) git push origin :refs/tags/<tagname>

後期打標籤

比如給下面的這個提交( modified readme.md )打標籤: git tag -a v1.2 c1285b

$ git log --pretty=oneline
22fb43d9f59b983feb64ee69bd0658f37ea45db6 (HEAD -> master, tag: v1.4-tyson, tag: v1.4) add file note.md
aab2fda0b604dc295fc2bd5bfef14f3b8e3c5a98 add one line
c1285bcff4ef6b2aefdaf94eb9282fd4257621c6 modified readme.md
ba8e8a5fb932014b4aaf9ccd3163affb7699d475 renamed
d2ffb8c33978295aed189f5854857bc4e7b55358 add readme.md

共享標籤

git push 命令並不會傳送標籤到遠端倉庫伺服器上。在建立完標籤後你必須顯式地推送標籤到共享伺服器上:git push origin v1.5

把所有不在遠端倉庫伺服器上的標籤全部傳送到那裡:git push origin --tags

檢出標籤

如果你想要工作目錄與倉庫中特定的標籤版本完全一樣,可以使用 git checkout -b [branchname] [tagname] 在特定的標籤上建立一個新分支:

$ git checkout -b version2 v2.0.0
Switched to a new branch 'version2'

git 別名

取消暫存別名:git config --global alias.unstage 'reset HEAD --'

最後一次提交:git config --global alias.last 'log -1 HEAD'

git 分支

Git 鼓勵在工作流程中頻繁地使用分支與合併。

Git 儲存的不是檔案的變化或者差異,而是一系列不同時刻的檔案快照。git 提交物件會包含一個指向暫存內容快照的指標。

分支建立

$ git branch testing

檢視遠端分支:git branch -r

分支切換

使用 git checkout branch-name 切換分支:

git checkout testing

檢視各個分支當前所指的物件:git log --oneline --decorate

$ git log --oneline --decorate
22fb43d (HEAD -> master, tag: v1.4-tyson, tag: v1.4, tyson) add file note.md
aab2fda add one line
c1285bc (tag: v1.2) modified readme.md
ba8e8a5 renamed
d2ffb8c add readme.md

master 和 tyson 分支都指向校驗和為 22fb43d 的提交物件。

$ git checkout -b iss53 相當於 git branch iss53 加上 git checkout iss53

分支合併

合併 iss53 分支到 master 分支:

git checkout master
git merge iss53

squash merge:合併多個 commit 為一個,合併完需要重新提交,會修改原 commit 的提交資訊,包括 author。

合併衝突

當合併產生衝突時不會自動地建立一個新的合併提交。 Git 會暫停下來,等待你去解決合併產生的衝突。 你可以在合併衝突後的任意時刻使用 git status 命令來檢視那些因包含合併衝突而處於 unmerged 狀態的檔案。

<<<<<<< HEAD:index.html
<div id="footer">contact : [email protected]</div>
=======
<div id="footer">
please contact us at [email protected]
</div>
>>>>>>> iss53:index.html

在你解決了所有檔案裡的衝突之後,對每個檔案使用 git add 命令來將其標記為衝突已解決。然後輸入 git commit -m "merge branch iss53"完成合並提交。

rebase

現在我們有這樣的兩個分支,test和master,提交如下:

       D---E test
/
A---B---C---F--- master

在master執行git merge test,會生成額外的提交節點G:

       D--------E
/ \
A---B---C---F----G--- test, master

在master執行git rebase test,本地提交以補丁形式打在分支的最後面:

A---B---D---E---C‘---F‘---   test, master

merge操作會生成一個新的節點,之前的提交分開顯示。

而rebase操作不會生成新的節點,是將兩個分支融合成一個線性的提交。

合併commit:git rebase -i

pick c38e7ae rebase content
s 595ede1 rebase # Rebase 8824682..595ede1 onto 8824682 (2 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit

s 595ede1 rebase會將595ede1合到前一個commit,按下:wq之後會彈出對話方塊,合併commit message。

刪除分支

刪除本地分支:git branch -d iss53

刪除遠端分支:git push origin --delete master

分支管理

得到當前所有分支的一個列表:

$ git branch
* master
tyson

*代表當前 HEAD 指標所指向的分支。

檢視每一個分支的最後一次提交:

$ git branch -v
* master 22fb43d add file note.md
tyson 22fb43d add file note.md

檢視哪些分支已經合併到當前分支:

$git	branch	--merged
iss53
*master

檢視所有包含未合併工作的分支:

$git branch --no-merged
testing

如果分支包含未合併的工作,使用 git branch -d testing 刪除時會出錯,可以使用 git branch -D testing強制刪除。

遠端分支

推送

git push origin master 將本地的 master 分支推送到遠端倉庫 origin/master 分支。git push origin tyson:tyson-branch 將本地的 tyson 分支推送到遠端倉庫的 tyson-branch 分支。

假如當前本地分支是 tyson,抓取遠端倉庫資料後,需要進行合併:

git fetch origin
git merge origin/tyson

將本地的所有分支都推送到遠端主機:git push -all origin

強制推送:git push --force origin

跟蹤分支

$ git checkout --track origin/tyson
Branch tyson set up to track remote branch tyson from origin.
Switched to a new branch 'tyson'

本地分支與遠端分支設定為不同名字:

$ git checkout -b tyson-branch origin/tyson
Branch tyson-branch set up to track remote branch tyson from origin.
Switched to a new branch 'tyson-branch'

設定已有的本地分支跟蹤一個剛剛拉取下來的遠端分支,使用 -u 或 --set-upstream-to 選項:

git branch -u origin master

檢視設定的所有跟蹤分支:

$ git branch -vv
iss53 7e424c3 [origin/iss53: ahead 2] forgot the brackets
master 1ae2a45 [origin/master] deploying index fix
* serverfix f8674d9 [teamone/server-fix-good: ahead 3, behind 1] this should do it
testing 5ea463a trying something new

這些資料是本地快取的伺服器資料,如果需要最新的資料,可以先執行:git fetch --all 然後再執行:git branch -vv

fetch和pull

git fetch 會將遠端倉庫的更新拉取到本地遠端倉庫的副本,不會自動合併到本地倉庫。

git fetch 步驟:

git fetch origin master:tmp  //在本地新建一個tmp分支,並將遠端origin倉庫的master分支程式碼下載到本地tmp分支
git diff tmp //來比較原生代碼與剛剛從遠端下載下來的程式碼的區別
git merge tmp//合併tmp分支到本地的master分支
git branch -d tmp//如果不想保留temp分支 可以用這步刪除

git pull = git fetch + git merge

刪除遠端分支

git push origin --delete tyson Git 伺服器會保留資料一段時間,誤刪的遠端分支很容易恢復。

建立遠端分支

基於本地分支建立遠端分支:git push origin backup_foreign:backup_foreign

本地新分支和遠端新分支關聯:git push --set-upstream origin backup_foreign

cherry-pick

參考自:cherry-pick

可以用於將在其他分支上的 commit 修改,移植到當前的分支。

git cherry-pick <commit-id>

當執行完 cherry-pick 之後,將會自動生成一個新的 commit 進行提交,會有一個新的 commit ID,commit 資訊與 cherry-pick 的 commit 資訊一致。遇到衝突則解決衝突,然後 git add 產生衝突的檔案,然後使用 git cherry-pick --continue 繼續。這個過程中可以使用 git cherry-pick --abort,恢復分支到 cherry-pick 之前的狀態。

git cherry-pick -x <commit_id> 增加 -x 引數,表示保留原提交的作者資訊進行提交。

在 Git 1.7.2 版本開始,新增了支援批量 cherry-pick ,就是可以一次將一個連續的時間序列內的 commit ,設定一個開始和結束的 commit ,進行 cherry-pick 操作。

git cherry-pick <start-commit-id>…<end-commit-id>

上述命令將從start-commit-id開始到end-commit-id之間的所有commit-id提交記錄都合併過來,需要注意的是,start-commit-id必須比end-commit-id提前提交。

cherry-pick與rebase的區別

cherry-pick 操作的是某一個或某幾個 commit,rebase 操作的是整個分支。

補丁

git apply xx.patch 需要自己重新 commit。xx.patch 必須從git diff中獲得,才能使用 git apply

git am yy.patch 會保留commit資訊,yy.patch是從git format–patch獲得的。

碼字不易,如果覺得對你有幫助,可以點個贊鼓勵一下!