Git最強總結!


本文已經收錄到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 的工作流程圖如下:

git-work-flow

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

存儲原理

Git 在保存項目狀態時,它主要對全部文件制作一個快照並保存這個快照的索引,如果文件沒有被修改,Git 不會重新存儲這個文件,而是只保留一個鏈接指向之前存儲的文件。

Git 快照

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

三種狀態

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

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

Git工作流程

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

配置

設置用戶名和郵箱地址:

git config --global user.name "dabin"
git config --global user.email xxx@xxx.com

如果使用了 --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

git生命周期

圖片來源: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 git@github.com: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.support@github.com</div>
=======
<div id="footer">
please contact us at support@github.com
</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獲得的。

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM