本篇文章已授權(quán)微信公眾號(hào) guolin_blog (郭霖)獨(dú)家發(fā)布
0. 序言
之前不太重視Git的命令行操作蠕蚜,直到去了前些天一直炒的非潮罟拢火的某某某某公司,呆了幾天幫忙解BUG姐帚,發(fā)現(xiàn)項(xiàng)目不用AndroidStudio的圖形化界面操作版本控制衷旅,一時(shí)間傻眼......想到應(yīng)該也有小伙伴和我一樣器一,所以就有了這篇文章课锌,希望通過(guò)閱讀這篇文章大家都能學(xué)會(huì)Git命令行操作。
講述方式非面面俱到。喜歡后者的渺贤,可以買本書細(xì)細(xì)品雏胃。講解目錄如下:
- 簡(jiǎn)介
- Git的完整性
- Git的文件狀態(tài)和工作區(qū)域
- 用戶身份
- 編輯器
- 創(chuàng)建本地倉(cāng)庫(kù)
- 常用本地操作
- 版本回退
- 撤銷修改
- 撤銷提交
- 撤銷遠(yuǎn)程提交
- 暫存修改
- 刪除相關(guān)操作
- 遠(yuǎn)程倉(cāng)庫(kù)
- 分支
- 解決沖突
- 變基
- 別名
- 拉取遠(yuǎn)程分支
- 修改本地名稱分支
- 修改遠(yuǎn)程分支名稱
- 創(chuàng)建遠(yuǎn)程分支
- 解決添加忽略失敗
簡(jiǎn)介
Git 是分布式版本控制系統(tǒng),客戶端保留完整的代碼倉(cāng)庫(kù)志鞍,就算搭載遠(yuǎn)程倉(cāng)庫(kù)的服務(wù)器出了故障瞭亮,客戶端的數(shù)據(jù)也可以用來(lái)恢復(fù)服務(wù)器數(shù)據(jù)。
Git 操作幾乎都在本地完成固棚,速度快统翩,效率高,且不受網(wǎng)絡(luò)限制此洲。
Git的完整性
Git以校驗(yàn)和的方式檢測(cè)數(shù)據(jù)的完整性厂汗。采用的校驗(yàn)和機(jī)制叫做SHA-1散列。SHA-1散列由40個(gè)十六進(jìn)制字符(0-9和a-f)所組成的字符串呜师,這些字符串是根據(jù)文件內(nèi)容和Git的目錄結(jié)構(gòu)計(jì)算所得娶桦。在Git中commit id 就是校驗(yàn)和,如下:
$git log
commit 555af4a0aadb6c64a73acfd94c8fe89af5604083
Author: Fu Kaiqiang <fukaiqiang@xxx.com>
Date: Mon Sep 17 10:45:24 2018 +0800
first commit
Git的文件狀態(tài)和工作區(qū)域
- 工作區(qū)域:
① 工作目錄:平時(shí)寫代碼的區(qū)域汁汗。
② 暫存區(qū):代碼add以后commit之前所在的地方衷畦。
③ 本地倉(cāng)庫(kù):代碼commit以后所在的地方。 - 文件狀態(tài):
① 已修改:工作目錄修改以后知牌,代碼沒(méi)有add到暫存區(qū)祈争,也沒(méi)有commit到本地倉(cāng)庫(kù)。
② 已暫存:工作目錄修改以后角寸,代碼已經(jīng)add到暫存區(qū)菩混,沒(méi)有commit到本地倉(cāng)庫(kù)。
③ 已提交:工作目錄修改以后袭厂,代碼已經(jīng)commit到本地倉(cāng)庫(kù)墨吓。
用戶身份
- 配置個(gè)人信息
$ git config --global user.name "Your Name"
$ git config --global user.email "email@example.com"
說(shuō)明:--global 表示你這臺(tái)機(jī)器上所有的Git倉(cāng)庫(kù)都會(huì)使用這個(gè)配置
- 查看個(gè)人信息
$git config --list
user.email=fukaiqiang@xxx.com
user.name=Fu Kaiqiang
alias.st=status
alias.co=checkout
alias.dt=difftool -t meld -y
color.ui=auto
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
remote.origin.url=git@github.com:OnlyYouMyLove/TestGit.git
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
branch.master.remote=origin
branch.master.merge=refs/heads/master
編輯器
- 不同操作系統(tǒng)推薦使用不同編輯器球匕,Linux推薦使用Vim纹磺,Window可使用NotePad++
以vim為例:
vim TestGit.md
說(shuō)明:vim 可以創(chuàng)建并打開(kāi)TestGit.md文件。不是重點(diǎn)亮曹,不詳述橄杨,感興趣,可找小度或小谷照卦。
創(chuàng)建本地倉(cāng)庫(kù)
- 初始化本地倉(cāng)庫(kù)
- $ git init
說(shuō)明:初始化倉(cāng)庫(kù)式矫,生成 .git 文件即可
- 克隆遠(yuǎn)程倉(cāng)庫(kù)到本地
$git clone git@github.com:OnlyYouMyLove/TestGit.git
Cloning into 'TestGit'...
remote: Counting objects: 6, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 6 (delta 0), reused 6 (delta 0), pack-reused 0
Receiving objects: 100% (6/6), 4.76 KiB | 0 bytes/s, done.
Checking connectivity... done.
說(shuō)明:
① 初始化倉(cāng)庫(kù)和克隆遠(yuǎn)程倉(cāng)庫(kù)是創(chuàng)建本地倉(cāng)庫(kù)兩種方式,根據(jù)場(chǎng)景不同役耕,選擇不同的創(chuàng)建方式采转。
② 本地倉(cāng)庫(kù)初始化以后,還需要和遠(yuǎn)程倉(cāng)庫(kù)進(jìn)行關(guān)聯(lián),遠(yuǎn)程倉(cāng)庫(kù)部分講故慈。
- 克隆遠(yuǎn)程倉(cāng)庫(kù)的某個(gè)分支到本地
git clone -b v1.6.3 https://github.com/square/leakcanary.git
常用本地操作
- 添加文件到暫存區(qū)
$ git add readme.txt
- 把暫存區(qū)的文件提交到本地倉(cāng)庫(kù)
$ git commit -m "wrote a readme file"
說(shuō)明: -m后添加此次提交的說(shuō)明
- 跳過(guò)暫存區(qū)執(zhí)行提交
$git commit -a -m "skip stage to commit"
On branch master
Your branch is ahead of 'origin/master' by 3 commits.
(use "git push" to publish your local commits)
nothing to commit, working directory clean
說(shuō)明:-a 參數(shù)可以自動(dòng)暫存文件板熊,然后執(zhí)行提交。
- 查看本地倉(cāng)庫(kù)提交歷史
$git log
commit 462a66ec484df873bc5638fbd53523408ecfed43
Merge: 34a6e3f 44d733a
Author: Fu Kaiqiang <fukaiqiang@xxx.com>
Date: Fri Sep 14 10:28:10 2018 +0800
Merge remote-tracking branch 'origin/master'
commit 34a6e3f6dba34d4870da3f9a25ab653a33ae2a49
Author: Fu Kaiqiang <fukaiqiang@xxx.com>
Date: Fri Sep 14 10:21:42 2018 +0800
Today is Friday!
- 簡(jiǎn)潔的方式查看本地倉(cāng)庫(kù)提交歷史
$git log --pretty=oneline
462a66ec484df873bc5638fbd53523408ecfed43 Merge remote-tracking branch 'origin/master'
34a6e3f6dba34d4870da3f9a25ab653a33ae2a49 Today is Friday!
- 查看文件狀態(tài)
$git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: TestGit.md
Untracked files:
(use "git add <file>..." to include in what will be committed)
.TestGit.md.swo
.TestGit.md.swp
說(shuō)明:
① Changes to be committed:已暫存察绷、可提交文件
② Untracked files:未暫存文件
- 查看未暫存文件變更細(xì)節(jié)
$git diff
diff --git a/TestGit.md b/TestGit.md
index 1de64fb..89aaf06 100644
--- a/TestGit.md
+++ b/TestGit.md
@@ -1,2 +1,3 @@
Hello World
Hello Chuizi
+Hello Branch
- 查看已暫存文件變更細(xì)節(jié)
$git diff --staged
diff --git a/TestGit.md b/TestGit.md
index bc8bff8..2d675a0 100644
--- a/TestGit.md
+++ b/TestGit.md
@@ -2,3 +2,4 @@ Hello World
Hello Chuizi
Hello HUAWEI
Hello XIAOMI
+Hello MEIZU
說(shuō)明:文件一旦暫存干签,通過(guò)git diff命令就不能查詢差異,必須添加--staged參數(shù)拆撼,或--cached參數(shù)容劳。
版本回退
- 回退到上一個(gè)版本
文件內(nèi)容:
1 Hello World
2 Test Git
3 Hello ChuiZi
4 Hello JianGuo
5 hahahahah
6 fdafafafafaf
7 fajfkajfakdjfk
8 eight line
9 nine line
10 tenth line
$git log
commit c836aafa9e33890aebd9b53c816e3180ccd4ddb7
Author: Fu Kaiqiang <fukaiqiang@smartisan.com>
Date: Fri Sep 14 17:01:59 2018 +0800
add tenth line
commit b1a66343568506fdb9960ebd3d896fd798ac61a4
Author: Fu Kaiqiang <fukaiqiang@smartisan.com>
Date: Fri Sep 14 17:01:09 2018 +0800
add ninth line
$git reset --hard HEAD^
HEAD is now at b1a6634 add ninth line
說(shuō)明:以上這句命令行代碼是核心代碼
$git log
commit b1a66343568506fdb9960ebd3d896fd798ac61a4
Author: Fu Kaiqiang <fukaiqiang@smartisan.com>
Date: Fri Sep 14 17:01:09 2018 +0800
add ninth line
文件內(nèi)容:
1 Hello World
2 Test Git
3 Hello ChuiZi
4 Hello JianGuo
5 hahahahah
6 fdafafafafaf
7 fajfkajfakdjfk
8 eight line
9 nine line
- 查詢每次版本提交記錄
$git reflog
c836aaf HEAD@{0}: reset: moving to c836a
b1a6634 HEAD@{1}: reset: moving to HEAD^
c836aaf HEAD@{2}: commit: add tenth line
b1a6634 HEAD@{3}: commit: add ninth line
說(shuō)明:內(nèi)容包括 ① commit id ② 執(zhí)行的命令 ③ 描述
- 回退到指定版本
$git reset --hard c836a
HEAD is now at c836aaf add tenth line
說(shuō)明:
① 找到commit id,就可以回退到指定版本闸度。
② commit id 不用填全部竭贩,填寫部分,git 自動(dòng)查找筋岛。
- 查看工作區(qū)和版本庫(kù)里面最新版本的區(qū)別
修改TestGit.md內(nèi)容為:
Hello World
$git add TestGit.md
再修改TestGit.md內(nèi)容為:
Hello World
Hello Chuizi
$git commit -m "Two line"
[master 7dd7cf8] Two line
1 file changed, 1 insertion(+), 11 deletions(-)
$git status
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
(use "git push" to publish your local commits)
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: TestGit.md
no changes added to commit (use "git add" and/or "git commit -a")
說(shuō)明:這時(shí)發(fā)現(xiàn)還有未添加到暫存區(qū)的內(nèi)容娶视。
$git diff HEAD -- TestGit.md
diff --git a/TestGit.md b/TestGit.md
index 35eab83..1de64fb 100644
--- a/TestGit.md
+++ b/TestGit.md
@@ -1,2 +1,2 @@
Hello World
-
+Hello Chuizi
說(shuō)明:
① 發(fā)現(xiàn)第二次修改沒(méi)有提交到暫存區(qū),導(dǎo)致 git commit 提交的只是第一次的修改睁宰。
② git diff 命令是核心代碼肪获。
③ 這個(gè)時(shí)候再執(zhí)行一遍add和commit操作即可。
撤銷修改
- 撤銷未添加到暫存區(qū)的修改
fukqdembp:TestGit fukq$ git status
On branch master
Your branch is up to date with 'origin/master'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: TestGit.md
no changes added to commit (use "git add" and/or "git commit -a")
說(shuō)明:discard changes - 放棄修改:的提示為 "git checkout -- <file>..."
fukqdembp:TestGit fukq$ git checkout -- TestGit.md
fukqdembp:TestGit fukq$ git status
On branch master
Your branch is up to date with 'origin/master'.
nothing to commit, working tree clean
- 撤銷已添加到暫存區(qū)的修改:
fukqdembp:TestGit fukq$ git add TestGit.md
fukqdembp:TestGit fukq$ git status
On branch master
Your branch is up to date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: TestGit.md
說(shuō)明:to unstage - 不暫存的提示為 "git reset HEAD <file>..."
fukqdembp:TestGit fukq$ git reset HEAD TestGit.md
Unstaged changes after reset:
M TestGit.md
fukqdembp:TestGit fukq$ git status
On branch master
Your branch is up to date with 'origin/master'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: TestGit.md
no changes added to commit (use "git add" and/or "git commit -a")
fukqdembp:TestGit fukq$
撤銷提交
當(dāng)你commit以后柒傻,想撤銷commit孝赫,但是又不想丟掉已經(jīng)改動(dòng)的代碼
git reset --soft HEAD^
撤銷遠(yuǎn)程提交
- 單個(gè)撤銷
git revert <commit>
- 多個(gè)連續(xù)提交用多個(gè)commit撤銷
git revert oldcommit^..newcommit
- 多個(gè)連續(xù)提交用一個(gè)commit撤銷
git revert -n oldcommit^..newcommit
- 遇到?jīng)_突
git add file
git revert --continue
git commit
git push
暫存修改
git stash
git pull
git stash pop
當(dāng)你在一個(gè)分支進(jìn)行修改后,需要切換到其他分支红符,這個(gè)時(shí)候你需要把修改撤銷掉才能切換到其他分支青柄。但是你又不想失去這些修改,那便可以暫存修改预侯,即撤銷修改并把修改存儲(chǔ)起來(lái)致开,然后切換到其他分支,等從其他分支切換回來(lái)之后萎馅,再恢復(fù)修改即可双戳。
刪除相關(guān)操作
- 刪除文件后的Git同步操作
fukqdembp:TestGit fukq$ git add TestGit.txt
fukqdembp:TestGit fukq$ git commit -m "remove TestGit.txt"
...
假如已經(jīng)提交了文件TestGit.txt
fukqdembp:TestGit fukq$ rm TestGit.txt
現(xiàn)在我在本地刪除了這個(gè)文件
fukqdembp:TestGit fukq$ git status
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
(use "git push" to publish your local commits)
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: TestGit.txt
no changes added to commit (use "git add" and/or "git commit -a")
fukqdembp:TestGit fukq$ git rm TestGit.txt
rm 'TestGit.txt'
假如想讓線上也刪除這個(gè)文件,執(zhí)行上述操作和下述操作即可糜芳。
fukqdembp:TestGit fukq$ git commit TestGit.txt -m "刪除TestGit.txt文件"
[master 7075b5f] 刪除TestGit.txt文件
1 file changed, 1 deletion(-)
delete mode 100644 TestGit.txt
fukqdembp:TestGit fukq$ git status
On branch master
Your branch is ahead of 'origin/master' by 2 commits.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
fukqdembp:TestGit fukq$ ls
LICENSE README.md TestGit.md
- 刪除文件后的恢復(fù)文件操作
fukqdembp:TestGit fukq$ rm TestGit.txt
fukqdembp:TestGit fukq$ git status
On branch master
Your branch is ahead of 'origin/master' by 3 commits.
(use "git push" to publish your local commits)
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: TestGit.txt
no changes added to commit (use "git add" and/or "git commit -a")
fukqdembp:TestGit fukq$ git checkout -- TestGit.txt
fukqdembp:TestGit fukq$ ls
LICENSE README.md TestGit.md TestGit.txt
說(shuō)明:$ git checkout --TestGit.txt 既可以對(duì)未添加到暫存區(qū)的修改操作進(jìn)行恢復(fù)飒货,也可以對(duì)已刪除的文件進(jìn)行恢復(fù)。
遠(yuǎn)程倉(cāng)庫(kù)
- 關(guān)聯(lián)遠(yuǎn)程倉(cāng)庫(kù)
$git remote add origin git@github.com:OnlyYouMyLove/TestGit.git
說(shuō)明:
① 組成 -- git remote add + 自定義倉(cāng)庫(kù)命名 + 倉(cāng)庫(kù)ssh地址
② git init 初始化倉(cāng)庫(kù)以后需要進(jìn)行 git remote操作峭竣,實(shí)現(xiàn)本地和遠(yuǎn)程倉(cāng)庫(kù)的綁定塘辅,這才能算是完整創(chuàng)建本地倉(cāng)庫(kù)。
- 第一次推送本地倉(cāng)庫(kù)內(nèi)容到遠(yuǎn)程倉(cāng)庫(kù)
$git push -u origin master
說(shuō)明:
① -u 參數(shù)的添加可以讓本地倉(cāng)庫(kù)和遠(yuǎn)程倉(cāng)庫(kù)進(jìn)行綁定
② 如果報(bào)以下錯(cuò),意思是缺少權(quán)限--本地生成ssh,添加到github的ssh列表即可:
$git push -u origin master
Warning: Permanently added the RSA host key for IP address 'xxx.xx.xxx.xxx' to the list of known hosts.
Permission denied (publickey).
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.
③ 如果報(bào)以下錯(cuò),輸入yes即可:
The authenticity of host 'github.com (xx.xx.xx.xx)' can't be established.
RSA key fingerprint is xx.xx.xx.xx.xx.
Are you sure you want to continue connecting (yes/no)?
Warning: Permanently added 'github.com' (RSA) to the list of known hosts.
說(shuō)明:警告只會(huì)出現(xiàn)一次皆撩。
④ 查看ssh key (linux系統(tǒng)下扣墩,其他系統(tǒng)大同小異):
$cat ~/.ssh/id_rsa.pub
- 非第一次推送本地倉(cāng)庫(kù)內(nèi)容到遠(yuǎn)程倉(cāng)庫(kù)
$git push origin master
- 從遠(yuǎn)程倉(cāng)庫(kù)拉取數(shù)據(jù)到本地
$git fetch origin
說(shuō)明:
① git clone 自動(dòng)命名遠(yuǎn)程倉(cāng)庫(kù)服務(wù)器名字為origin,并拉取全部數(shù)據(jù),然后在本地創(chuàng)建指向服務(wù)器上master分支的指針呻惕,并命名為origin/master,它就叫遠(yuǎn)程分支盘榨,接著git會(huì)創(chuàng)建本地master分支。
② fetch 這條命令會(huì)從服務(wù)器取得所有本地尚未包含的數(shù)據(jù)蟆融,然后更新遠(yuǎn)程分支草巡。注意:只是更新遠(yuǎn)程分支,本地master分支并未改變型酥,需要合并才行山憨。
③ origin 與 master分支名稱一樣,只是默認(rèn)名稱弥喉,沒(méi)有什么特殊含義郁竟,都可以自定義。
$git merge origin/master
Updating ce50a7f..253d867
Fast-forward
TestGit.md | 1 +
1 file changed, 1 insertion(+)
說(shuō)明:只要經(jīng)過(guò)fetch和merge才能把遠(yuǎn)程倉(cāng)庫(kù)的數(shù)據(jù)同步給本地倉(cāng)庫(kù)由境。
- 從遠(yuǎn)程倉(cāng)庫(kù)拉取數(shù)據(jù)并直接合并到本地
$git pull origin master
From github.com:OnlyYouMyLove/TestGit
* branch master -> FETCH_HEAD
Updating ce50a7f..5ec3b49
Fast-forward
.test.swp | Bin 0 -> 4096 bytes
TestGit.md | 3 +++
2 files changed, 3 insertions(+)
create mode 100644 .test.swp
說(shuō)明:pull 命令直接拉取數(shù)據(jù)到遠(yuǎn)程分支并且合并數(shù)據(jù)到master分支棚亩。
分支
- 創(chuàng)建并切換分支
$git checkout -b dev
Switched to a new branch 'dev'
說(shuō)明:-b 參數(shù) 意思是 創(chuàng)建并切換分支,相當(dāng)于下面兩條命令
$ git branch dev 創(chuàng)建分支
$ git checkout dev 切換分支
Switched to branch 'dev'
- 查看當(dāng)前分支
$git branch
* master
$git checkout -b dev
Switched to a new branch 'dev'
$git status
On branch dev
nothing to commit, working directory clean
$git branch
* dev
master
說(shuō)明:核心命令--git branch虏杰,并用 * 指向當(dāng)前所在分支
- 合并分支
$git branch
* dev
master
$vim TestGit.md
$git checkout master
M TestGit.md
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
$git branch
dev
* master
$git merge dev
Already up-to-date.
說(shuō)明:操作步驟如下
① 在dev分支上編輯TestGit
② 切換到master分支
③ 合并dev到當(dāng)前分支master
- 刪除分支
$git branch -d dev
Deleted branch dev (was 555af4a).
解決沖突
- 場(chǎng)景分析和解決辦法
一個(gè)文件讥蟆,兩個(gè)分支,每個(gè)分支都對(duì)文件中的相同一句話做了不同的修改纺阔。當(dāng)一個(gè)分支修改完提交后瘸彤,另外一個(gè)分支修改提交,然后合并另外一個(gè)分支的時(shí)候就會(huì)產(chǎn)生沖突笛钝,而解決的方法就是繼續(xù)修改文件质况,把兩個(gè)分支都操作的那句話進(jìn)行最終編輯,然后提交即可玻靡。
創(chuàng)建并切換到dev分支
$git checkout -b dev
M TestGit.md
Switched to a new branch 'dev'
編輯TestGit.md文件
$vim TestGit.md
編輯以后:
Hello World
Hello Chuizi
Hello XIAOMI
暫存
$git add TestGit.md
提交
$git commit TestGit.md -m "dev commit file"
[dev 6a31928] dev commit file
1 file changed, 1 insertion(+)
切換到master分支
$git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
編輯TestGit.md文件
$vim TestGit.md
編輯以后:
Hello World
Hello Chuizi
Hello HUAWEI
暫存
$git add TestGit.md
提交
$git commit TestGit.md -m "master commit file"
[master b62ed88] master commit file
1 file changed, 1 insertion(+)
合并
$git merge dev
Auto-merging TestGit.md
CONFLICT (content): Merge conflict in TestGit.md
Automatic merge failed; fix conflicts and then commit the result.
編輯TestGit.md文件
$vim TestGit.md
Hello World
Hello Chuizi
<<<<<<< HEAD
Hello HUAWEI
=======
Hello XIAOMI
>>>>>>> dev
說(shuō)明:=======上面是HEAD(master)版本 >>>>>>>上面是dev版本
解決沖突--進(jìn)行編輯:
Hello World
Hello Chuizi
Hello HUAWEI
Hello XIAOMI
暫存
$git add TestGit.md
提交
$git commit TestGit.md
fatal: cannot do a partial commit during a merge.
說(shuō)明:出現(xiàn)沖突以后结榄,修改文件解決沖突后,不能提交部分文件
上面的commit修改為提交所有文件即可
$git commit -m "merge files"
[master 39791ca] merge files
- 查看分支的合并圖:
$git log --graph --pretty=oneline --abbrev-commit
* 39791ca merge files
|\
| * 6a31928 dev commit file
* | b62ed88 master commit file
|/
* 555af4a first commit
從合并圖可以看出來(lái)是dev和master的合并:
① 555af4a first commit :首次的提交
② 6a31928 dev commit file b62ed88 master commit file :dev先提交master后提交
③ 39791ca merge files :解決沖突后合并提交
變基
$git log --graph --pretty=oneline --abbrev-commit
* 39791ca merge files
|\
| * 6a31928 dev commit file
* | b62ed88 master commit file
|/
* 555af4a first commit
- 上面是分支沖突后的合并圖log囤捻,你會(huì)發(fā)現(xiàn)非尘世剩混亂,兩個(gè)commit一個(gè)merge最蕾,并不在一條直線上依溯。而這僅僅是一次沖突的合并老厌。合并越多瘟则,歷史log越亂!一個(gè)項(xiàng)目的合并次數(shù)可能達(dá)到成百上千枝秤,如果歷史合并log非炒着。混亂,會(huì)對(duì)閱讀造成非常大的障礙,影響工作效率丹壕,那能否左邊的圖是一條直線而非菱形呢庆械?答案是肯定的,當(dāng)本地出現(xiàn)沖突的時(shí)候使用變基--rebase來(lái)替代合并--merge菌赖。
- 那為什么merge后會(huì)產(chǎn)生菱形歷史缭乘?這就要從其實(shí)質(zhì)說(shuō)起 : dev 分支、master 分支琉用、兩者的共同祖先一起合并生成新的快照堕绩,我們稱這種提交叫做“合并提交",而合并提交并非只有一個(gè)父提交邑时,這里有兩個(gè)dev和master奴紧。所以合并歷史圖出現(xiàn)了菱形。
復(fù)現(xiàn)沖突場(chǎng)景:dev和master分別修改了同一個(gè)文件的相同地方晶丘,并且執(zhí)行了暫存和提交黍氮,然后我們這里執(zhí)行rebase操作:
$git checkout dev
Switched to branch 'dev'
$git rebase master
First, rewinding head to replay your work on top of it...
Applying: dev commit
Using index info to reconstruct a base tree...
M TestGit.md
Falling back to patching base and 3-way merge...
Auto-merging TestGit.md
CONFLICT (content): Merge conflict in TestGit.md
error: Failed to merge in the changes.
Patch failed at 0001 dev commit
The copy of the patch that failed is found in: .git/rebase-apply/patch
When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".
說(shuō)明:rebase失敗,讓先解決沖突浅浮,然后用 "git rebase --continue"
$vim TestGit.md
$git add TestGit.md
$git rebase --continue
Applying: dev commit
$git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 1 commit.
(use "git push" to publish your local commits)
$git merge dev
Updating 6321248..ce50a7f
Fast-forward
TestGit.md | 1 +
1 file changed, 1 insertion(+)
$git log --graph --pretty=oneline --abbrev-commit
* ce50a7f dev commit
* 6321248 master commit
* 555af4a first commit
- 為什么變基可以實(shí)現(xiàn)一條線的歷史提交效果呢沫浆?那我們也看看其原理:首先找到兩個(gè)要整合的分支(你當(dāng)前所在的分支和要整合到的分支)的共同祖先,然后取得當(dāng)前所在分支的每次提交引入的更改(diff)滚秩,并把這些更改保存為臨時(shí)文件件缸,這之后將當(dāng)前分支重置為要整合到的分支,最后在該分支上依次引入之前保存的每個(gè)更改叔遂。說(shuō)白了就是記錄dev的更改并保存他炊,然后把保存的更改依次引入master分支,這樣相當(dāng)于所有的更改都在master上已艰。merge和rebase的結(jié)果相同痊末,但是提交歷史完全不同。
- 你說(shuō)還不明白哩掺,還是沒(méi)有看出區(qū)別凿叠!但是你仔細(xì)想想其實(shí)區(qū)別很大:變基實(shí)際上是拋棄了dev的已有的提交,隨后創(chuàng)建了新的對(duì)應(yīng)提交嚼吞,內(nèi)容相似盒件,但是卻是不同的提交。
別名
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.cm commit
git config --global alias.st status
git config --global alias.unstage 'reset HEAD --'
git config --global alias.last 'log -1 HEAD'
提高效率舱禽,不防試試...
拉取分支
git fetch origin branch1:branch2
branch1:遠(yuǎn)程分支的名稱 branch2:創(chuàng)建一個(gè)本地分支對(duì)齊遠(yuǎn)程分支branch1
注意:此時(shí)本地分支并沒(méi)有切換到branch2
修改本地分支名稱
git branch -m old_name new_name
修改遠(yuǎn)程分支名稱
- 先修改本地分支名稱
git branch -m old_name new_name
- 刪除遠(yuǎn)程分支
git push --delete origin old_name
注意:刪除遠(yuǎn)程分支之前確保本地分支與最新的遠(yuǎn)程分支內(nèi)容相同
- 創(chuàng)建遠(yuǎn)程分支
git push origin new_name
- 關(guān)聯(lián)遠(yuǎn)程分支
git branch --set-upstream-to origin/new_name
或者
git branch --set-upstream-to origin/new_name new_name
origin/new_name:遠(yuǎn)程分支 new_name:本地分支
創(chuàng)建遠(yuǎn)程分支
- 如果只有本地分支炒刁,沒(méi)有遠(yuǎn)程分支
git push --set-upstream origin new_name
本地分支為new_name,遠(yuǎn)端自動(dòng)創(chuàng)建分支new_name誊稚,并且會(huì)自動(dòng)和本地分支關(guān)聯(lián)翔始。
上面的命令其實(shí)就相當(dāng)于以下兩個(gè)命令
git push origin new_name
git branch --set-upstream-to origin/new_name
- 假設(shè)本地你能看到有遠(yuǎn)程分支罗心,想創(chuàng)建本地分支與之關(guān)聯(lián)
git checkout --track origin/branch_name
解決添加忽略失敗
當(dāng)你把文件已經(jīng)提交到git管理之后,你才把文件加入到忽略之中城瞎,這個(gè)時(shí)候忽略將不生效渤闷,解決辦法,在發(fā)生問(wèn)題的目錄下執(zhí)行以下命令即可:
git rm -r --cached .
git add .
git commit -m 'update .gitignore'
后續(xù)
如果大家喜歡這篇文章脖镀,歡迎點(diǎn)贊飒箭;如果想看更多 Git 方面的技術(shù),歡迎關(guān)注蜒灰!