關(guān)于Git伍掀,你真的學(xué)會了嗎掰茶?

“鋒哥,Git有什么可說的蜜笤,不就是git add添加濒蒋,git commit提交嘛” 聽說我要寫一篇Git教程,小明不屑一顧地說把兔。
“..."啊胶。

小明是我的一個學(xué)生。目前垛贤,是一名Android開發(fā)工程師焰坪。

過了幾天,我又再次見到了小明聘惦。

“鋒哥某饰,今天儒恋,我在Github新建了一個版本庫,本地提交后推送遠(yuǎn)程的時候黔漂,卻被拒絕了诫尽,是怎么回事?”

以下是小明的操作記錄:

git init
git add .
git commit -m "Init commit"
git remote add origin git@github.com:xiaoming/xxx.git
git pull origin master

以上操作觸發(fā)了下面的錯誤:

From git@github.com:xiaoming/xxx.git
 * branch            master     -> FETCH_HEAD
 * [new branch]      master     -> origin/master
fatal: refusing to merge unrelated histories

“小明炬守,注意看最后一句提示牧嫉。翻譯成中文的意思是 ‘拒絕合并不相關(guān)的歷史’,這個問題有兩個方案可以處理减途。"

  • git pull命令其實(shí)是觸發(fā)了拉取git fetch和合并git merge兩個操作酣藻。而本地的版本庫和遠(yuǎn)程版本庫在第一次拉取或推送完成之前是毫不相關(guān)的,Git為了避免不必要的合并鳍置,默認(rèn)不允許進(jìn)行這樣的操作辽剧。但你可以手動添加--allow-unrelated-histories強(qiáng)制進(jìn)行合并,這是方案一税产。
git pull origin master --allow-unrelated-histories
  • 再來看方案二怕轿,從你上面的操作來看,你只是在本地初始化了一個版本庫辟拷,并完成了基礎(chǔ)的提交撞羽。接下來,你希望和遠(yuǎn)程版本庫建立關(guān)聯(lián)衫冻,將提交推送到遠(yuǎn)程诀紊。這種情況下,其實(shí)你可能并不需要遠(yuǎn)程的默認(rèn)數(shù)據(jù)(通常是一個空的README文件)羽杰。所以渡紫,你可以添加-f參數(shù)羡儿,將提交強(qiáng)制提交并覆蓋遠(yuǎn)程版本庫雏逾。
git push -f origin master

小明若有所思地點(diǎn)點(diǎn)頭月趟,這是小明第一次遇到Git問題。我想颜骤,接下來他應(yīng)該會比較順利了。

沒想到捣卤,過了幾天忍抽,我又收到了小明的消息。這一次董朝,他發(fā)來的是對Git的抱怨鸠项。

“鋒哥,Git好討厭子姜,提交日志出現(xiàn)了錯誤祟绊,也不能修改。你知道搜狗輸入法有時候不夠智能,輸入太快不小心就輸錯了...??”

“??牧抽,你這孩子嘉熊,別輕易下結(jié)論哈。其實(shí)扬舒,Git是允許修改提交記錄的阐肤。使用Git最舒服的一點(diǎn)就是:Git永遠(yuǎn)都會給你反悔的機(jī)會。這一點(diǎn)讲坎,其它的版本控制工具是做不到的孕惜!”

“哦,原來是這樣耙赂稀诊赊!那快說說看,要怎么做府瞄?” 小明已經(jīng)一副迫不及待的表情了碧磅。

git commit命令中有一個參數(shù)叫--amend就是為解決這個問題而生的。因此遵馆,如果是最近的提交鲸郊,你只需要按照下面的命令操作即可』醯耍”

git commit --amend -m "這是新的提交日志"

看完我的消息秆撮,小明給我發(fā)來一個微笑的表情。小明的抱怨讓我想起一句好氣又好笑的農(nóng)村俗語 “屙屎不出怪茅坑”换况,哈哈职辨。

本以為一切可以風(fēng)平浪靜了。沒想到戈二,過了一個月左右舒裤,突然接到了小明的緊急電話。電話那頭觉吭,小明似乎心情很急躁腾供。

“鋒哥,我不小心進(jìn)行了還原操作鲜滩,我寫的代碼全丟了伴鳖。幾千行的代碼啊,明天晚上就要發(fā)版本了徙硅,有辦法找回來嗎榜聂?”

聽到這個消息,我心里盤算嗓蘑,大約有50%的概率應(yīng)該是找不回來了须肆。這孩子比較粗心贴汪,可能根本就沒提交到版本庫。但如果他正好提交到了版本庫休吠,興許還有救扳埂。因此,我安慰他說 “小明瘤礁,別急阳懂!你打開TeamViewer,我遠(yuǎn)程幫你看看”

連上機(jī)器后柜思,我使用history命令看到小明在提交之后使用了git reset --hard xxx命令進(jìn)行重置岩调。--hardgit reset命令中唯一一個不安全的操作,它會真正地銷毀數(shù)據(jù)赡盘,以至于你在git log中完全看不到操作日志号枕。可是陨享,Git真的很聰明葱淳,它還保存了另外一份日志叫reflog,這個日志記錄了你每次修改HEAD的操作抛姑。因此赞厕,你可以通過下面的命令對數(shù)據(jù)進(jìn)行還原:

git reflog

// 使用這個命令,你看到的日志大概是這樣
c8278f9 (HEAD -> master) HEAD@{0}: reset: moving to c8278f9914a91e3aca6ab0993b48073ba1e41b2b
3e59423 HEAD@{1}: commit: a
c8278f9 (HEAD -> master) HEAD@{2}: commit (amend): v2 update
2dc167b HEAD@{3}: commit: v2
2e342e9 HEAD@{4}: commit (initial): Init commit

可以看到定硝,我們在版本3e59423進(jìn)行了git reset操作皿桑,最新版本是3e59423。因此蔬啡,我們可以再次通過git reset命令回到這個版本:

git reset --hard 3e59423

以上操作完成后诲侮,你會驚喜地發(fā)現(xiàn),丟失的數(shù)據(jù)居然神奇般地回來了箱蟆。

“?? ?? ??”

“下次別這樣操作了哈沟绪。另外,你怎么一次性丟失這么多代碼顽腾。一定要記得勤提交近零∨岛耍” 小明出現(xiàn)這樣的問題抄肖,與平時的不規(guī)范操作也是分不開的。因此窖杀,最后我還不忘囑咐了他一句漓摩。

“好的,我知道了入客。對了管毙,我一個還有比較疑惑的問題腿椎。git checkoutgit reset到底有啥區(qū)別?我以前用SVN的時候git checkout是用來檢出代碼的夭咬,在Git中可以用它切換分支或者指定版本啃炸,但git reset同樣可以做到。難道兩者是完全一樣的嗎卓舵?” 小明在QQ中給我發(fā)來了回復(fù)消息南用。

“這是一個比較有深度的問題,解釋這個問題需要一點(diǎn)時間掏湾。接下來裹虫,你仔細(xì)聽”

理解Git工作空間

理解這個問題之前,先來簡單學(xué)習(xí)一些Git基礎(chǔ)知識融击。Git有三種狀態(tài):

  • 已提交(commited):數(shù)據(jù)已完全保存到本地?cái)?shù)據(jù)庫中
  • 已修改(modified):修改了文件筑公,但還沒有保存到數(shù)據(jù)庫中
  • 已暫存(staged):對一個已修改的文件做了標(biāo)記,將包含在下一次提交的版本快照中

這三種狀態(tài)對應(yīng)Git三個工作區(qū)域:Git版本庫尊浪、暫存區(qū)和工作區(qū)


Git版本庫是Git用來保存項(xiàng)目的元數(shù)據(jù)和對象數(shù)據(jù)庫的地方匣屡,使用git clone命令時拷貝的就是這里的數(shù)據(jù)。

工作目錄是對某個版本獨(dú)立檢出的內(nèi)容拇涤,這些數(shù)據(jù)可以供你使用和修改耸采。

暫存區(qū)在Git內(nèi)部對應(yīng)一個名為index的文件,它保存了下次將要提交的文件列表信息工育。因此虾宇,暫存區(qū)有時候也被叫作 “索引”。

一個基礎(chǔ)的Git工作流程如下:
1)在工作區(qū)修改文件
2)使用git add將文件添加到暫存區(qū)如绸,也就是記錄到index文件中
3)使用git commit將暫存區(qū)中記錄的文件列表嘱朽,使用快照永久地保存到Git版本庫中

理解HEAD

解釋這個問題,你還需要簡單理解HEAD是什么怔接。簡單來說搪泳,HEAD是當(dāng)前分支引用的指針,它永遠(yuǎn)指向該分支上最后一次提交扼脐。為了讓你更容易理解HEAD岸军,你可以將HEAD看作上一次提交數(shù)據(jù)的快照。

如果你感興趣瓦侮,你可以使用一個底層命令來查看當(dāng)前HEAD的快照信息:

git ls-tree -r HEAD

100644 blob aca4b576b7d4534266cb818ab1191d91887508b9    demo/src/main/java/com/youngfeng/snake/demo/Constant.java
100644 blob b8691ec87867b180e6ffc8dd5a7e85747698630d    demo/src/main/java/com/youngfeng/snake/demo/SnakeApplication.java
100644 blob 9a70557b761171ca196196a7c94a26ebbec89bb1    demo/src/main/java/com/youngfeng/snake/demo/activities/FirstActivity.java
100644 blob fab8d2f5cb65129df09185c5bd210d20484154ce    demo/src/main/java/com/youngfeng/snake/demo/activities/SecondActivity.java
100644 blob a7509233ecd8fe6c646f8585f756c74842ef0216    demo/src/main/java/com/youngfeng/snake/demo/activities/SplashActivity.java

這里簡單解釋一下每個字段的意思:100644表示文件模式艰赞,其對應(yīng)一個普通文件。blob表示Git內(nèi)部存儲對象數(shù)據(jù)類型肚吏,另外還有一種數(shù)據(jù)類型tree方妖,對應(yīng)一個樹對象,中間較長的字符串對應(yīng)當(dāng)前文件的SHA-1值罚攀,這部分不需要記住党觅,簡單了解即可雌澄。

所以,簡單來說杯瞻,HEAD對應(yīng)一個樹形結(jié)構(gòu)镐牺,存儲了當(dāng)前分支所有的Git對象快照:


我們用一個表格簡單來總結(jié)一下以上知識點(diǎn):

HEAD Index(暫存區(qū)) 工作區(qū)
上一次提交的快照,下一次提交的父節(jié)點(diǎn) 預(yù)期的下一次提交快照 當(dāng)前正在操作的沙盒目錄

理解git resetgit checkout區(qū)別主要是理解Git內(nèi)部是怎么操作以上三棵樹的魁莉。

接下來任柜,我們用一個簡單的例子來看一下使用git reset到底發(fā)生了什么。先創(chuàng)建一個Git版本庫并觸發(fā)三次提交:

git init repo
touch file.txt
git add file.txt
git commit -m "v1"

echo v2 > file.txt
git add file.txt
git commit -m "v2"

echo v3 > file.txt
git add file.txt
git commit -m "v3"

以上操作完成后沛厨,版本庫現(xiàn)在看起來是這樣的:


接下來執(zhí)行命令git reset 14ad152看看會發(fā)生什么宙地。以下是命令執(zhí)行完成后看到的結(jié)果:

git log --abbrev-commit --pretty=oneline
### This is output ###
14ad152 (HEAD -> master) v2
bcc49f4 v1

git status -s
### This is output ###
 M file.txt

cat file.txt
### This is output ###
v3

可以看到版本庫中文件版本回退到了V2,工作區(qū)文件內(nèi)容同之前的版本V3一致逆皮;為了確認(rèn)暫存區(qū)發(fā)生了什么變化宅粥,我們再使用一個底層命令對比一下暫存區(qū)數(shù)據(jù)和版本庫數(shù)據(jù)是否一致:

# 查看暫存區(qū)信息
git ls-files -s
### This is output ###
100644 8c1384d825dbbe41309b7dc18ee7991a9085c46e 0   file.txt

# 查看版本庫快照信息
git ls-tree -r HEAD
### This is output ###
100644 blob 8c1384d825dbbe41309b7dc18ee7991a9085c46e    file.txt

可以看到當(dāng)前版本庫和暫存區(qū)信息是完全一致的,HEAD指向了v2提交电谣,用一個圖形來表示整個過程秽梅,應(yīng)該是這樣:


看一眼上圖,理解一下剛剛發(fā)生的事情:首先剿牺,HEAD指針發(fā)生了移動企垦,指向了V2,并撤銷了上一次提交晒来。目前钞诡,版本庫和暫存區(qū)都保存的是第二次提交的記錄,工作區(qū)卻保存了最近一次修改湃崩。稍微聯(lián)想一下荧降,你就會發(fā)現(xiàn),這次的git reset命令恰好是最近一次提交的逆向操作攒读。讓數(shù)據(jù)完全回到了上一次提交前的狀態(tài)朵诫。所以,如果你想撤銷最近一次提交薄扁,可以這么做剪返。

增加--soft參數(shù)測試

以上是我們對git reset命令的第一次嘗試,在下一輪嘗試前邓梅,先執(zhí)行git help reset看看reset命令的用法:

git reset [-q] [<tree-ish>] [--] <paths>...
git reset (--patch | -p) [<tree-ish>] [--] [<paths>...]
git reset [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>]

看最后一句發(fā)現(xiàn)脱盲,reset命令后面還可以接5個不同的參數(shù): --soft--mixed震放、--hard 宾毒、--merge驼修、--keep殿遂。這里我們主要關(guān)注前面三個诈铛,其中--mixed其實(shí)剛剛已經(jīng)嘗試過,它和不帶參數(shù)的git reset命令是同樣的效果墨礁。換而言之幢竹,--mixedgit reset命令的默認(rèn)行為。接下來執(zhí)行git reset --soft 14ad152看看會發(fā)生什么恩静。命令執(zhí)行完成后焕毫,按照慣例,我們同樣使用基礎(chǔ)命令看看發(fā)生了什么變化:

git log --abbrev-commit --pretty=oneline
### This is output ###
14ad152 (HEAD -> master) v2
bcc49f4 v1

git status -s
### This is output ###
M  file.txt

cat file.txt
### This is output ###
v3

奇怪了驶乾?為什么會和上次不帶任何參數(shù)的執(zhí)行結(jié)果完全一致邑飒?難道Git出現(xiàn)了設(shè)計(jì)錯誤。相信你看到結(jié)果一定會有這樣的疑問级乐,其實(shí)不然疙咸!因?yàn)椋@里我用文本粘貼了輸出結(jié)果风科,忽略了命令的字體顏色撒轮,其實(shí)這里第二條命令輸出結(jié)果中的M顏色與上一次執(zhí)行結(jié)果是不一樣的。為了讓你看到不同贼穆,看下面的截圖:


這個顏色表示:file.txt文件已經(jīng)被添加到了暫存區(qū)题山,使用git commit命令就可以完成提交。為了嚴(yán)謹(jǐn)故痊,我們依然使用上面的底層命令看看版本庫和暫存區(qū)信息是否一致顶瞳。注意:這里的結(jié)果應(yīng)該是不一致才對,因?yàn)榘姹編煊涗浀奈募姹臼莢2愕秫,而暫存區(qū)記錄的文件版本其實(shí)是v3浊仆。

git ls-tree -r HEAD
### This is output ###
100644 blob 8c1384d825dbbe41309b7dc18ee7991a9085c46e    file.txt

git ls-files -s
### This is output ###
100644 29ef827e8a45b1039d908884aae4490157bcb2b4 0   file.txt

可以看到,兩個命令執(zhí)行輸出的SHA-1并不一致豫领,驗(yàn)證了我們的猜想抡柿。

這里我們可以得出一個結(jié)論:--soft和默認(rèn)行為(--mixed)不一樣的地方是:--soft會將工作區(qū)的最新文件版本再做一步操作,添加到暫存區(qū)等恐。使用這個命令可以用來合并提交洲劣。即:如果你在某一次提交中有未完成的工作,而你反悔了课蔬,你可以使用這個命令撤銷提交囱稽,等工作做完后繼續(xù)一次性完成提交。

增加--hard參數(shù)測試

接下來我們對最后一個參數(shù)進(jìn)行測試二跋,這也是小明在使用過程出現(xiàn)問題的一個參數(shù)战惊。執(zhí)行命令git reset --hard 14ad152,看看發(fā)生了什么:

git log --abbrev-commit --pretty=oneline
### This is output ###
14ad152 (HEAD -> master) v2
bcc49f4 v1

git status -s
### This is output ###
>>> No output <<<

cat file.txt
v2

注意看扎即,這次使用git status -s完全看不到輸出吞获,這就證明:當(dāng)前工作區(qū)况凉,暫存區(qū),版本庫數(shù)據(jù)是完全一致的各拷。查看文件內(nèi)容刁绒,發(fā)現(xiàn)文件回到了v2版本。通常情況下烤黍,如果你看到這種情況知市,一定會嚇一跳,你最近一次提交的數(shù)據(jù)居然完全丟失了速蕊。的確嫂丙,這是Git命令中少有的幾個真正銷毀數(shù)據(jù)的命令之一。除非你非常清楚地知道自己在做什么规哲,否則奢入,請盡量不要使用這個命令!

我們依然用一張圖媳叨,完整地描述這個命令到底發(fā)什么了什么:


可以看到腥光,相對于默認(rèn)行為,--hard將工作區(qū)的數(shù)據(jù)也還原到了V2版本糊秆,以至于V3版本的提交已經(jīng)完全丟失武福。

git checkout

接下來看git checkout, 按照慣例,先執(zhí)行git checkout 14ad152看看會發(fā)生什么:

git log --abbrev-commit --pretty=oneline
### This is output ###
14ad152 (HEAD -> master) v2
bcc49f4 v1

git status -s
### This is output ###
>>> No output <<<

cat file.txt
v2

可以看到痘番,又出現(xiàn)了神奇的一幕捉片,這一次git checkout命令的執(zhí)行結(jié)果的確和git reset --hard完全一致。這是否意味著兩者就沒有任何區(qū)別了呢汞舱?當(dāng)然也不是伍纫。嚴(yán)格來說,兩者有兩個“本質(zhì)”的區(qū)別:

  • 相對而言昂芜,git checkout對工作目錄是安全的莹规,它不會將工作區(qū)已經(jīng)修改的文件還原,git reset則不管三七二十一一股腦全部還原泌神。
  • 另外一個比較重要的區(qū)別是良漱,git checkout并不移動HEAD分支的指向,它是通過直接修改HEAD引用來完成指針的指向欢际。

第二個不同點(diǎn)相對比較難理解母市,我們用一張圖來更直觀地展示二者的區(qū)別:


簡單來說,git reset會通過移動指針來完成HEAD的指向损趋,而git checkout則通過直接修改HEAD本身來完成指向的移動患久。

命令作用于部分文件

git resetgit checkout還可以作用于一個文件,或者部分文件,即帶文件路徑執(zhí)行蒋失。這種情況下返帕,兩個命令的表現(xiàn)不太一樣。我們來試試看高镐,先執(zhí)行git reset 14ad15 -- file.txt命令嘗試將文件恢復(fù)到V2版本溉旋。命令執(zhí)行完成畸冲,按照慣例用一些基礎(chǔ)命令來看看發(fā)生了什么:

git log --abbrev-commit --pretty=oneline
### This is output ###
4521405 (HEAD -> master) v3
14ad152 v2
bcc49f4 v1

git status -v
### This is output ###
diff --git a/file.txt b/file.txt
index 29ef827..8c1384d 100644
--- a/file.txt
+++ b/file.txt
@@ -1 +1 @@
-v3
+v2

cat file.txt
v3

可以看到嫉髓,版本庫和工作區(qū)的數(shù)據(jù)都沒有發(fā)生變化。唯一發(fā)生變化的是暫存區(qū)邑闲,暫存區(qū)記錄下一次提交的改動將導(dǎo)致數(shù)據(jù)從V3恢復(fù)到V2版本!


這里我們可以這樣理解:執(zhí)行這條命令后算行,Git先將暫存區(qū)和工作區(qū)的文件版本恢復(fù)到V2,再將工作區(qū)的文件版本恢復(fù)到V3苫耸。與--hard不一樣的地方是:這個命令并不會覆蓋工作區(qū)已經(jīng)修改的文件州邢,是安全操作。

執(zhí)行帶路徑的git checkout命令和git reset命令有一些細(xì)微的差別褪子,相對于git reset量淌,git checkout帶路徑執(zhí)行會覆蓋工作區(qū)已經(jīng)修改的內(nèi)容,導(dǎo)致數(shù)據(jù)丟失嫌褪,是一個非安全操作呀枢。

針對上面的所有實(shí)驗(yàn),我們用一個簡單的表格來總結(jié)他們的區(qū)別笼痛,以及操作是否安全:

不帶路徑執(zhí)行

命令行 HEAD 暫存區(qū) 工作區(qū) 目錄安全
git reset [--mixed] YES YES NO YES
git reset --soft YES YES NO YES
git reset --hard YES YES YES NO
git checkout Modify YES YES YES

帶路徑執(zhí)行

命令行 HEAD 暫存區(qū) 工作區(qū) 目錄安全
git reset -- NO YES NO YES
git checkout NO YES YES NO

注意:執(zhí)行非目錄安全的命令操作的時候裙秋,一定要慎重,除非你非常清楚自己在做什么缨伊!

“小明摘刑,你明白了嗎?” 消息發(fā)送過去之后刻坊,等了很久卻一直沒有響應(yīng)枷恕。
“哎,這孩子谭胚!估計(jì)聽睡著了... ??”

自從這次問到Git的問題后活尊,已經(jīng)兩年過去了,小明再沒有問到關(guān)于Git的問題漏益。而就在昨天蛹锰,突然又收到了小明的消息。

也許你應(yīng)該試試Git Flow

“鋒哥绰疤,我現(xiàn)在已經(jīng)是Android Leader了⊥現(xiàn)在安卓團(tuán)隊(duì)一共6個人,我們現(xiàn)在在做一個社交類應(yīng)用,在Git管理方面我還是發(fā)現(xiàn)了一些問題癣猾。其中一個問題就是敛劝,現(xiàn)在版本庫有好多分支,其中開發(fā)主要在develop分支纷宇。主干分支是master主要用于版本發(fā)布夸盟。可還有一些分支卻顯得非诚翊罚混亂上陕,有什么辦法改善這種情況嗎?”

“關(guān)于Git的分支設(shè)計(jì)拓春,目前有一個公認(rèn)比較好的設(shè)計(jì)叫 Git Flow模型释簿。關(guān)于Git Flow模型,你可以查看這篇文章 http://nvie.com/posts/a-successful-git-branching-model/ 了解一下"

一個idea硼莽,一次提交

"好的庶溶!還有一個困擾了我很久的問題是,大家的提交日志寫的比較籠統(tǒng)懂鸵。在查找問題的時候非常不便偏螺,而且大部分同學(xué)一次性提交好多文件,導(dǎo)致解決問題的時候不能準(zhǔn)確定位到具體是哪一次提交導(dǎo)致的匆光。我告訴大家套像,一次提交改動要盡可能小。但當(dāng)別人問到具體的提交規(guī)則的時候我又不知道從何說起..."

“這是一個很好的問題 殴穴。中國程序員普遍存在的一個問題是凉夯,恨不得把這輩子能提交的代碼一次性搞定。甚至有人用多次提交太麻煩的借口來搪塞問責(zé)人采幌。簡單來說劲够,可以用一句話概括提交原則:一個idea,一次提交休傍。另外征绎,你說的沒錯,提交必須盡可能小磨取,注釋必須盡可能表述準(zhǔn)確人柿!”

給小明講了這么多Git,我忍不住半開玩笑地問他忙厌,“小明凫岖,你現(xiàn)在還覺得Git簡單嗎?”

小明發(fā)了一個無奈的表情逢净!說道哥放,“以前是我才疏學(xué)淺歼指,略知皮毛,不知道Git原來還有這么多玩法甥雕,忍不住為Git的發(fā)明者點(diǎn)贊了踩身。對了,鋒哥社露,Git到底是誰開發(fā)的挟阻?”

Git的最大功臣,其實(shí)不是Linus

”關(guān)于Git的故事峭弟,互聯(lián)網(wǎng)上其實(shí)已經(jīng)爛大街了附鸽。我簡單給你介紹一下吧!Git的誕生其實(shí)是一個偶然孟害,其初始使命是為Linux內(nèi)核代碼管理服務(wù)的拒炎。早年的時候Linux內(nèi)核源碼是用Bitkeeper版本控制工具管理的挪拟“の瘢可是,后來因?yàn)槟承├骊P(guān)系玉组,Bitkeeper要求Linux社區(qū)付費(fèi)使用谎柄。這一舉動激怒了Linus,也就是Linux的創(chuàng)始人惯雳,他決定自己開發(fā)一個分布式版本控制系統(tǒng)朝巫。幾周時間下來,Git的雛形就誕生了石景,并且開始在Linux社區(qū)中應(yīng)用開來劈猿。雖然Linus是Git的創(chuàng)始人,可是背后的最大功臣卻是一個日本人 Junio C Hamano潮孽。Linus在Git開源版本庫的提交只有258次揪荣,而Junio C Hamano卻提交了4000多次。也就是說往史,在Linus開發(fā)后不久項(xiàng)目的管理權(quán)就交給了這個日本人仗颈。關(guān)于 Junio C Hamano,你感興趣的話可以Google了解一下椎例。他現(xiàn)在在Google工作挨决,如同Linus一樣非常低調(diào)《┩幔“

“這個故事也告訴我:不要用技術(shù)去挑戰(zhàn)一個程序員 @_@ ”

這個故事講完脖祈,小明與Git的故事就已經(jīng)告一段落了。其實(shí)刷晋,還有一些比較常見的問題盖高,小明并沒有問到過福压。這里,我為你準(zhǔn)備了一個附錄或舞,給你介紹一些常用的小命令幫你解決日常小問題荆姆。它很有用,一定要拿筆記下來映凳,或者收藏這篇文章備用胆筒。

常見問題

問題一:公司的Git服務(wù)器是搭建在一個內(nèi)網(wǎng)服務(wù)器上面的,我想把代碼同時提交到OsChina上面诈豌,以便在家拉取代碼仆救,遠(yuǎn)程辦公,怎么辦矫渔?
Git本身是一個分布式的版本管理系統(tǒng)彤蔽,實(shí)現(xiàn)這個需求非常簡單,使用git remote add命令添加多個遠(yuǎn)程版本庫關(guān)聯(lián)即可庙洼。

git remote add company git@xxx
git remote add home git@xxx

問題二:在拉取遠(yuǎn)程代碼的時候顿痪,如果本地有代碼還沒有提交,Git就會提示先提交代碼到版本庫油够∫舷可暫時我又不想提交,怎么辦石咬?
針對這個問題揩悄,Git提供了一個臨時區(qū)域用于保存不想提交的記錄,對應(yīng)的命令是git stash鬼悠。通常情況下删性,你可以這樣操作:

# 將暫時還不想提交的數(shù)據(jù)保存到臨時區(qū)域,保存成功后焕窝,工作區(qū)將和版本庫完全一致
git stash
# 還原stash數(shù)據(jù)到工作區(qū)
git stash apply
# 以上操作完成后蹬挺,stash數(shù)據(jù)依然保存在臨時區(qū)域中,為了刪除這部分?jǐn)?shù)據(jù)袜啃,使用如下命令即可汗侵。
git stash drop
# 如果你想在還原數(shù)據(jù)的同時從臨時區(qū)域刪除數(shù)據(jù),可以這樣操作:
git statsh pop
# 以上兩個命令如果不接任何參數(shù)將刪除掉所有的臨時區(qū)域數(shù)據(jù)群发,如果你只想刪除其中一條記錄晰韵,指定對應(yīng)索引數(shù)據(jù)即可。
git stash pop/drop stash@{index}
# 查看臨時區(qū)域所有數(shù)據(jù)熟妓,使用如下命令:
git stash list

問題三:作為項(xiàng)目負(fù)責(zé)人雪猪,我希望迅速找出問題代碼的“元兇”,有什么辦法嗎起愈?
針對這個問題只恨,最好的答案是git blame译仗,使用這個命令并指定具體文件它將顯示文件每一行代碼的最近修改記錄,你可以清晰地看到最近代碼的修改人官觅。

問題四:部分Team Leader會要求使用git rebase合并代碼纵菌,這有什么好處嗎?
我們用一個簡單的思維來理解這個問題休涤,最常見的合并操作是使用git merge咱圆,而這樣操作會在合并分支生成一次新的提交,并且會嚴(yán)格記錄分支提交日志功氨,在長期開發(fā)過程中序苏,日志就會呈現(xiàn)多條線路展示,給閱讀帶來一定的障礙捷凄。而使用git rebase會使整體代碼提交記錄始終像在單一分支開發(fā)一樣忱详,僅使用一條線路展示。但使用git rebase是有一定陷阱的跺涤,這個問題需要一定的時間才能說清楚匈睁,如果需要了解兩個命令的詳細(xì)區(qū)別,我推薦你閱讀這篇文章 Rebase 代替合并钦铁。

總結(jié)

Git是一個非常優(yōu)秀的版本控制系統(tǒng)软舌,我極力推薦你在日常開發(fā)中使用才漆。這篇文章從小明的角度解釋了幾個常見問題的解決方案牛曹,毫無懸念地,你可能還會遇到其它的一些問題醇滥。遇到問題黎比,你可以嘗試使用Google搜索解決方案;也可以在文章下方給我留言鸳玩,我非常樂意為你解答Git問題阅虫。


我是歐陽鋒,版本控制不跟,我使用Git颓帝。了解歐陽鋒,從這里開始:歐陽鋒檔案館窝革。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末购城,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子虐译,更是在濱河造成了極大的恐慌瘪板,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件漆诽,死亡現(xiàn)場離奇詭異侮攀,居然都是意外死亡锣枝,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門兰英,熙熙樓的掌柜王于貴愁眉苦臉地迎上來撇叁,“玉大人,你說我怎么就攤上這事畦贸∷捌樱” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵家制,是天一觀的道長正林。 經(jīng)常有香客問我,道長颤殴,這世上最難降的妖魔是什么觅廓? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮涵但,結(jié)果婚禮上杈绸,老公的妹妹穿的比我還像新娘。我一直安慰自己矮瘟,他們只是感情好瞳脓,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著澈侠,像睡著了一般劫侧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上哨啃,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天烧栋,我揣著相機(jī)與錄音,去河邊找鬼拳球。 笑死审姓,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的祝峻。 我是一名探鬼主播魔吐,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼莱找!你這毒婦竟也來了酬姆?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤宋距,失蹤者是張志新(化名)和其女友劉穎轴踱,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體谚赎,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡淫僻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年诱篷,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片雳灵。...
    茶點(diǎn)故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡棕所,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出悯辙,到底是詐尸還是另有隱情琳省,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布躲撰,位于F島的核電站针贬,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏拢蛋。R本人自食惡果不足惜桦他,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望谆棱。 院中可真熱鬧快压,春花似錦、人聲如沸垃瞧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽个从。三九已至脉幢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間信姓,已是汗流浹背鸵隧。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留意推,地道東北人。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓珊蟀,卻偏偏與公主長得像菊值,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子育灸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容