git 版本管理

Git版本控制管理@[TOC]

git

Git is a distributed version control system.

知識(shí)點(diǎn)

版本回退

1.工作區(qū)和暫存區(qū)

工作區(qū): 電腦里的目錄
版本庫(kù): .git
版本庫(kù)中含有暫存區(qū)(stage)


工作區(qū)/版本庫(kù)

git add 將文件添加到暫存區(qū)
git commit 將文件提交到本地分支

劃重點(diǎn)

git checkout -- <file> (注意 這里有一個(gè)空格) 用于丟棄工作區(qū)的修改
情況1. readme.md 還沒(méi)有被放到暫存區(qū),撤銷修改后和版本庫(kù)一模一樣
情況2. readme.md 已經(jīng)添加到暫存區(qū)后,又作了修改,現(xiàn)在,撤銷修改就回到添加到暫存區(qū)后的狀態(tài)

git reset HEAD <file> 將暫存區(qū)的修改撤銷,放回工作區(qū)
具體而言: git reset調(diào)整HEAD引用指向給定的提交,默認(rèn)情況下還會(huì)更新索引以匹配該提交
如果我們希望工作區(qū) 暫存區(qū)都沒(méi)有進(jìn)行修改
先進(jìn)行 git reset 再進(jìn)行 git checkout

2.刪除文件 git rm

在文件管理器中刪除沒(méi)用的文件 rm test.txt
此時(shí)工作區(qū)和版本庫(kù)就不一致了,git status命令會(huì)立刻告訴你哪些文件被刪除了:

$ git status
On branch master
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    deleted:    test.txt

no changes added to commit (use "git add" and/or "git commit -a")

git rm: 將在版本庫(kù)和工作目錄中同時(shí)刪除文件

注意: git rm 是一條對(duì)索引進(jìn)行操作的命令

git rm --cached 可以將誤添加的文件恢復(fù)為未添加狀態(tài)

刪除索引中的文件并把它保留在工作目錄中,git rm則會(huì)將文件從索引目錄和工作目錄中都刪除

$ git status
On branch master
You are currently rebasing branch 'dev' on 'b79e97b'.
  (all conflicts fixed: run "git rebase --continue")

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   readme.md

Untracked files:
  (use "git add <file>..." to include in what will be committed)

    opps.md

3. 移動(dòng)文件 git mv

如果你需要移動(dòng)或者重命名文件,可以執(zhí)行

$ mv stuff newstuff
$ git rm stuff
$ git add newstuff

天吶,移動(dòng)一個(gè)文件居然三部才能完成????
使用git mv 命令 ,將文件stuff 重新命名為 newstuff
git mv stuff newstuff

4.查看提交的歷史記錄 git log

git log newstuff
如果你剛好重新命名了一個(gè)文件,你會(huì)發(fā)現(xiàn)除了命名之后的記錄之外之前文件的記錄都丟了
Git其實(shí)是記的全部的歷史記錄的,但是顯示要限制于在命令中指定的文件名; --follow選項(xiàng)會(huì)讓git在日志中回溯并找到內(nèi)容相關(guān)聯(lián)的整個(gè)歷史記錄;
$ git log --follow newstuff
git log 提交范圍
git log ^ XY 等同于 git log X...Y 可以認(rèn)為是集合減法
用Y之前的所有提交減去X之前的所有提交且包括X
范圍: (X,Y]
topic...master 表示排除從topic分支可達(dá)的提交記錄

情境一
topic并入master

此時(shí)包含的提交記錄是 V W X Y Z

情境二
切分支又合并

此時(shí)包含的提交記錄是 W X Y Z

版本庫(kù)搜索(強(qiáng)大的命令)

1. 使用git bisect命令 (啟動(dòng)二分搜索)

步驟:

//  1. 啟動(dòng)二分搜索,Git進(jìn)入二分模式,并為自己設(shè)置一些狀態(tài)信息, 一旦啟動(dòng),需要告訴git哪一個(gè)是壞的 
$ git bisect start
// 2. 可以默認(rèn)使用當(dāng)前分支提交作為壞提交
$ git bisect bad
// 3. 同樣需要告訴git 哪一個(gè)是好的
$ git bisect good v1.0.4

2. 識(shí)別特定提交 git blame

$ git blame -L 35 , init/version.c

分支管理

1.創(chuàng)建& 合并分支 git checkout / git merge

創(chuàng)建分支實(shí)際上是改變指針HEAD的指向,工作區(qū)文件沒(méi)有任何變化


0.png

合并分支

$ git checkout master
Switched to branch 'master'  
$ git merge dev    //將dev合并到master
Updating d46f35e..b17d20e
Fast-forward
 readme.txt | 1 +
 1 file changed, 1 insertion(+)

2.解決沖突

出現(xiàn)在合并分支的時(shí)候
我們到底應(yīng)該保留哪一部分呢? 到底哪一部分才是最新的修改? 天啊 我分不清了
此時(shí)處于master分支 ,合并了feature1的內(nèi)容
注意現(xiàn)在
<<<<<< HEAD
=======
這部分的內(nèi)容 , 是master分支上的, 下面的這個(gè)>>>>>>> feature1 才是合并進(jìn)來(lái)的分支上的內(nèi)容

<<<<<< HEAD
我不是亂碼
=======
djadjsjd
>>>>>> feature1

圖形化查看提交記錄

git log --graph

使用 --no-ff 采取普通模式合并,合并后的歷史有分支,能看出曾經(jīng)做過(guò)合并

3 刪除分支

  1. 刪除特定未合并分支
    git branch -d <branch-name>
    git可能提示銷毀失敗,因?yàn)榉种н€沒(méi)有被合并,如果刪除,將丟失更改
  2. 強(qiáng)行刪除分支
    git branch -d <branch-name>
    告訴我們一件事情: 開(kāi)發(fā)一個(gè)新功能,就新建一個(gè)分支
  3. 恢復(fù)刪除的分支
    意外刪除分支或其它引用后,使用 git reflog 命令來(lái)恢復(fù)
git reflog -g  // 找到所有commitID
根據(jù)操作的提示信息,回到某一次提交 將修改應(yīng)用在一個(gè)新分支上
git branch [newbranch] [commitID]

4. 處理本地和遠(yuǎn)程分支的關(guān)系

例子: 在dev分支上進(jìn)行開(kāi)發(fā),必須創(chuàng)建遠(yuǎn)程 origin的dev分支到本地
創(chuàng)建遠(yuǎn)程dev分支到本地

$ git checkout -b dev origin/dev

5. rebase 命令

變基操作一次只遷移一個(gè)提交,從各自原始提交為止遷移到新的提交基礎(chǔ);

圖解
git rebase之前

git rebase之后
變基與合并

變基的一系列提交會(huì)導(dǎo)致Git生成一系列全新的提交,擁有新的SHA1提交ID,基于新的初始狀態(tài),代表不同的差異;
??注意:如果有額外的分支基于你想變基的分支,可能會(huì)產(chǎn)生問(wèn)題;
例子:


對(duì)多分支進(jìn)行g(shù)it rebase之前
# 將dev分支移動(dòng)到master分支的頭
$ git rebase master dev

實(shí)際得到的結(jié)果
如果你想要的是 將dev_2變基到dev最新的提交Z,意想得到的結(jié)果是這樣的


git rebase master dev 之后

在這里插入圖片描述

這種情況下,如果你更希望的是移動(dòng)整個(gè)分支(包括該分支的子分支),需要反過(guò)來(lái)把dev2分支變基到dev分支的新提交Y’上面

$ git rebase dev^ dev2  
重要的幾個(gè)概念
  1. 變基將提交重寫(xiě)成新提交
  2. 不可達(dá)的舊提交會(huì)消失;
  3. 任何舊的、變基前的提交的用戶可能被困?。?/li>
  4. 如果有分支用變基前的提交,可能需要反過(guò)來(lái)對(duì)它變基;
  5. 如果有用戶有不同版本庫(kù)中變基前的提交,即使它已經(jīng)移動(dòng)到你的版本庫(kù)中,它仍然擁有該提交的副本,該用戶現(xiàn)在也必須修復(fù)他的提交歷史記錄。

用書(shū)中這個(gè)復(fù)雜的例子解釋一下這幾句話:


復(fù)雜的分支
$ git rebase master dev
First, rewinding head to replay your work on top of it...
Applying: X
Applying: Y
Applying: Z
Applying: P
Applying: N

 $ git show-branch
 * [dev] N
  ![master] D
  --
  * [dev] N
  * [dev^] P
  * [dev~2] Z
  * [dev~3] Y
  * [dev~4] X
  * [dev~5] D
# 現(xiàn)在所有的提交連成了一串

git 應(yīng)用了所有的(非合并)提交變更;發(fā)生的過(guò)程:
在master ...dev 范圍內(nèi)找提交。為了列出所有提交,Git對(duì)圖中的那部分執(zhí)行拓?fù)渑判颍a(chǎn)生該范圍內(nèi)所有提交的一個(gè)線性序列;
【其實(shí)我也沒(méi)有明白 - - 】

diff命令

一個(gè)根級(jí)別的diiff可以有效的將兩個(gè)版本庫(kù)進(jìn)行同步
顯示工作目錄和給定提交之間的差異

1. git diff commit

比較SVN 和 Git 如何產(chǎn)生 diff

git: 每個(gè)修訂版本都有自己的一棵樹(shù),但git不需要它們來(lái)生成diff , Git可以直接操作兩個(gè)版本的完整狀態(tài)快照
svn:跟蹤修訂一系列版本,只儲(chǔ)存文件內(nèi)的差異 查看r1008 與r1908間的diff,svn會(huì)查看兩個(gè)版本之間所有單獨(dú)的diff,然后合成一個(gè)大的diff,把結(jié)果發(fā)送給用戶

合并

1. 合并策略

解決(resolve): 解決策略只操作兩個(gè)分支。定位共同的祖先作為合并基礎(chǔ),然后執(zhí)行一個(gè)直接的三方合并;
遞歸(Recursive): 遞歸策略和解決策略相似,每次處理兩個(gè)分支; 但它可以處理在兩個(gè)分支之間有多個(gè)合并基礎(chǔ)的情況; Git生成一個(gè)臨時(shí)合并來(lái)包含所有相同的合并基礎(chǔ),以此為基礎(chǔ)通過(guò)一個(gè)普通的三方合并算法導(dǎo)出兩個(gè)給定分支的最終合并;
章魚(yú)(Octopus): 專為合并兩個(gè)以上分支而設(shè)計(jì); 在內(nèi)部它需要多次調(diào)用遞歸合并策略,要合并的每個(gè)分支調(diào)一次;

2. 應(yīng)用合并策略

Git會(huì)盡可能嘗試使用簡(jiǎn)單廉價(jià)的算法,如果可能,首先嘗試使用“已經(jīng)是最新的”和“快進(jìn)”策略來(lái)消除不重要的、簡(jiǎn)單的情況;

終止或重新啟動(dòng)合并

a. 如果你開(kāi)始合并,但是因?yàn)槟撤N原因你不想完成它,git提供 如下命令來(lái)終止合并
$ git reset --hard HEAD
這條命令可以立即把工作目錄和索引都還原到 git merge 之前的狀態(tài)
b. 如果要中止或在它已經(jīng)結(jié)束(即 引入一個(gè)新的合并提交)后放棄, 使用:
$ git reset --hard ORIG_HEAD
在開(kāi)始合并操作之前,Git將原始分支的HEAD 保存在 ORIG_HEAD ,就是為了這種目的

從Git 1.6.1 開(kāi)始,有另一種選擇。
如果你把沖突解決方案搞砸了,并且想再返回到嘗試解決前的原始沖突狀態(tài),可以使用 git checkout -m

更改提交

1. 關(guān)于修改歷史記錄的注意事項(xiàng)

如果一個(gè)分支已經(jīng)公開(kāi)了,并且可能已經(jīng)存在于其他版本庫(kù)中,就不應(yīng)該重寫(xiě)、修改或者更改該分支的任何部分;

2.git reset命令

git reset命令是“破壞性”的,可以覆蓋并銷毀工作目錄中的修改;

3. 使用 git cherry-pick

  1. 在當(dāng)前分支上應(yīng)用給定提交引入的變更
    在正常開(kāi)發(fā)過(guò)程中,開(kāi)發(fā)線的提交F修復(fù)了一個(gè)bug;此時(shí)F提交也存在于版本2.3發(fā)布版中,可以對(duì)rel 2.3分支使用 git cherry-pick 來(lái)應(yīng)用bug修復(fù)


    cherry-pick.png
$ git checkout rel_2.3
git cherry-pick dev~2 #commit F , above
  1. 重建一系列提交
    通過(guò)從一個(gè)分支選一批提交,然后把它們引入一個(gè)新分支
    以Y , W , X , Z 的順序應(yīng)用它們,可以使用如下命令:


    執(zhí)行cherry-pick 進(jìn)行亂序之前
$ git checkout master
$ git cherry-pick my_dev^   #Y
$ git cherry-pick my_dev~3   #W
$ git cherry-pick my_dev~2   #X
$ git cherry-pick my_dev #Z
執(zhí)行 git cherry-pick之后

4. 使用 git revert

git cherry-pick提交命令是大致相同的,但又一個(gè)重要區(qū)別: 應(yīng)用于給定提交的逆過(guò)程
常見(jiàn)用途是:“撤銷”可能深埋在歷史記錄中的某個(gè)提交的影響
$ git revert master~3 master向前數(shù)三個(gè)版本撤銷

執(zhí)行g(shù)it revert之后

儲(chǔ)藏和引用日志

git stash 命令

用于緊急修復(fù)bug 但不提交手頭的工作
git stash (save) 暫存剛才的改動(dòng)記錄
git stash list用于查看之前的工作現(xiàn)場(chǎng),按照時(shí)間由近及遠(yuǎn)的順序舉出儲(chǔ)藏棧
git stash apply 重新創(chuàng)建保存在儲(chǔ)藏棧中的上下文,但記錄歷史不會(huì)從棧中刪除;
git stash drop 丟棄儲(chǔ)藏的狀態(tài)
一旦應(yīng)用儲(chǔ)藏,合并處理了沖突,并希望工作繼續(xù),應(yīng)該使用 git stash grop 來(lái)將狀態(tài)從儲(chǔ)藏棧中刪除,否則git 將會(huì)維護(hù)一個(gè)內(nèi)容不斷增加的棧;
git stash pop = git stash apply + git stash drop
git stash apply stash@{n} n= 0,1,2.....1000... 多次stash之后恢復(fù)指定的stash

2.git stash的其他經(jīng)典應(yīng)用場(chǎng)景: 在臟的目錄中進(jìn)行拉取

場(chǎng)景復(fù)現(xiàn):

  1. 本地版本庫(kù)進(jìn)行開(kāi)發(fā)過(guò)程中,已經(jīng)做過(guò)多次提交,但仍然有些尚未提交的修改,這時(shí)候上游分支有了你想要的更新,但某些修改與上游分支沖突,導(dǎo)致 pul失敗,因?yàn)?code>git pull 不想覆蓋本地的新版本文件
    使用 git stash --include--untracked 參數(shù)以便它也能儲(chǔ)藏新的未被追蹤的文件和余下的修改。確保在拉取工作目錄時(shí)是完全干凈的;
    2.需要暫時(shí)移除已經(jīng)修改的工作來(lái)保證一個(gè)干凈的pull --rebase時(shí), 可以使用 git stash

引用日志

確保操作會(huì)如預(yù)期般發(fā)生在計(jì)劃的分支上
git reflog 命令
查看操作歷史記錄(每一步分支切換,commit,merge都可以查看)

搞砸了一次 merge, 想再來(lái)一遍怎么辦? git reset HEAD {@1} ,根據(jù)需要可以添加 --hard 選項(xiàng)

版本庫(kù)

裸版本庫(kù) & 開(kāi)發(fā)版本庫(kù)

默認(rèn)創(chuàng)建的是 開(kāi)發(fā)版本庫(kù),用于日常常規(guī)開(kāi)發(fā);
裸版本庫(kù)角色:作為協(xié)作開(kāi)發(fā)的權(quán)威焦點(diǎn),其他開(kāi)發(fā)人員只能從裸版本庫(kù)clone,fetch,并push更新;
裸版本庫(kù)不能創(chuàng)建遠(yuǎn)程版本庫(kù);
[12章未總結(jié)完全,下次再找實(shí)踐看]

補(bǔ)丁

應(yīng)用場(chǎng)景: 一個(gè)單獨(dú)bug的修復(fù)或一個(gè)特定功能實(shí)現(xiàn)
為最近n次提交生成補(bǔ)丁 最簡(jiǎn)方式是使用 -n選項(xiàng)

$ git for

QA

1.為什么不使用 commit -a 或者 commit -m ./ ?
2. 我應(yīng)該對(duì)一系列操作進(jìn)行合并還是變基?

做你想做的。
通過(guò)合并,兩個(gè)原本獨(dú)立發(fā)展的分支合并到一起,會(huì)產(chǎn)生額外的合并提交歷史記錄更新同時(shí)存在與每一個(gè)分支的變更;
在合并期間必須解決沖突,每個(gè)分支的提交都是基于原來(lái)的提交,當(dāng)推送到上游時(shí),任何合并的歷史記錄將繼續(xù)存在;
a. 認(rèn)為是多余的合并,并不愿意看到它們弄亂歷史記錄;
b. 這些合并是開(kāi)發(fā)歷史記錄更準(zhǔn)確的寫(xiě)照,希望看到它們被保留;
變基操作: 改變了一系列提交是在何時(shí)何地開(kāi)發(fā)的概念;開(kāi)發(fā)歷史記錄的某些方面會(huì)丟失;

3. 裸版本庫(kù)作為發(fā)布版本,但它又不是遠(yuǎn)程倉(cāng)庫(kù),這不矛盾嗎?
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Git 基礎(chǔ) 基本原理 客戶端并不是只提取最新版本的文件快照,而是把代碼倉(cāng)庫(kù)完整的鏡像下來(lái)。這樣一來(lái),任何一處協(xié)同...
    __silhouette閱讀 16,201評(píng)論 5 147
  • Git 命令行學(xué)習(xí)筆記 Git 基礎(chǔ) 基本原理 客戶端并不是只提取最新版本的文件快照,而是把代碼倉(cāng)庫(kù)完整的鏡像下來(lái)...
    sunnyghx閱讀 4,155評(píng)論 0 11
  • [TOC] 背景 以前協(xié)同修改文件的方法: 通過(guò)復(fù)制文件來(lái)備份不同版本,按照日期等命名規(guī)則來(lái)區(qū)分。 文件共享,大家...
    dszkng閱讀 1,109評(píng)論 0 0
  • 如果能早點(diǎn)和你相遇 在清晨 在晌午 在夜暮 我漫不經(jīng)心的迎著北風(fēng) 踩著你斜...
    By于你與你閱讀 274評(píng)論 0 0
  • 天青色等煙雨,而我在等你。這個(gè)季節(jié)的江南古鎮(zhèn)恰到好處的投影了這個(gè)場(chǎng)景。 春雨中的江南少了幾分俗世的喧囂與煩惱,添了...
    他就叫冬冬閱讀 1,520評(píng)論 0 1

友情鏈接更多精彩內(nèi)容