日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當(dāng)前位置:首頁(yè) > > 21ic電子網(wǎng)
[導(dǎo)讀]1、簡(jiǎn)介 Git 是什么? Git 是一個(gè)開(kāi)源的分布式版本控制系統(tǒng)。 什么是版本控制? 版本控制是一種記錄一個(gè)或若干文件內(nèi)容變化,以便將來(lái)查閱特定版本修訂情況的系統(tǒng)。 什么是分布式版本控制系統(tǒng)? 介紹分布式版本控制系統(tǒng)前,有必要先了解一下傳統(tǒng)的集中式版本

1、簡(jiǎn)介

Git 是什么?

Git 是一個(gè)開(kāi)源的分布式版本控制系統(tǒng)。

什么是版本控制?

版本控制是一種記錄一個(gè)或若干文件內(nèi)容變化,以便將來(lái)查閱特定版本修訂情況的系統(tǒng)。

什么是分布式版本控制系統(tǒng)?

介紹分布式版本控制系統(tǒng)前,有必要先了解一下傳統(tǒng)的集中式版本控制系統(tǒng)。
集中化的版本控制系統(tǒng),諸如 CVS,Subversion 等,都有一個(gè)單一的集中管理的服務(wù)器,保存所有文件的修訂版本,而協(xié)同工作的人們都通過(guò)客戶(hù)端連到這臺(tái)服務(wù)器,取出最新的文件或者提交更新。
這么做最顯而易見(jiàn)的缺點(diǎn)是中央服務(wù)器的單點(diǎn)故障。如果宕機(jī)一小時(shí),那么在這一小時(shí)內(nèi),誰(shuí)都無(wú)法提交更新,也就無(wú)法協(xié)同工作。要是中央服務(wù)器的磁盤(pán)發(fā)生故障,碰巧沒(méi)做備份,或者備份不夠及時(shí),就會(huì)有丟失數(shù)據(jù)的風(fēng)險(xiǎn)。最壞的情況是徹底丟失整個(gè)項(xiàng)目的所有歷史更改記錄。
Git 從入門(mén)到精通,這篇包教包會(huì)!
分布式版本控制系統(tǒng)的客戶(hù)端并不只提取最新版本的文件快照,而是把代碼倉(cāng)庫(kù)完整地鏡像下來(lái)。這么一來(lái),任何一處協(xié)同工作用的服務(wù)器發(fā)生故障,事后都可以用任何一個(gè)鏡像出來(lái)的本地倉(cāng)庫(kù)恢復(fù)。因?yàn)槊恳淮蔚奶崛〔僮?,?shí)際上都是一次對(duì)代碼倉(cāng)庫(kù)的完整備份。
Git 從入門(mén)到精通,這篇包教包會(huì)!

2、為什么使用 Git?

Git 是分布式的。這是 Git 和其它非分布式的版本控制系統(tǒng),例如 svn,cvs 等,最核心的區(qū)別。分布式帶來(lái)以下好處:
工作時(shí)不需要聯(lián)網(wǎng)
首先,分布式版本控制系統(tǒng)根本沒(méi)有 “中央服務(wù)器”,每個(gè)人的電腦上都是一個(gè)完整的版本庫(kù),這樣,你工作的時(shí)候,就不需要聯(lián)網(wǎng)了,因?yàn)榘姹編?kù)就在你自己的電腦上。既然每個(gè)人電腦上都有一個(gè)完整的版本庫(kù),那多個(gè)人如何協(xié)作呢?比方說(shuō)你在自己電腦上改了文件 A,你的同事也在他的電腦上改了文件 A,這時(shí),你們倆之間只需把各自的修改推送給對(duì)方,就可以互相看到對(duì)方的修改了。
更加安全
集中式版本控制系統(tǒng),一旦中央服務(wù)器出了問(wèn)題,所有人都無(wú)法工作。
分布式版本控制系統(tǒng),每個(gè)人電腦中都有完整的版本庫(kù),所以某人的機(jī)器掛了,并不影響其它人。

3、Git 安裝

Debian/Ubuntu 環(huán)境安裝
如果你使用的系統(tǒng)是 Debian/Ubuntu , 安裝命令為:
   
$ apt-get install libcurl4-gnutls-dev libexpat1-dev gettext \
> libz-dev libssl-dev
$ apt-get install git-core
$ git --version
git version 1.8.1.2
Centos/RedHat 環(huán)境安裝
如果你使用的系統(tǒng)是 Centos/RedHat ,安裝命令為:
   
$ yum install curl-devel expat-devel gettext-devel \
> openssl-devel zlib-devel
$ yum -y install git-core
$ git --version
git version 1.7.1
Windows 環(huán)境安裝
在 Git 官方下載地址下載 exe 安裝包。按照安裝向?qū)О惭b即可。
建議安裝 Git Bash 這個(gè) git 的命令行工具。
Mac 環(huán)境安裝
在 Git 官方下載地址下載 mac 安裝包。按照安裝向?qū)О惭b即可。

4、Git配置

Git 自帶一個(gè)  git config 的工具來(lái)幫助設(shè)置控制 Git 外觀和行為的配置變量。這些變量存儲(chǔ)在三個(gè)不同的位置:
  • /etc/gitconfig  文件: 包含系統(tǒng)上每一個(gè)用戶(hù)及他們倉(cāng)庫(kù)的通用配置。如果使用帶有  --system  選項(xiàng)的  git config  時(shí),它會(huì)從此文件讀寫(xiě)配置變量。
  • \~/.gitconfig  或  \~/.config/git/config  文件:只針對(duì)當(dāng)前用戶(hù)。可以傳遞  --global  選項(xiàng)讓 Git 讀寫(xiě)此文件。
  • 當(dāng)前使用倉(cāng)庫(kù)的 Git 目錄中的  config  文件(就是  .git/config ):針對(duì)該倉(cāng)庫(kù)。
每一個(gè)級(jí)別覆蓋上一級(jí)別的配置,所以  .git/config 的配置變量會(huì)覆蓋  /etc/gitconfig 中的配置變量。
在 Windows 系統(tǒng)中,Git 會(huì)查找  $HOME 目錄下(一般情況下是  C:\Users\$USER)的  .gitconfig 文件。Git 同樣也會(huì)尋找  /etc/gitconfig 文件,但只限于 MSys 的根目錄下,即安裝 Git 時(shí)所選的目標(biāo)位置。

5、用戶(hù)信息

當(dāng)安裝完 Git 應(yīng)該做的第一件事就是設(shè)置你的用戶(hù)名稱(chēng)與郵件地址。這樣做很重要,因?yàn)槊恳粋€(gè) Git 的提交都會(huì)使用這些信息,并且它會(huì)寫(xiě)入到你的每一次提交中,不可更改:
   
$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com
再次強(qiáng)調(diào),如果使用了  --global 選項(xiàng),那么該命令只需要運(yùn)行一次,因?yàn)橹鬅o(wú)論你在該系統(tǒng)上做任何事情, Git 都會(huì)使用那些信息。當(dāng)你想針對(duì)特定項(xiàng)目使用不同的用戶(hù)名稱(chēng)與郵件地址時(shí),可以在那個(gè)項(xiàng)目目錄下運(yùn)行沒(méi)有  --global 選項(xiàng)的命令來(lái)配置。
很多 GUI 工具都會(huì)在第一次運(yùn)行時(shí)幫助你配置這些信息。

.gitignore

.gitignore 文件可能從字面含義也不難猜出:這個(gè)文件里配置的文件或目錄,會(huì)自動(dòng)被 git 所忽略,不納入版本控制。
在日常開(kāi)發(fā)中,我們的項(xiàng)目經(jīng)常會(huì)產(chǎn)生一些臨時(shí)文件,如編譯 Java 產(chǎn)生的  *.class 文件,又或是 IDE 自動(dòng)生成的隱藏目錄(Intellij 的  .idea 目錄、Eclipse 的  .settings 目錄等)等等。這些文件或目錄實(shí)在沒(méi)必要納入版本管理。在這種場(chǎng)景下,你就需要用到  .gitignore 配置來(lái)過(guò)濾這些文件或目錄。
配置的規(guī)則很簡(jiǎn)單,也沒(méi)什么可說(shuō)的,看幾個(gè)例子,自然就明白了。
這里推薦一下 Github 的開(kāi)源項(xiàng)目:https://github.com/github/gitignore
在這里,你可以找到很多常用的模板,如:Java、Nodejs、C++ 的  .gitignore 模板等等。

6、Git原理

個(gè)人認(rèn)為,對(duì)于 Git 這個(gè)版本工具,再不了解原理的情況下,直接去學(xué)習(xí)命令行,可能會(huì)一頭霧水。所以,本文特意將原理放在命令使用章節(jié)之前講解。

版本庫(kù)

當(dāng)你一個(gè)項(xiàng)目到本地或創(chuàng)建一個(gè) git 項(xiàng)目,項(xiàng)目目錄下會(huì)有一個(gè)隱藏的  .git  子目錄。這個(gè)目錄是 git 用來(lái)跟蹤管理版本庫(kù)的,千萬(wàn)不要手動(dòng)修改。

哈希值

Git 中所有數(shù)據(jù)在存儲(chǔ)前都計(jì)算校驗(yàn)和,然后以校驗(yàn)和來(lái)引用。這意味著不可能在 Git 不知情時(shí)更改任何文件內(nèi)容或目錄內(nèi)容。這個(gè)功能建構(gòu)在 Git 底層,是構(gòu)成 Git 哲學(xué)不可或缺的部分。若你在傳送過(guò)程中丟失信息或損壞文件,Git 就能發(fā)現(xiàn)。
Git 用以計(jì)算校驗(yàn)和的機(jī)制叫做 SHA-1 散列(hash,哈希)。這是一個(gè)由 40 個(gè)十六進(jìn)制字符(0-9 和 a-f)組成字符串,基于 Git 中文件的內(nèi)容或目錄結(jié)構(gòu)計(jì)算出來(lái)。SHA-1 哈??雌饋?lái)是這樣:
   
24b9da6552252987aa493b52f8696cd6d3b00373
Git 中使用這種哈希值的情況很多,你將經(jīng)常看到這種哈希值。實(shí)際上,Git 數(shù)據(jù)庫(kù)中保存的信息都是以文件內(nèi)容的哈希值來(lái)索引,而不是文件名。

文件狀態(tài)

在 GIt 中,你的文件可能會(huì)處于三種狀態(tài)之一:
  • 已修改(modified) - 已修改表示修改了文件,但還沒(méi)保存到數(shù)據(jù)庫(kù)中。
  • 已暫存(staged) - 已暫存表示對(duì)一個(gè)已修改文件的當(dāng)前版本做了標(biāo)記,使之包含在下次提交的快照中。
  • 已提交(committed) - 已提交表示數(shù)據(jù)已經(jīng)安全的保存在本地?cái)?shù)據(jù)庫(kù)中。

工作區(qū)域

與文件狀態(tài)對(duì)應(yīng)的,不同狀態(tài)的文件在 Git 中處于不同的工作區(qū)域。
  • 工作區(qū)(working) - 當(dāng)你  git clone  一個(gè)項(xiàng)目到本地,相當(dāng)于在本地克隆了項(xiàng)目的一個(gè)副本。工作區(qū)是對(duì)項(xiàng)目的某個(gè)版本獨(dú)立提取出來(lái)的內(nèi)容。這些從 Git 倉(cāng)庫(kù)的壓縮數(shù)據(jù)庫(kù)中提取出來(lái)的文件,放在磁盤(pán)上供你使用或修改。
  • 暫存區(qū)(staging) - 暫存區(qū)是一個(gè)文件,保存了下次將提交的文件列表信息,一般在 Git 倉(cāng)庫(kù)目錄中。有時(shí)候也被稱(chēng)作 `‘索引’',不過(guò)一般說(shuō)法還是叫暫存區(qū)。
  • 本地倉(cāng)庫(kù)(local) - 提交更新,找到暫存區(qū)域的文件,將快照永久性存儲(chǔ)到 Git 本地倉(cāng)庫(kù)。
  • 遠(yuǎn)程倉(cāng)庫(kù)(remote) - 以上幾個(gè)工作區(qū)都是在本地。為了讓別人可以看到你的修改,你需要將你的更新推送到遠(yuǎn)程倉(cāng)庫(kù)。同理,如果你想同步別人的修改,你需要從遠(yuǎn)程倉(cāng)庫(kù)拉取更新。
Git 從入門(mén)到精通,這篇包教包會(huì)!

7、Git命令

國(guó)外網(wǎng)友制作了一張 Git Cheat Sheet,總結(jié)很精煉,各位不妨收藏一下。
本節(jié)選擇性介紹 git 中比較常用的命令行場(chǎng)景。
Git 從入門(mén)到精通,這篇包教包會(huì)!

創(chuàng)建倉(cāng)庫(kù)

克隆一個(gè)已創(chuàng)建的倉(cāng)庫(kù):
   
# 通過(guò) SSH
$ git clone ssh://user@domain.com/repo.git

#通過(guò) HTTP
$ git clone http://domain.com/user/repo.git
創(chuàng)建一個(gè)新的本地倉(cāng)庫(kù):
   
$ git init

添加修改

添加修改到暫存區(qū):
   
# 把指定文件添加到暫存區(qū)
$ git add xxx

# 把當(dāng)前所有修改添加到暫存區(qū)
$ git add .

# 把所有修改添加到暫存區(qū)
$ git add -A
提交修改到本地倉(cāng)庫(kù):
   
# 提交本地的所有修改
$ git commit -a

# 提交之前已標(biāo)記的變化
$ git commit

# 附加消息提交
$ git commit -m 'commit message'

儲(chǔ)藏

有時(shí),我們需要在同一個(gè)項(xiàng)目的不同分支上工作。當(dāng)需要切換分支時(shí),偏偏本地的工作還沒(méi)有完成,此時(shí),提交修改顯得不嚴(yán)謹(jǐn),但是不提交代碼又無(wú)法切換分支。這時(shí),你可以使用  git stash 將本地的修改內(nèi)容作為草稿儲(chǔ)藏起來(lái)。
官方稱(chēng)之為儲(chǔ)藏,但我個(gè)人更喜歡稱(chēng)之為存草稿。
   
# 1. 將修改作為當(dāng)前分支的草稿保存
$ git stash

# 2. 查看草稿列表
$ git stash list
stash@{0}: WIP on master: 6fae349 :memo: Writing docs.

# 3.1 刪除草稿
$ git stash drop stash@{0}

# 3.2 讀取草稿
$ git stash apply stash@{0}

撤銷(xiāo)修改

撤銷(xiāo)本地修改:
   
# 移除緩存區(qū)的所有文件(i.e. 撤銷(xiāo)上次git add)
$ git reset HEAD

# 將HEAD重置到上一次提交的版本,并將之后的修改標(biāo)記為未添加到緩存區(qū)的修改
$ git reset <commit>

# 將HEAD重置到上一次提交的版本,并保留未提交的本地修改
$ git reset --keep <commit>

# 放棄工作目錄下的所有修改
$ git reset --hard HEAD

# 將HEAD重置到指定的版本,并拋棄該版本之后的所有修改
$ git reset --hard <commit-hash>

# 用遠(yuǎn)端分支強(qiáng)制覆蓋本地分支
$ git reset --hard <remote/branch> e.g., upstream/master, origin/my-feature

# 放棄某個(gè)文件的所有本地修改
$ git checkout HEAD <file>
刪除添加 .gitignore文件前錯(cuò)誤提交的文件:
   
$ git rm -r --cached .
$ git add .
$ git commit -m "remove xyz file"
撤銷(xiāo)遠(yuǎn)程修改(創(chuàng)建一個(gè)新的提交,并回滾到指定版本):
   
$ git revert <commit-hash>
徹底刪除指定版本:
   
# 執(zhí)行下面命令后,commit-hash 提交后的記錄都會(huì)被徹底刪除,使用需謹(jǐn)慎
$ git reset --hard <commit-hash>
$ git push -f

更新與推送

更新:
   
# 下載遠(yuǎn)程端版本,但不合并到HEAD中
$ git fetch <remote>

# 將遠(yuǎn)程端版本合并到本地版本中
$ git pull origin master

# 以rebase方式將遠(yuǎn)端分支與本地合并
$ git pull --rebase <remote> <branch>
推送:
   
# 將本地版本推送到遠(yuǎn)程端
$ git push remote <remote> <branch>

# 刪除遠(yuǎn)程端分支
$ git push <remote> :<branch> (since Git v1.5.0)
$ git push <remote> --delete <branch> (since Git v1.7.0)

# 發(fā)布標(biāo)簽
$ git push --tags

查看信息

顯示工作路徑下已修改的文件:
   
$ git status
顯示與上次提交版本文件的不同:
   
$ git diff
顯示提交歷史:
   
# 從最新提交開(kāi)始,顯示所有的提交記錄(顯示hash, 作者信息,提交的標(biāo)題和時(shí)間)
$ git log

# 顯示某個(gè)用戶(hù)的所有提交
$ git log --author="username"

# 顯示某個(gè)文件的所有修改
$ git log -p <file>
顯示搜索內(nèi)容:
   
# 從當(dāng)前目錄的所有文件中查找文本內(nèi)容
$ git grep "Hello"

# 在某一版本中搜索文本
$ git grep "Hello" v2.5

分支

增刪查分支:
   
# 列出所有的分支
$ git branch

# 列出所有的遠(yuǎn)端分支
$ git branch -r

# 基于當(dāng)前分支創(chuàng)建新分支
$ git branch <new-branch>

# 基于遠(yuǎn)程分支創(chuàng)建新的可追溯的分支
$ git branch --track <new-branch> <remote-branch>

# 刪除本地分支
$ git branch -d <branch>

# 強(qiáng)制刪除本地分支,將會(huì)丟失未合并的修改
$ git branch -D <branch>
切換分支:
   
# 切換分支
$ git checkout <branch>

# 創(chuàng)建并切換到新分支
$ git checkout -b <branch>

標(biāo)簽

   
# 給當(dāng)前版本打標(biāo)簽
$ git tag <tag-name>

# 給當(dāng)前版本打標(biāo)簽并附加消息
$ git tag -a <tag-name>

合并與重置

merge 與 rebase 雖然是 git 常用功能,但是強(qiáng)烈建議不要使用 git 命令來(lái)完成這項(xiàng)工作。
因?yàn)槿绻霈F(xiàn)代碼沖突,在沒(méi)有代碼比對(duì)工具的情況下,實(shí)在太艱難了。
你可以考慮使用各種 Git GUI 工具。
合并:
   
# 將分支合并到當(dāng)前HEAD中
$ git merge <branch>
重置:
   
# 將當(dāng)前HEAD版本重置到分支中,請(qǐng)勿重置已發(fā)布的提交
$ git rebase <branch>

Github

Github 作為最著名的代碼開(kāi)源協(xié)作社區(qū),在程序員圈想必?zé)o人不知,無(wú)人不曉。
這里不贅述 Github 的用法,確實(shí)有不會(huì)用的新手同學(xué),可以參考官方教程:https://guides.github.com/

clone 方式

Git 支持三種協(xié)議:HTTPS / SSH / GIT
而 Github 上支持 HTTPS 和 SSH。
HTTPS 這種方式要求你每次 push 時(shí)都要輸入用戶(hù)名、密碼,有些繁瑣。
而 SSH 要求你本地生成證書(shū),然后在你的 Github 賬戶(hù)中注冊(cè)。第一次配置麻煩是麻煩了點(diǎn),但是以后就免去了每次 push 需要輸入用戶(hù)名、密碼的繁瑣。
Git 從入門(mén)到精通,這篇包教包會(huì)!
以下介紹以下,如何生成證書(shū),以及在 Github 中注冊(cè)。

生成 SSH 公鑰

如前所述,許多 Git 服務(wù)器都使用 SSH 公鑰進(jìn)行認(rèn)證。為了向 Git 服務(wù)器提供 SSH 公鑰,如果某系統(tǒng)用戶(hù)尚未擁有密鑰,必須事先為其生成一份。這個(gè)過(guò)程在所有操作系統(tǒng)上都是相似的。首先,你需要確認(rèn)自己是否已經(jīng)擁有密鑰。默認(rèn)情況下,用戶(hù)的 SSH 密鑰存儲(chǔ)在其  \~/.ssh 目錄下。進(jìn)入該目錄并列出其中內(nèi)容,你便可以快速確認(rèn)自己是否已擁有密鑰:
   
$ cd ~/.ssh
$ ls
authorized_keys2 id_dsa known_hosts
config id_dsa.pub
我們需要尋找一對(duì)以  id_dsa 或  id_rsa 命名的文件,其中一個(gè)帶有  .pub 擴(kuò)展名。  .pub 文件是你的公鑰,另一個(gè)則是私鑰。如果找不到這樣的文件(或者根本沒(méi)有  .ssh 目錄),你可以通過(guò)運(yùn)行  ssh-keygen 程序來(lái)創(chuàng)建它們。在 Linux/Mac 系統(tǒng)中, ssh-keygen 隨 SSH 軟件包提供;在 Windows 上,該程序包含于 MSysGit 軟件包中。
   
$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/schacon/.ssh/id_rsa):
Created directory '/home/schacon/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/schacon/.ssh/id_rsa.
Your public key has been saved in /home/schacon/.ssh/id_rsa.pub.
The key fingerprint is:
d0:82:24:8e:d7:f1:bb:9b:33:53:96:93:49:da:9b:e3 schacon@mylaptop.local
首先  ssh-keygen 會(huì)確認(rèn)密鑰的存儲(chǔ)位置(默認(rèn)是  .ssh/id_rsa),然后它會(huì)要求你輸入兩次密鑰口令。如果你不想在使用密鑰時(shí)輸入口令,將其留空即可。
現(xiàn)在,進(jìn)行了上述操作的用戶(hù)需要將各自的公鑰發(fā)送給任意一個(gè) Git 服務(wù)器管理員(假設(shè)服務(wù)器正在使用基于公鑰的 SSH 驗(yàn)證設(shè)置)。他們所要做的就是復(fù)制各自的  .pub 文件內(nèi)容,并將其通過(guò)郵件發(fā)送。公鑰看起來(lái)是這樣的:
   
$ cat ~/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAklOUpkDHrfHY17SbrmTIpNLTGK9Tjom/BWDSU
GPl+nafzlHDTYW7hdI4yZ5ew18JH4JW9jbhUFrviQzM7xlELEVf4h9lFX5QVkbPppSwg0cda3
Pbv7kOdJ/MTyBlWXFCR+HAo3FXRitBqxiX1nKhXpHAZsMciLq8V6RjsNAQwdsdMFvSlVK/7XA
t3FaoJoAsncM1Q9x5+3V0Ww68/eIFmb1zuUFljQJKprrX88XypNDvjYNby6vw/Pb0rwert/En
mZ+AW4OZPnTPI89ZPmVMLuayrD2cE86Z/il8b+gw3r3+1nKatmIkjn2so1d01QraTlMqVSsbx
NrRFi9wrf+M7Q== schacon@mylaptop.local
在你的 Github 賬戶(hù)中,依次點(diǎn)擊  Settings >  SSH and GPG keys >  New SSH key
然后,將上面生成的公鑰內(nèi)容粘貼到  Key 編輯框并保存。至此大功告成。
后面,你在克隆你的 Github 項(xiàng)目時(shí)使用 SSH 方式即可。
如果覺(jué)得我的講解還不夠細(xì)致,可以參考:https://help.github.com/articles/adding-a-new-ssh-key-to-your-github-account/

8、最佳實(shí)踐 Git Flow

詳細(xì)內(nèi)容,可以參考這篇文章:Git 在團(tuán)隊(duì)中的最佳實(shí)踐 -- 如何正確使用 Git Flow
Git 在實(shí)際開(kāi)發(fā)中的最佳實(shí)踐策略 Git Flow 可以歸納為以下:
  • master 分支 - 也就是我們經(jīng)常使用的主線分支,這個(gè)分支是最近發(fā)布到生產(chǎn)環(huán)境的代碼,這個(gè)分支只能從其他分支合并,不能在這個(gè)分支直接修改。
  • develop 分支 - 這個(gè)分支是我們的主開(kāi)發(fā)分支,包含所有要發(fā)布到下一個(gè) release 的代碼,這個(gè)分支主要是從其他分支合并代碼過(guò)來(lái),比如 feature 分支。
  • feature 分支 - 這個(gè)分支主要是用來(lái)開(kāi)發(fā)一個(gè)新的功能,一旦開(kāi)發(fā)完成,我們合并回 develop 分支進(jìn)入下一個(gè) release。
  • release 分支 - 當(dāng)你需要一個(gè)發(fā)布一個(gè)新 release 的時(shí)候,我們基于 Develop 分支創(chuàng)建一個(gè) release 分支,完成 release 后,我們合并到 master 和 develop 分支。
  • hotfix 分支 - 當(dāng)我們?cè)?master 發(fā)現(xiàn)新的 Bug 時(shí)候,我們需要?jiǎng)?chuàng)建一個(gè) hotfix, 完成 hotfix 后,我們合并回 master 和 develop 分支,所以 hotfix 的改動(dòng)會(huì)進(jìn)入下一個(gè) release。

9、Git常見(jiàn)問(wèn)題

編輯提交 (editting commits)

我剛才提交了什么

如果你用  git commit -a 提交了一次變化 (changes),而你又不確定到底這次提交了哪些內(nèi)容。你就可以用下面的命令顯示當(dāng)前 HEAD上的最近一次的提交 (commit):
   
(master)$ git show
或者
   
$ git log -n1 -p

我的提交信息 (commit message) 寫(xiě)錯(cuò)了

如果你的提交信息 (commit message) 寫(xiě)錯(cuò)了且這次提交 (commit) 還沒(méi)有推(push), 你可以通過(guò)下面的方法來(lái)修改提交信息(commit message):
   
$ git commit --amend
這會(huì)打開(kāi)你的默認(rèn)編輯器, 在這里你可以編輯信息. 另一方面, 你也可以用一條命令一次完成:
   
$ git commit --amend -m 'xxxxxxx'
如果你已經(jīng)推 (push) 了這次提交 (commit), 你可以修改這次提交(commit) 然后強(qiáng)推(force push), 但是不推薦這么做。

我提交 (commit) 里的用戶(hù)名和郵箱不對(duì)

如果這只是單個(gè)提交 (commit),修改它:
   
$ git commit --amend --author "New Authorname <authoremail@mydomain.com>"
如果你需要修改所有歷史, 參考'git filter-branch'的指南頁(yè).

我想從一個(gè)提交 (commit) 里移除一個(gè)文件

通過(guò)下面的方法,從一個(gè)提交 (commit) 里移除一個(gè)文件:
   
$ git checkout HEAD^ myfile
$ git add -A
$ git commit --amend
這將非常有用,當(dāng)你有一個(gè)開(kāi)放的補(bǔ)丁 (open patch),你往上面提交了一個(gè)不必要的文件,你需要強(qiáng)推(force push) 去更新這個(gè)遠(yuǎn)程補(bǔ)丁。

我想刪除我的的最后一次提交 (commit)

如果你需要?jiǎng)h除推了的提交 (pushed commits),你可以使用下面的方法??墒?,這會(huì)不可逆的改變你的歷史,也會(huì)搞亂那些已經(jīng)從該倉(cāng)庫(kù)拉取(pulled) 了的人的歷史。簡(jiǎn)而言之,如果你不是很確定,千萬(wàn)不要這么做。
   
$ git reset HEAD^ --hard
$ git push -f [remote] [branch]
如果你還沒(méi)有推到遠(yuǎn)程, 把 Git 重置 (reset) 到你最后一次提交前的狀態(tài)就可以了(同時(shí)保存暫存的變化):
   
(my-branch*)$ git reset --soft HEAD@{1}
這只能在沒(méi)有推送之前有用. 如果你已經(jīng)推了, 唯一安全能做的是  git revert SHAofBadCommit, 那會(huì)創(chuàng)建一個(gè)新的提交 (commit) 用于撤消前一個(gè)提交的所有變化(changes);或者, 如果你推的這個(gè)分支是 rebase-safe 的 (例如:其它開(kāi)發(fā)者不會(huì)從這個(gè)分支拉), 只需要使用  git push -f;更多, 請(qǐng)參考 the above section。

刪除任意提交 (commit)

同樣的警告:不到萬(wàn)不得已的時(shí)候不要這么做.
   
$ git rebase --onto SHA1_OF_BAD_COMMIT^ SHA1_OF_BAD_COMMIT
$ git push -f [remote] [branch]
或者做一個(gè) 交互式 rebase 刪除那些你想要?jiǎng)h除的提交 (commit) 里所對(duì)應(yīng)的行。

我嘗試推一個(gè)修正后的提交 (amended commit) 到遠(yuǎn)程,但是報(bào)錯(cuò):

   
To https://github.com/yourusername/repo.git
! [rejected] mybranch -> mybranch (non-fast-forward)
error: failed to push some refs to 'https://github.com/tanay1337/webmaker.org.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
注意, rebasing(見(jiàn)下面)和修正 (amending) 會(huì)用一個(gè) 新的提交 (commit) 代替舊的, 所以如果之前你已經(jīng)往遠(yuǎn)程倉(cāng)庫(kù)上推過(guò)一次修正前的提交 (commit),那你現(xiàn)在就必須強(qiáng)推 (force push) ( -f)。注意 –  總是 確保你指明一個(gè)分支!
   
(my-branch)$ git push origin mybranch -f
一般來(lái)說(shuō),  要避免強(qiáng)推. 最好是創(chuàng)建和推 (push) 一個(gè)新的提交(commit),而不是強(qiáng)推一個(gè)修正后的提交。后者會(huì)使那些與該分支或該分支的子分支工作的開(kāi)發(fā)者,在源歷史中產(chǎn)生沖突。

我意外的做了一次硬重置 (hard reset),我想找回我的內(nèi)容

如果你意外的做了  git reset --hard, 你通常能找回你的提交 (commit), 因?yàn)?Git 對(duì)每件事都會(huì)有日志,且都會(huì)保存幾天。
   
(master)$ git reflog
你將會(huì)看到一個(gè)你過(guò)去提交 (commit) 的列表, 和一個(gè)重置的提交。選擇你想要回到的提交 (commit) 的 SHA,再重置一次:
   
(master)$ git reset --hard SHA1234
這樣就完成了。

暫存 (Staging)

我需要把暫存的內(nèi)容添加到上一次的提交 (commit)

   
(my-branch*)$ git commit --amend

我想要暫存一個(gè)新文件的一部分,而不是這個(gè)文件的全部

一般來(lái)說(shuō), 如果你想暫存一個(gè)文件的一部分, 你可這樣做:
   
$ git add --patch filename.x
-p 簡(jiǎn)寫(xiě)。這會(huì)打開(kāi)交互模式, 你將能夠用  s 選項(xiàng)來(lái)分隔提交 (commit);然而, 如果這個(gè)文件是新的, 會(huì)沒(méi)有這個(gè)選擇, 添加一個(gè)新文件時(shí), 這樣做:
   
$ git add -N filename.x
然后, 你需要用  e 選項(xiàng)來(lái)手動(dòng)選擇需要添加的行,執(zhí)行  git diff --cached 將會(huì)顯示哪些行暫存了哪些行只是保存在本地了。

我想把在一個(gè)文件里的變化 (changes) 加到兩個(gè)提交 (commit) 里

git add 會(huì)把整個(gè)文件加入到一個(gè)提交.  git add -p 允許交互式的選擇你想要提交的部分.

我想把暫存的內(nèi)容變成未暫存,把未暫存的內(nèi)容暫存起來(lái)

這個(gè)有點(diǎn)困難, 我能想到的最好的方法是先 stash 未暫存的內(nèi)容, 然后重置 (reset),再 pop 第一步 stashed 的內(nèi)容, 最后再 add 它們。
   
$ git stash -k
$ git reset --hard
$ git stash pop
$ git add -A

未暫存 (Unstaged) 的內(nèi)容

我想把未暫存的內(nèi)容移動(dòng)到一個(gè)新分支

   
$ git checkout -b my-branch

我想把未暫存的內(nèi)容移動(dòng)到另一個(gè)已存在的分支

   
$ git stash
$ git checkout my-branch
$ git stash pop

我想丟棄本地未提交的變化 (uncommitted changes)

如果你只是想重置源 (origin) 和你本地 (local) 之間的一些提交(commit),你可以:
   
## one commit
(my-branch)$ git reset --hard HEAD^
## two commits
(my-branch)$ git reset --hard HEAD^^
## four commits
(my-branch)$ git reset --hard HEAD~4
## or
(master)$ git checkout -f
重置某個(gè)特殊的文件, 你可以用文件名做為參數(shù):
   
$ git reset filename

我想丟棄某些未暫存的內(nèi)容

如果你想丟棄工作拷貝中的一部分內(nèi)容,而不是全部。
簽出 (checkout) 不需要的內(nèi)容,保留需要的。
   
$ git checkout -p
## Answer y to all of the snippets you want to drop
另外一個(gè)方法是使用  stash, Stash 所有要保留下的內(nèi)容, 重置工作拷貝, 重新應(yīng)用保留的部分。
   
$ git stash -p
## Select all of the snippets you want to save
$ git reset --hard
$ git stash pop
或者, stash 你不需要的部分, 然后 stash drop。
   
$ git stash -p
## Select all of the snippets you don't want to save
$ git stash drop

分支 (Branches)

我從錯(cuò)誤的分支拉取了內(nèi)容,或把內(nèi)容拉取到了錯(cuò)誤的分支

這是另外一種使用  git reflog 情況,找到在這次錯(cuò)誤拉 (pull) 之前 HEAD 的指向。
   
(master)$ git reflog
ab7555f HEAD@{0}: pull origin wrong-branch: Fast-forward
c5bc55a HEAD@{1}: checkout: checkout message goes here
重置分支到你所需的提交 (desired commit):
   
$ git reset --hard c5bc55a
完成。

我想扔掉本地的提交 (commit),以便我的分支與遠(yuǎn)程的保持一致

先確認(rèn)你沒(méi)有推 (push) 你的內(nèi)容到遠(yuǎn)程。
git status 會(huì)顯示你領(lǐng)先 (ahead) 源(origin)多少個(gè)提交:
   
(my-branch)$ git status
## On branch my-branch
## Your branch is ahead of 'origin/my-branch' by 2 commits.
## (use "git push" to publish your local commits)
#
一種方法是:
   
(master)$ git reset --hard origin/my-branch

我需要提交到一個(gè)新分支,但錯(cuò)誤的提交到了 master

在 master 下創(chuàng)建一個(gè)新分支,不切換到新分支, 仍在 master 下:
   
(master)$ git branch my-branch
把 master 分支重置到前一個(gè)提交:
   
(master)$ git reset --hard HEAD^
HEAD^ 是  HEAD^1 的簡(jiǎn)寫(xiě),你可以通過(guò)指定要設(shè)置的 HEAD來(lái)進(jìn)一步重置。
或者, 如果你不想使用  HEAD^, 找到你想重置到的提交 (commit) 的 hash( git log 能夠完成), 然后重置到這個(gè) hash。使用 git push 同步內(nèi)容到遠(yuǎn)程。
例如, master 分支想重置到的提交的 hash 為 a13b85e:
   
(master)$ git reset --hard a13b85e
HEAD is now at a13b85e
簽出 (checkout) 剛才新建的分支繼續(xù)工作:
   
(master)$ git checkout my-branch

我想保留來(lái)自另外一個(gè) ref-ish 的整個(gè)文件

假設(shè)你正在做一個(gè)原型方案 (原文為 working spike (see note)), 有成百的內(nèi)容,每個(gè)都工作得很好。現(xiàn)在, 你提交到了一個(gè)分支,保存工作內(nèi)容:
   
(solution)$ git add -A && git commit -m "Adding all changes from this spike into one big commit."
當(dāng)你想要把它放到一個(gè)分支里 (可能是 feature, 或者  develop), 你關(guān)心是保持整個(gè)文件的完整,你想要一個(gè)大的提交分隔成比較小。
假設(shè)你有:
  • 分支  solution, 擁有原型方案, 領(lǐng)先  develop 分支。
  • 分支  develop, 在這里你應(yīng)用原型方案的一些內(nèi)容。
我去可以通過(guò)把內(nèi)容拿到你的分支里,來(lái)解決這個(gè)問(wèn)題:
   
(develop)$ git checkout solution -- file1.txt
這會(huì)把這個(gè)文件內(nèi)容從分支  solution 拿到分支  develop 里來(lái):
   
## On branch develop
## Your branch is up-to-date with 'origin/develop'.
## Changes to be committed:
## (use "git reset HEAD <file>..." to unstage)
#
## modified: file1.txt
然后, 正常提交。
Note: Spike solutions are made to analyze or solve the problem. These solutions are used for estimation and discarded once everyone gets clear visualization of the problem. ~ Wikipedia.

我把幾個(gè)提交 (commit) 提交到了同一個(gè)分支,而這些提交應(yīng)該分布在不同的分支里

假設(shè)你有一個(gè) master分支, 執(zhí)行 git log, 你看到你做過(guò)兩次提交:
   
(master)$ git log

commit e3851e817c451cc36f2e6f3049db528415e3c114
Author: Alex Lee <alexlee@example.com>
Date: Tue Jul 22 15:39:27 2014 -0400

Bug #21 - Added CSRF protection

commit 5ea51731d150f7ddc4a365437931cd8be3bf3131
Author: Alex Lee <alexlee@example.com>
Date: Tue Jul 22 15:39:12 2014 -0400

Bug #14 - Fixed spacing on title

commit a13b85e984171c6e2a1729bb061994525f626d14
Author: Aki Rose <akirose@example.com>
Date: Tue Jul 21 01:12:48 2014 -0400

First commit
讓我們用提交 hash(commit hash) 標(biāo)記 bug ( e3851e8 for #21,  5ea5173 for #14).
首先, 我們把 master分支重置到正確的提交 ( a13b85e):
   
(master)$ git reset --hard a13b85e
HEAD is now at a13b85e
現(xiàn)在, 我們對(duì) bug #21 創(chuàng)建一個(gè)新的分支:
   
(master)$ git checkout -b 21
(21)$
接著, 我們用  cherry-pick 把對(duì) bug #21 的提交放入當(dāng)前分支。這意味著我們將應(yīng)用 (apply) 這個(gè)提交(commit),僅僅這一個(gè)提交(commit),直接在 HEAD 上面。
   
(21)$ git cherry-pick e3851e8
這時(shí)候, 這里可能會(huì)產(chǎn)生沖突, 參見(jiàn)交互式 rebasing 章  沖突節(jié) 解決沖突.
再者, 我們?yōu)?bug #14 創(chuàng)建一個(gè)新的分支, 也基于 master分支
   
(21)$ git checkout master
(master)$ git checkout -b 14
(14)$
最后, 為 bug #14 執(zhí)行  cherry-pick:
   
(14)$ git cherry-pick 5ea5173

我想刪除上游 (upstream) 分支被刪除了的本地分支

一旦你在 github 上面合并 (merge) 了一個(gè) pull request, 你就可以刪除你 fork 里被合并的分支。如果你不準(zhǔn)備繼續(xù)在這個(gè)分支里工作, 刪除這個(gè)分支的本地拷貝會(huì)更干凈,使你不會(huì)陷入工作分支和一堆陳舊分支的混亂之中。
   
$ git fetch -p

我不小心刪除了我的分支

如果你定期推送到遠(yuǎn)程, 多數(shù)情況下應(yīng)該是安全的,但有些時(shí)候還是可能刪除了還沒(méi)有推到遠(yuǎn)程的分支。讓我們先創(chuàng)建一個(gè)分支和一個(gè)新的文件:
   
(master)$ git checkout -b my-branch
(my-branch)$ git branch
(my-branch)$ touch foo.txt
(my-branch)$ ls
README.md foo.txt
添加文件并做一次提交
   
(my-branch)$ git add .
(my-branch)$ git commit -m 'foo.txt added'
(my-branch)$ foo.txt added
1 files changed, 1 insertions(+)
create mode 100644 foo.txt
(my-branch)$ git log

commit 4e3cd85a670ced7cc17a2b5d8d3d809ac88d5012
Author: siemiatj <siemiatj@example.com>
Date: Wed Jul 30 00:34:10 2014 +0200

foo.txt added

commit 69204cdf0acbab201619d95ad8295928e7f411d5
Author: Kate Hudson <katehudson@example.com>
Date: Tue Jul 29 13:14:46 2014 -0400

Fixes #6: Force pushing after amending commits
現(xiàn)在我們切回到主 (master) 分支,‘不小心的’刪除 my-branch分支
   
(my-branch)$ git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
(master)$ git branch -D my-branch
Deleted branch my-branch (was 4e3cd85).
(master)$ echo oh noes, deleted my branch!
oh noes, deleted my branch!
在這時(shí)候你應(yīng)該想起了 reflog, 一個(gè)升級(jí)版的日志,它存儲(chǔ)了倉(cāng)庫(kù) (repo) 里面所有動(dòng)作的歷史。
   
(master)$ git reflog
69204cd HEAD@{0}: checkout: moving from my-branch to master
4e3cd85 HEAD@{1}: commit: foo.txt added
69204cd HEAD@{2}: checkout: moving from master to my-branch
正如你所見(jiàn),我們有一個(gè)來(lái)自刪除分支的提交 hash(commit hash),接下來(lái)看看是否能恢復(fù)刪除了的分支。
   
(master)$ git checkout -b my-branch-help
Switched to a new branch 'my-branch-help'
(my-branch-help)$ git reset --hard 4e3cd85
HEAD is now at 4e3cd85 foo.txt added
(my-branch-help)$ ls
README.md foo.txt
看! 我們把刪除的文件找回來(lái)了。Git 的  reflog 在 rebasing 出錯(cuò)的時(shí)候也是同樣有用的。

我想刪除一個(gè)分支

刪除一個(gè)遠(yuǎn)程分支:
   
(master)$ git push origin --delete my-branch
你也可以:
   
(master)$ git push origin :my-branch
刪除一個(gè)本地分支:
   
(master)$ git branch -D my-branch

我想從別人正在工作的遠(yuǎn)程分支簽出 (checkout) 一個(gè)分支

首先, 從遠(yuǎn)程拉取 (fetch) 所有分支:
   
(master)$ git fetch --all
假設(shè)你想要從遠(yuǎn)程的 daves分支簽出到本地的 daves
   
(master)$ git checkout --track origin/daves
Branch daves set up to track remote branch daves from origin.
Switched to a new branch 'daves'
( --track 是  git checkout -b [branch] [remotename]/[branch] 的簡(jiǎn)寫(xiě))
這樣就得到了一個(gè) daves分支的本地拷貝, 任何推過(guò) (pushed) 的更新,遠(yuǎn)程都能看到.

Rebasing 和合并 (Merging)

我想撤銷(xiāo) rebase/merge

你可以合并 (merge) 或 rebase 了一個(gè)錯(cuò)誤的分支, 或者完成不了一個(gè)進(jìn)行中的 rebase/merge。Git 在進(jìn)行危險(xiǎn)操作的時(shí)候會(huì)把原始的 HEAD 保存在一個(gè)叫 ORIG_HEAD 的變量里, 所以要把分支恢復(fù)到 rebase/merge 前的狀態(tài)是很容易的。
   
(my-branch)$ git reset --hard ORIG_HEAD

我已經(jīng) rebase 過(guò), 但是我不想強(qiáng)推 (force push)

不幸的是,如果你想把這些變化 (changes) 反應(yīng)到遠(yuǎn)程分支上,你就必須得強(qiáng)推 (force push)。是因你快進(jìn)(Fast forward) 了提交,改變了 Git 歷史, 遠(yuǎn)程分支不會(huì)接受變化 (changes),除非強(qiáng)推(force push)。這就是許多人使用 merge 工作流, 而不是 rebasing 工作流的主要原因之一, 開(kāi)發(fā)者的強(qiáng)推(force push) 會(huì)使大的團(tuán)隊(duì)陷入麻煩。使用時(shí)需要注意,一種安全使用 rebase 的方法是,不要把你的變化 (changes) 反映到遠(yuǎn)程分支上, 而是按下面的做:
   
(master)$ git checkout my-branch
(my-branch)$ git rebase -i master
(my-branch)$ git checkout master
(master)$ git merge --ff-only my-branch
更多, 參見(jiàn) this SO thread.

我需要組合 (combine) 幾個(gè)提交(commit)

假設(shè)你的工作分支將會(huì)做對(duì)于  master 的 pull-request。一般情況下你不關(guān)心提交 (commit) 的時(shí)間戳,只想組合  所有 提交 (commit) 到一個(gè)單獨(dú)的里面, 然后重置(reset) 重提交 (recommit)。確保主(master) 分支是最新的和你的變化都已經(jīng)提交了, 然后:
   
(my-branch)$ git reset --soft master
(my-branch)$ git commit -am "New awesome feature"
如果你想要更多的控制, 想要保留時(shí)間戳, 你需要做交互式 rebase (interactive rebase):
   
(my-branch)$ git rebase -i master
如果沒(méi)有相對(duì)的其它分支, 你將不得不相對(duì)自己的 HEAD 進(jìn)行 rebase。例如:你想組合最近的兩次提交 (commit), 你將相對(duì)于 HEAD\~2 進(jìn)行 rebase, 組合最近 3 次提交 (commit), 相對(duì)于 HEAD\~3, 等等。
   
(master)$ git rebase -i HEAD~2
在你執(zhí)行了交互式 rebase 的命令 (interactive rebase command) 后, 你將在你的編輯器里看到類(lèi)似下面的內(nèi)容:
   
pick a9c8a1d Some refactoring
pick 01b2fd8 New awesome feature
pick b729ad5 fixup
pick e3851e8 another fix

## Rebase 8074d12..b729ad5 onto 8074d12
#
## 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
#
## These lines can be re-ordered; they are executed from top to bottom.
#
## If you remove a line here THAT COMMIT WILL BE LOST.
#
## However, if you remove everything, the rebase will be aborted.
#
## Note that empty commits are commented out
所有以  # 開(kāi)頭的行都是注釋, 不會(huì)影響 rebase.
然后,你可以用任何上面命令列表的命令替換  pick, 你也可以通過(guò)刪除對(duì)應(yīng)的行來(lái)刪除一個(gè)提交 (commit)。
例如, 如果你想  單獨(dú)保留最舊 (first) 的提交(commit), 組合所有剩下的到第二個(gè)里面, 你就應(yīng)該編輯第二個(gè)提交 (commit) 后面的每個(gè)提交(commit) 前的單詞為  f:
   
pick a9c8a1d Some refactoring
pick 01b2fd8 New awesome feature
f b729ad5 fixup
f e3851e8 another fix
如果你想組合這些提交 (commit)  并重命名這個(gè)提交 (commit), 你應(yīng)該在第二個(gè)提交 (commit) 旁邊添加一個(gè) r,或者更簡(jiǎn)單的用 s 替代  f:
   
pick a9c8a1d Some refactoring
pick 01b2fd8 New awesome feature
s b729ad5 fixup
s e3851e8 another fix
你可以在接下來(lái)彈出的文本提示框里重命名提交 (commit)。
   
Newer, awesomer features

## Please enter the commit message for your changes. Lines starting
## with '#' will be ignored, and an empty message aborts the commit.
## rebase in progress; onto 8074d12
## You are currently editing a commit while rebasing branch 'master' on '8074d12'.
#
## Changes to be committed:
#modified: README.md
#
如果成功了, 你應(yīng)該看到類(lèi)似下面的內(nèi)容:
   
(master)$ Successfully rebased and updated refs/heads/master.
安全合并 (merging) 策略
--no-commit 執(zhí)行合并 (merge) 但不自動(dòng)提交, 給用戶(hù)在做提交前檢查和修改的機(jī)會(huì)。  no-ff 會(huì)為特性分支 (feature branch) 的存在過(guò)留下證據(jù), 保持項(xiàng)目歷史一致。
   
(master)$ git merge --no-ff --no-commit my-branch
我需要將一個(gè)分支合并成一個(gè)提交 (commit)
   
(master)$ git merge --squash my-branch
我只想組合 (combine) 未推的提交(unpushed commit)
有時(shí)候,在將數(shù)據(jù)推向上游之前,你有幾個(gè)正在進(jìn)行的工作提交 (commit)。這時(shí)候不希望把已經(jīng)推(push) 過(guò)的組合進(jìn)來(lái),因?yàn)槠渌丝赡芤呀?jīng)有提交 (commit) 引用它們了。
   
(master)$ git rebase -i @{u}
這會(huì)產(chǎn)生一次交互式的 rebase(interactive rebase), 只會(huì)列出沒(méi)有推 (push) 的提交(commit), 在這個(gè)列表時(shí)進(jìn)行 reorder/fix/squash 都是安全的。

檢查是否分支上的所有提交 (commit) 都合并 (merge) 過(guò)了

檢查一個(gè)分支上的所有提交 (commit) 是否都已經(jīng)合并 (merge) 到了其它分支, 你應(yīng)該在這些分支的 head(或任何 commits)之間做一次 diff:
   
(master)$ git log --graph --left-right --cherry-pick --oneline HEAD...feature/120-on-scroll
這會(huì)告訴你在一個(gè)分支里有而另一個(gè)分支沒(méi)有的所有提交 (commit), 和分支之間不共享的提交(commit) 的列表。另一個(gè)做法可以是:
   
(master)$ git log master ^feature/120-on-scroll --no-merges

交互式 rebase(interactive rebase) 可能出現(xiàn)的問(wèn)題

這個(gè) rebase 編輯屏幕出現(xiàn)'noop'
如果你看到的是這樣:
   
noop
這意味著你 rebase 的分支和當(dāng)前分支在同一個(gè)提交 (commit) 上, 或者  領(lǐng)先 (ahead) 當(dāng)前分支。你可以嘗試:
  • 檢查確保主 (master) 分支沒(méi)有問(wèn)題
  • rebase  HEAD\~2 或者更早
有沖突的情況
如果你不能成功的完成 rebase, 你可能必須要解決沖突。
首先執(zhí)行  git status 找出哪些文件有沖突:
   
(my-branch)$ git status
On branch my-branch
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: README.md
在這個(gè)例子里面,  README.md 有沖突。打開(kāi)這個(gè)文件找到類(lèi)似下面的內(nèi)容:
   
<<<<<<< HEAD
some code
=========
some code
>>>>>>> new-commit
你需要解決新提交的代碼 (示例里, 從中間 ==線到 new-commit的地方) 與 HEAD 之間不一樣的地方.
有時(shí)候這些合并非常復(fù)雜,你應(yīng)該使用可視化的差異編輯器 (visual diff editor):
   
(master*)$ git mergetool -t opendiff
在你解決完所有沖突和測(cè)試過(guò)后,  git add 變化了的 (changed) 文件, 然后用 git rebase --continue 繼續(xù) rebase。
   
(my-branch)$ git add README.md
(my-branch)$ git rebase --continue
如果在解決完所有的沖突過(guò)后,得到了與提交前一樣的結(jié)果, 可以執(zhí)行 git rebase --skip
任何時(shí)候你想結(jié)束整個(gè) rebase 過(guò)程,回來(lái) rebase 前的分支狀態(tài), 你可以做:
   
(my-branch)$ git rebase --abort

雜項(xiàng) (Miscellaneous Objects)

克隆所有子模塊

   
$ git clone --recursive git://github.com/foo/bar.git
如果已經(jīng)克隆了:
   
$ git submodule update --init --recursive

刪除標(biāo)簽 (tag)

   
$ git tag -d <tag_name>
$ git push <remote> :refs/tags/<tag_name>

恢復(fù)已刪除標(biāo)簽 (tag)

如果你想恢復(fù)一個(gè)已刪除標(biāo)簽 (tag), 可以按照下面的步驟: 首先, 需要找到無(wú)法訪問(wèn)的標(biāo)簽 (unreachable tag):
   
$ git fsck --unreachable | grep tag
記下這個(gè)標(biāo)簽 (tag) 的 hash,然后用 Git 的 update-ref:
   
$ git update-ref refs/tags/<tag_name> <hash>
這時(shí)你的標(biāo)簽 (tag) 應(yīng)該已經(jīng)恢復(fù)了。

已刪除補(bǔ)丁 (patch)

如果某人在 GitHub 上給你發(fā)了一個(gè) pull request, 但是然后他刪除了他自己的原始 fork, 你將沒(méi)法克隆他們的提交 (commit) 或使用  git am。在這種情況下, 最好手動(dòng)的查看他們的提交 (commit),并把它們拷貝到一個(gè)本地新分支,然后做提交。
做完提交后, 再修改作者,參見(jiàn)變更作者。然后, 應(yīng)用變化, 再發(fā)起一個(gè)新的 pull request。

跟蹤文件 (Tracking Files)

我只想改變一個(gè)文件名字的大小寫(xiě),而不修改內(nèi)容

   
(master)$ git mv --force myfile MyFile

我想從 Git 刪除一個(gè)文件,但保留該文件

   
(master)$ git rm --cached log.txt

配置 (Configuration)

我想給一些 Git 命令添加別名 (alias)

在 OS X 和 Linux 下, 你的 Git 的配置文件儲(chǔ)存在  \~/.gitconfig。我在 [alias] 部分添加了一些快捷別名 (和一些我容易拼寫(xiě)錯(cuò)誤的),如下:
   
[alias]
a = add
amend = commit --amend
c = commit
ca = commit --amend
ci = commit -a
co = checkout
d = diff
dc = diff --changed
ds = diff --staged
f = fetch
loll = log --graph --decorate --pretty=oneline --abbrev-commit
m = merge
one = log --pretty=oneline
outstanding = rebase -i @{u}
s = status
unpushed = log @{u}
wc = whatchanged
wip = rebase -i @{u}
zap = fetch -p

我想緩存一個(gè)倉(cāng)庫(kù) (repository) 的用戶(hù)名和密碼

你可能有一個(gè)倉(cāng)庫(kù)需要授權(quán),這時(shí)你可以緩存用戶(hù)名和密碼,而不用每次推 / 拉 (push/pull) 的時(shí)候都輸入,Credential helper 能幫你。
   
$ git config --global credential.helper cache
## Set git to use the credential memory cache
   
$ git config --global credential.helper 'cache --timeout=3600'
## Set the cache to timeout after 1 hour (setting is in seconds)

我不知道我做錯(cuò)了些什么

你把事情搞砸了:你  重置(reset) 了一些東西, 或者你合并了錯(cuò)誤的分支, 亦或你強(qiáng)推了后找不到你自己的提交 (commit) 了。有些時(shí)候, 你一直都做得很好, 但你想回到以前的某個(gè)狀態(tài)。
這就是  git reflog 的目的,  reflog 記錄對(duì)分支頂端 (the tip of a branch) 的任何改變, 即使那個(gè)頂端沒(méi)有被任何分支或標(biāo)簽引用?;旧? 每次 HEAD 的改變, 一條新的記錄就會(huì)增加到 reflog。遺憾的是,這只對(duì)本地分支起作用,且它只跟蹤動(dòng)作 (例如,不會(huì)跟蹤一個(gè)沒(méi)有被記錄的文件的任何改變)。
   
(master)$ git reflog
0a2e358 HEAD@{0}: reset: moving to HEAD\~2
0254ea7 HEAD@{1}: checkout: moving from 2.2 to master
c10f740 HEAD@{2}: checkout: moving from master to 2.2
上面的 reflog 展示了從 master 分支簽出 (checkout) 到 2.2 分支,然后再簽回。那里,還有一個(gè)硬重置 (hard reset) 到一個(gè)較舊的提交。最新的動(dòng)作出現(xiàn)在最上面以  HEAD@{0}標(biāo)識(shí).
如果事實(shí)證明你不小心回移 (move back) 了提交(commit), reflog 會(huì)包含你不小心回移前 master 上指向的提交(0254ea7)。
   
$ git reset --hard 0254ea7
然后使用 git reset 就可以把 master 改回到之前的 commit,這提供了一個(gè)在歷史被意外更改情況下的安全網(wǎng)。


作者:靜默虛空
來(lái)源:https://juejin.im/post/5c8296f85188257e3941b2d4

end



免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場(chǎng),如有問(wèn)題,請(qǐng)聯(lián)系我們,謝謝!

21ic電子網(wǎng)

掃描二維碼,關(guān)注更多精彩內(nèi)容

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專(zhuān)欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除( 郵箱:macysun@21ic.com )。
關(guān)閉