㈠ Git撤銷與合並
1. git init
創建一個空的git repo,也就是創建一個.git的子目錄,這個目錄包含了幾乎所有git存儲和操作的東西。新初始化的.git目錄的典型結構如下:
description文件僅供git web程序使用,平常無需關心。
config文件包含項目特有的配置選項。
info目錄包含一個全局性排除文件,用以放置那些不希望被記錄在.gitignore文件中的忽略模式。
hooks目錄包含客戶端或服務端的鉤子腳本。
HEAD文件指向目前被檢出的分支。
index文件(尚待創建)保存暫存區信息。
objects目錄存儲所有數據內容。
refs目錄存儲指向數據的提交對象的指針。
git的默認分支名字是master,git init時默認創建它。
2. git的三種狀態,以及工作區(Working directory),暫存區(Index),HEAD
Git 有三種狀態,你的文件可能處於其中之一:已修改(modified)、已暫存(staged)和已提交(committed)
基於剛才init的git project,做一些改動。
會看到在git add之後,.git下面多了一個index文件。
這時候,所做的改動就處於已暫存狀態,體現在index文件中。
可以利用以下命令查看git緩存了的內容。
同時,.git/objects下面多了一個子文件夾,並生成了一個新文件。這個新文件就對應了剛才所做的改動。這就是git存儲內容的方式--一個文件對應一條內容,以該內容加上特定頭部信息一起的SHA-1校驗和作為文件名。校驗和的前兩個字元用於命名子目錄,餘下的38個字元則作為文件名。後面會詳敘。
可以通過cat-file命令從git那裡查看存儲的內容。
git cat-file -p
由於file1.txt的內容為空,所以這里顯示為空。
這時候可以往file1.txt里添加一些內容,並git add。可以看到.git/objects又多了一個object。
查看這個新的對象的內容以及類型。會發現它是一個blob對象。
接下來commit這個change。
myProject $ git commit -m "first commit"
查看這個commit 對象的類型以及內容,commit的tree對象所指向的內容, 我們會發現,這個tree指向的是一個blob,而這個blob的內容,就是我們剛剛做過改動的文件。
同時,我們查看一下暫存區的內容:
會發現,暫存區指向的也是同樣的blob對象。
至此,一個commit就提交了,工作區,暫存區,以及head又指向了同樣的內容。
它們更新內容的順序為,工作區->暫存區->head
3. git reset
將做過的change撤銷掉,就像沒有發生過一樣。
git reset 應用的順序為 head->暫存區->工作區。
(1) git reset --soft
當前,git的狀態如下。
head指向的內容為:
(head是當前分支引用的指針,總是指向該分支上的最後一次提交。)
index指向的內容為:
(索引是你的預期的下一個提交)
我們來進行一次reset。(移動HEAD, --soft)
--soft將僅僅移動HEAD的指向,而並不會移動index以及工作區。
HEAD 指的是HEAD的父節點。HEAD 是父節點的父節點,也可以寫成HEAD 2.
所以這個命令本質上是撤銷了上一次git commit命令。
(2) git reset --mixed
接下來,再通過reset來更新索引。(--mixed,默認行為)
(3) git reset --hard
reset更新工作目錄(--hard)
git reset --hard HEAD~
--hard標記是reset命令的危險用法,它也是git會真正銷毀數據的幾個操作之一。
如果這個commit已經被推送到遠端,可以用這個命令使遠端也回退到相應的版本。
git push origin <branch> --force
4. git revert
將做過的change撤銷掉,通過「反做」某一個版本,用一個新的commit來消除做過的change。
當前git的狀態:
revert其中一個commit:
再來看,多了一個commit,也就是用來revert的commit:
而若是想要revert某個版本,但是在這個版本後又做過change,則在revert的過程中可能出現沖突,則需要解決沖突之後再提交。
5. git merge 與git rebase
先來講講git merge。
當前master 和 dev branch:
接下來打算將dev的工作並入master分支。
另外,還想將master的工作也並入dev。
git merge之後,會發現dev branch指向了與master相同的commit:
所以,git merge是把兩個分支的最新快照,以及兩者最近的共同祖先進行三方合並,合並的結果是生成一個新的快照。
接下來,用git rebase來合並分支。
當前的git狀態
此時,採用git rebase,將dev的工作並入到master。
當在master branch上執行git rebase dev的時候,實際發生的事情是,找到master和dev兩個分支的最近共同祖先,對比當前分支(master分支)相對於該祖先的歷次提交,提取相應的修改並存為臨時文件,然後將master分支指向目標基底(dev的head指向的commit),最後以此將之前另存為臨時文件的修改依序應用。
可以看到,rebase使得提交歷史更加整潔。盡管實際的開發工作是並行在不同branch上進行的,但是它們看上去就像是串列的一樣,提交歷史是一條直線沒有分叉。
因此,變基是將一系列提交按照原有次序依次應用到另一分支上,而合並是把最終結果合在一起。這兩種方式,整合的最終結果所指向的快照始終是一樣的,只不過提交歷史不同。
㈡ Git常用命令
1.1 配置環境
當安裝Git後首先要做的事情是設置用戶名稱和email地址。這是非常重要的,因為每次Git提交都會使用該用戶信息。該用戶信息和GitHub上注冊的遠程倉庫的相關信息沒有任何關系。
git config --global user.name "你的名字"
git config --global user.email "你的郵箱"
git config --list
配置信息保存在用戶目錄下的.giitconfig文件中
1.2 獲取Git倉庫
要使用Git對我們的代碼進行版本控制,首先需要獲得Git倉庫
獲取Git倉庫通常有兩種方式:
執行步驟如下:
1、在電腦的任意位置創建一個空目錄作為我們的本地Git倉庫
2、進入這個目錄中,點擊右鍵打開Git bash 窗口
3、執行命令git init
可以通過Git提供的命令從遠程倉庫進行克隆,將遠程倉庫克隆到本地的命令形式為:
git clone 遠程Git倉庫地址
1.3 工作目錄、暫存區以及版本庫概念
版本庫:.git隱藏文件就是版本庫,版本庫存儲了很多配置信息、日誌信息和文件版本信息等
工作目錄(工作區):包含.git文件夾的目錄就是工作目錄,主要用於存放開發的代碼
暫存區:.git文件夾中有很多文件,其中一個index文件就是暫存區,也可以叫做stage。暫存區是一個臨時保存修改文件的地方
1.4 Git工作目錄下文件的兩種狀態
Git工作目錄下的文件存在兩種狀態:
Unmodified 未修改狀態
Modified 已修改狀態
Staged 已暫存狀態
這些文件的狀態會隨著我們執行Git的命令發生變化
1.5 本地倉庫操作
git status 查看文件狀態
也可以使用git status -s使輸出信息更簡潔
git add 將未跟蹤的文件加入暫存區,將已經修改的文件加入暫存區也是通過這個命令
git reset 將暫存區文件取消暫存
git commit -m 「你的說明」 將暫存區文件提交到本地倉庫
git rm 刪除文件 說明:這種操作是直接將文件加入到暫存區裡面,直接提交到本地倉庫生效,而直接刪除的話沒有進入到暫存區,需要先把文件加入到暫存區之後,再提交到本地倉庫。
將文件添加至忽略列表
一般我們總會有些文件無需納入Git的管理,也不希望他們總出現在未跟蹤文件列表。通常這些都是自動生成的文件,比如日誌文件,或者編譯過程中創建的臨時文件等。在這種情況下,我們可以在工作目錄中創建一個名為.gitnore的文件(文件名稱固定),列出忽略的文件模式。下面是一個示例:#代表注釋
由於windows無法創建不含文件名的文件,因此我們需要在bash窗口中用如下命令創建。
git log 查看日記記錄
1.6 遠程倉庫操作
如果想查看已經配置的遠程倉庫伺服器,可以運行git remote 命令。它會列出指定的每一個遠程伺服器的簡寫。如果已經克隆了遠程倉庫,那麼至少可以看見origin,這是Git克隆的倉庫伺服器的默認名字
git remote -v 可以查看對遠程倉庫詳細一點的說明
git remote show origin 可以查看對origin更詳細的遠程倉庫的說明
運行git remote add 添加一個遠程Git倉庫,同時指定一個可以引用的簡寫
如果你想獲得一份已經存在了的Git倉庫的拷貝,這時需要用到 git clone 命令。Git克隆的是Git倉庫伺服器上的幾乎所有數據(包括日誌信息、 歷史 記錄等),而不僅僅是復制工作所需要的文件。當你執行git clone 命令的時候,默認配置下Git倉庫中的每一個文件的每一個版本都將被拉取下來。
如果因為一些原因想要移除一個遠程倉庫,可以使用git remote rm
注意:此命令只是從本地移除遠程倉庫的記錄,並不會影響到遠程倉庫
git fetch 是從遠程倉庫獲取最新版本到本地倉庫,不會自動merge
說明:如果使用fetch命令,拉取的文件會放到版本庫裡面,不會自動整合到工作區,如果需要整合到工作區,需要使用 git merge 遠程倉庫別名/遠程倉庫分支
git pull 是從遠程倉庫獲取最新版本並merge到本地倉庫
注意:如果本地倉庫不是從遠程倉庫克隆,而是本地創建的倉庫,並且倉庫中存在文件,此時再從遠程倉庫中拉取文件的時候會報錯(fatal:refusing to merge unrelated histories),解決此我呢提可以在git pull 命令後加入參數 --allow-unrelated-histories
git push
1.7 Git分支
幾乎所有的版本控制系統都是以某種形式支持分支。使用分支意味著你可以把你的工作從開發主線上分離開來,以免影響開發主線。Git的master是一個特殊分支。它跟其它分支沒有區別。之所以每一個倉庫都有mater分支,是因為git init默認創建它,並且大多數人都懶得去改動它。
# 列出所有本地分支
$ git branch
#列出所有遠程分支
$ git branch -r
#列出所有本地分支和遠程分支
$git branch -a
git branch 分支名稱
git checkout 分支名稱
git push 遠程倉庫別名 遠程倉庫分支
git merge 分支名稱 說明:在當前分支下合並其他分支
注意:如果兩個分支存在同樣的文件名且同行的內容不一樣,那麼會產生矛盾,需要自己手動修改產生矛盾後的文件,然後添加到暫存區然後提交。
git branch -d 分支名稱
如果要刪除的分支中進行了一些開發動作,此時執行上面的刪除命令並不會刪除分支,可以將命令中的-d參數改為-D
如果要刪除遠程倉庫中的分支,可以使用命令git push origin -d branchName
1.8 Git標簽
像其他版本控制系統一樣,Git可以給 歷史 中的某一給提交打上標簽,以示重要。比較有代表性的是人們會使用這個功能來標記發布結點(v1.0、v1.2等)。標簽指的是某個分支某個特定時間點的狀態。通過標簽,可以很方便地切換到標記時的狀態。
#新建一個tag
$ git tag [tagName]
$ git tag
#新建一個分支,指向某個tag
$ git checkout -b [branch] [tag]
#刪除本地tag
$git tag -d[tag]
#刪除遠程tag
$git push origin :refs/tags/[tag]
㈢ git分支合並問題討論
關於git的分支合並會被覆蓋的問題
首先在project1和project2中使用git init初始化倉庫
然後直接使用git checkout -b test的方式創建分支,出現如圖所示的情況
在test分支使用git branch命令發現沒有分支情況,然後使用git branch master命令想要創建主分支,出現了如圖的錯誤:fatal: Not a valid object name: 'master'.
網上查詢了一下,發現是分支只是申明了,但是沒有初始化,需要使用一次add 和commit去初始化分支。
參考鏈接: https://blog.csdn.net/jackie_tsai/article/details/51587994
接著我使用git remote add origin 地址 添加一個遠程倉庫地址,先將建立好的test分支上傳到遠程倉庫,這樣遠程倉庫也會自動創建好一個名為test的分支
為了測試的簡易性,我在project1和project2中都創建了一個test.txt的文本,文本內容如下:
project1:
然後我將兩個文本上傳到遠程倉庫中:
首先是project1
然後上傳project2的
出現這個錯誤的原因是,我之前在project1中上傳了文本,更改了遠程倉庫中類似版本號的東西,然後project2再上傳本文的時候,因為本地倉庫不是遠程倉庫的版本號,所以報出這樣的錯誤
有兩種方法:
1、git push -f origin test:將本地倉庫的數據強制上傳到遠程倉庫,這樣會造成project1上傳的數據丟失
2、先使用git pull origin test將遠程倉庫的數據拉到本地進行合並,然後再上傳到遠程倉庫,下面展示這種方法:
我們可以看到,遠程倉庫和本地相同文本進行了合並(merge),查看下文本內容變化:
因為發生了一個合並的操作,需要重新經歷add - commit 的過程
沒問題,遠程倉庫的數據是預期的,接下來就是我遇到問題的地方了
我重新修改了project1文本的內容,然後上傳到遠程倉庫
上傳成功,然後我再從project2中將遠程倉庫的數據拿出來
問題來了,為什麼第一次我們從遠程倉庫拉到本地能夠實現相同數據的合並,而這一次不行呢,經過多番測試,我發現,merge合並的內容是commit內容的文本,也就是說,如果test.txt在本地有commit的操作,那麼從遠程倉庫拉取數據的時候會合並這一部分數據,然後需要重新的add-commit,至於沒有commit操作的其他文本,會被遠程倉庫直接覆蓋掉。
總結:
分支合並合並的是commit的內容,也就是版本庫的內容,並且分支合並基本都是在本地進行的,也就是無法在客戶端去合並遠程倉庫里的分支。
㈣ 圖解4種git合並分支方法
原文網址: http://yanhaijing.com/git/2017/07/14/four-method-for-git-merge/
有時候我們會後悔,有時候我們會想回到過去,有時候我們想改變歷史,然而在我們這個世界,目前來看是無法回到過去改變歷史的
但在git的世界裡,一切皆有可能,我們可以在多維空間里任意切換,隨意改變一個宇宙的時間線,只要我們願意,git的分支就是這么神奇
然而很多時候你以為你改變了歷史,不為人知,那個宇宙並沒有消失,而是遺失在了git的世界裡,有能力的人便能找到
彼此分開的世界也能隨時交叉合並,世界就這樣開開合合,偶會需要解決合並沖突
git中的分支非常的輕量,其實就是一個文件,裡面記錄了分支所指向的commit id,下圖中有兩個分支分別是master和test,他們都指向了A2這個提交,HEAD是一個特殊的指針,他永遠指向你當前所在的位置;有時候你可能不在某一個分支上,不要驚慌,你隨時有權利去你想去的分支,git賦予了你新建,切換分支的能力
然後有時候世界並不總如上圖那般美好,面對分叉的兩個分支,git新手總是一臉茫然,本文我將講述git中合並分支的方法
在git中合並分支有三種方法,分別是merge,rebase,cherry-pick,而其中merge又有三種區別,下面將一一介紹
如果待合並的分支在當前分支的下游,也就是說沒有分叉時,會發生快速合並,從test分支切換到master分支,然後合並test分支
這種方法相當於直接把master分支移動到test分支所在的地方,並移動HEAD指針
如果我們不想要快速合並,那麼我們可以強制指定為非快速合並,只需加上 --no-ff 參數
這種合並方法會在master分支上新建一個提交節點,從而完成合並
svn的在合並分支時採用的就是這種方式,squash會在當前分支新建一個提交節點
squash和no-ff非常類似,區別只有一點不會保留對合入分支的引用
當要合並兩個分叉的分支時,merge的方式是將待合入分支和當前分支不同的部分,在當前分支新建節點,如下圖所示
rebase與merge不同,rebase會將合入分支上超前的節點在待合入分支上重新提交一遍,如下圖,B1 B2會變為B1』 B2』,看起來會變成線性歷史
這命令簡直就是神器,給你自由,你想把那個節點merge過來就把那個節點merge過來,其合入的不是分支而是提交節點
只有知道了這些合並方式的區別,才能git在手,天下我有,任你分支在凌亂,我自巋然不動
原文網址: http://yanhaijing.com/git/2017/07/14/four-method-for-git-merge/
㈤ git(五 合並提交命令)
場景 :本地做了四次提交,想把第 2、3、4 次提交合並,只保留第二次提交的commit message
解決方案 :
1、git reflog 查看所有的提交記錄
p.s. git reflog 可以查看所有分支的所有操作記錄(包括已經被刪除的 commit 記錄和 reset 的操作);git log 命令可以顯示所有提交過的版本信息,看不到刪除的記錄。所以買後悔葯回退刪除記錄的時候,可以用 git reflog
上面的圖片展示了,一共四次提交,按照時間倒序排列分別是 第 4、3、2、1次提交
2、git rebase -i 「最新的一個想保留的 Commit」
意思是,我想合並2、3、4,那麼最新一個想保留的 commit 就是 第一次 commit,他的hash值為 ae9c811,輸入下列命令並回車
或者
3、選擇要合並的 commit :上述步驟完成後會跳出下圖界面
注意這個時候的順序:最近一次提交在最下面
前面三行是我們需要操作的三個 Commit,每行最前面的是對該 Commit 操作的 Command。關於每個 Command 具體做什麼,下面的注釋寫得非常清楚。為了完成我們的需求,我們可以關注到這兩個命令:
我們可以選擇把第 3、4 次的commit message合並到第二次上面,修改command如下,並保存退出:
4、編輯合並 commit 的 commit message
上述步驟完成後,會跳出如下界面
5、檢查:使用git log檢查
結果如下:
注意,使用git reflog仍可以查看最初的命令:
兩者的區別在於,git log只顯示保留的,git reflog可以顯示 reset 和 rebase、刪除的版本
編譯器的可視化git工具中的展示:
這個時候再push,提交記錄上就非常好看了
請注意 :
㈥ git 自定義命令,合並多個命令
問題:如何自定義命令,如何將多個命令進行合並執行?
通過給命令起 別名 的方式,來簡化命令
解析:
別名語法 git config --global alias.【別名】 '【執行的命令】'
執行函數: !f(){ 【命令】; }; f :表示定義f函數,並執行
相當於執行 git add .
合並命令為rpush:檢出新的分支
解析:
別名語法 git config --global alias.【別名】 '【執行的命令】'
執行函數: !f(){ 【命令】; }; f :表示定義f函數,並執行
A&&B :與符號,執行A成功後,執行B
$1 :表示變數
相當與執行以下命令
㈦ git合並分支沖突解決
1、執行合並
執行 merge 命令 git merge [有新內容分支名]
2、出現沖突,文件中沖突的表現
3、沖突的解決
3.1 編輯沖突文件,進行人工合並
3.2:git add [文件名] // 這是相對路徑,執行命令的文件位置,要保證可以通過文件名能找到這個文件
3.3:git commit -m "日誌信息"
3.4 此時 commit 一定不能帶具體文件名
㈧ 【Git】合並兩個沒有共同祖先的分支
在 github 上創建了項目,要和本地的項目合並。
此時提示:
這是因為兩個分支沒有共同祖先,無法合並,此時可使用如下命令:
成功,再執行
提交完成。
㈨ git分支的創建與合並
1、分支創建命令
2、分支合並:切換到master後,進行合並「分支名1」,然後要記得git push
注意:這里merge以後要記得git push哦
3、分支刪除:
刪除本地分支
注意:當分支改動後沒有merge到主分支時,進行刪除會報錯哦
刪除遠程分支:
4、合並時沖突:分支merge的過程,可能會因為多個人或多個分支同時修改同一個地方,導致文件沖突,merge會失敗。此時會提示merge失敗。可以用git status查看merge失敗的具體情況,再到對應文件中手動解決沖突再進行merge
5、分支管理:git branch
學習鏈接