目錄:
減少【.git】文件夾的大小和文件數
隨着commit次數的增多,.git
文件夾的文件數和文件夾大小都會不斷增大。
雖然對於小項目,增大的速度極慢,文件夾也基本在10M左右。但如果你和我一樣,想減少該文件夾的文件數目(通常不少),可以試試這個命令。當然,git是鼓勵你多使用這個命令的。見:Git - git-gc Documentation
Users are encouraged to run this task on a regular basis within each repository to maintain good disk space utilization and good operating performance.
如何減少?特別簡單,就是你進入到一個repository,也就是你項目的根目錄,執行 git
gc
就行了。
我們來看看執行gc命令前後的對比:
運行 git
gc
前:
運行 git
gc
後:
文件夾大小變化不大。變化最大的是文件數目(2561 -> 37)和文件夾數(274 -> 18)。
要講清楚這個命令,涉及到了git是如何存儲你的commit。這就要說到快照(Snapshot)
。
我們先看看git的官方說明:直接記錄快照,而非差異比較
每次你提交更新,或在 Git 中保存項目狀態時,它主要對當時的全部文件製作一個快照並保存這個快照的索引。 爲了高效,如果文件沒有修改,Git 不再重新存儲該文件,而是隻保留一個鏈接指向之前存儲的文件。 Git 對待數據更像是一個 快照流。
那麼問題來了:什麼是快照?
來實際感受一下:
首先我準備了一個大的文件,這樣比較能說明問題。剛好今天整理一個文件,有55.3MB,就順手拿來用了。
可以看到,源文件是55.3MB,而將其添加到倉庫裏後,倉庫的大小變爲46.3MB。這相當於是將整個文件複製到裏面去。
如果這還不能說明問題,再來一次。我刪除了文件裏的一大部分內容,將其減小至20.5MB。再將其提交到倉庫裏面。
增加了19MB,跟20.5MB很接近。
你可以在 .git\objects\某個文件夾
裏找到這兩份快照。
於是我們可以得出一個近似的結論:在git中,一份快照就是你當前工作目錄的狀態。當你使用add命令時,它將你當前工作目錄的文件進行壓縮,形成一份快照。
不過,如果你有一些文件完全沒有被修改過,它只保存指向之前版本的引用。這樣可以減少快照所佔用的空間。這裏沒有試驗,但是官方對此有說明:
To be efficient, if files have not changed, Git doesn’t store the file again, just a link to the previous identical file it has already stored.
那麼這個時候我們再去執行 git
gc
,會變成什麼樣呢?
之前說的三個方面都有減少。
我們再看看.git\objects
裏的文件夾(事先不知道它會刪除文件夾,沒有截圖。。)
可以看到我們上面快照所在文件,即02
和f7
文件夾已經不在objects
這個文件夾裏面了。(info和pack兩個文件夾一直都在那裏)
點進pack文件夾:
.git
文件夾的46.5M都在這裏了。所以我們可以知道,git將之前兩個文件夾的快照文件合併到一起了。
更換git for windows的文本編輯器
git for windows默認使用vim作爲文本編輯器,爲此我專門寫了篇vim的基本操作:vim編輯器的簡單使用
如果你不想學習vim的使用,也可以把它換掉。
例如我想把它換成atom:
- 先找到啓動atom的exe文件的路徑。我的在
C:\Users\Schaepher\AppData\Local\atom\app-1.13.0\atom.exe
-
啓動git for windows,執行
git config --global core.editor "C:/Users/Schaepher/AppData/Local/atom/app-1.13.0/atom.exe --new-window --foreground --wait"
注意,這裏路徑的斜槓與Windows顯示的相反,這是Linux的路徑格式。
後面一串參數--new-window --foreground --wait
是由各編輯器自己指定的。如果不這樣指定,執行git rebase -i commitId^
的時候會直接退出編輯。
修改已經提交的commit說明
先用git
log
查看commit信息:
我打算更改下面那個commit,使用git
rebase -i 版本號^
:
執行命令後,會進入這樣的界面:
它把我們傳入的版本號之上的commit條目都顯示出來了,這裏只關注我們要改的那一條。將第一個pick
修改爲reword
,保存並退出。
過一會兒,它會再進入這樣的界面:
將第一行的Android的ListView
改爲這個更改後的message
,保存並退出。
再用git
log
查看:
不僅commit message被更改了,從被更改的commit開始,commit id都會重新生成。
合併commit
先用git
log
查看commit信息:
如果你想把最近的四個commit合併成一個commit,有兩種方法。一種是用git
reset --soft d7ac
,在git
commit -m "新的commit message"
,另一種是用git
rebase
。接下來講第二種。
首先根據上圖的commit id,我想把afe14f
之後的commit合併到afe14f
裏面,執行 git
rebase -i afe14f^
。進入編輯界面:
根據提示,squash
會把所在的commit合併到前一個commit上面。我們要合併到afe14f
,所以修改後三個。而在合併之後,我們需要修改afe14f
的commit
message,所以使用reword
。
你也可以用縮寫,比如
squash
的縮寫是s
。而reword
的縮寫是s
。
保存並退出,會進入下一個界面。修改第一行的commit message,即reword
的那個message,爲添加Android學習筆記,特別是ListView的介紹;添加對git
commit的修改教程
。如下圖:
保存並退出。自動進入下一個界面:
此時要將其他三個message去掉,只要在那三行前面加#
就行了。如下圖:
保存並退出,等待git處理完成。
再次使用git
log
查看commit信息:
完成!
這裏貌似可以不使用
reword
,待實驗。
解決merge時出現的衝突
當你和其他團隊成員對同一個文件進行修改後,merge的時候有可能會出現衝突。你可以打開每個衝突的文件,手工解決衝突;也可以藉助衝突處理工具來解決衝突。這裏分別介紹這兩種方式:
-
手工解決衝突
衝突提示如下圖所示:
CONFLICT表示有衝突,在這一行的末尾,顯示衝突文件。這裏有兩個文件衝突,分別是README.md和app.iml
這裏以README.md爲例,解決衝突:被紅框框住的符號
=======
是衝突的分割線。<<<<<<< HEAD
和分割線之間的是本地的文本,分割線和>>>>>>> upstream/dev
之間的是遠程分支的文本你可以選擇保留其中一個版本的文本,然後將三個衝突符號都刪除。這樣表示已解決衝突。如果你想同時保留兩個版本,那麼只需將衝突符號刪除。
解決衝突後如下圖所示:
-
藉助衝突處理工具
個人認爲Meld這個工具比較好用,Android Studio自帶的衝突處理工具和它很相似。我用過tortoisegit的工具,感覺沒有Meld好用,這裏就不介紹了。(1) 首先去Meld的官網下載安裝文件並安裝。->點此進入Meld官網
(2) 安裝完後,打開你的git工具,比如msysgit。執行
git config --edit --global
,此時會打開一個配置文件。在文件最後添加以下四行:[merge] tool = meld [mergetool "meld"] path = e:/software/MeldMergeTool/Meld.exe
提示:path是根據你安裝Meld的路徑來決定的,同時要把路徑中的
\
改成/
。從上面可以看出我的安裝路徑爲e:\software\MeldMergeTool\
。(3) 在merge的時候,如果出現衝突,運行命令
git mergetool
這時就會打開Meld。(4) Meld的界面如下:
衝突的地方會顯示紅色,如果你想保留本地的代碼,則點擊左邊的
→
箭頭。把所有紅色(衝突)區域解決後,可以根據實際情況去解決綠色(添加)和灰色(更改)。
一般保存中間的修改就行。如上圖紅框處。
回退一個merge
-
如果是merge一個GitHub的Pull Request,可以進入要回退的那個Pull Request,在下面有一個revert按鈕,可以用來revert一個Pull Request。如下圖紅框處:
-
在命令行裏revert
(1)用
git log
看commit記錄現在我們要回退
commit 561dab
(也就是圖中第一個commit),該commit將Pull Request #113 merge到項目中。(2)使用
git revert HEAD -m 1
命令回退如果是非merge的回退,用
git revert 版本號
就行了。但是這裏是對merge操作進行revert,需要加上參數-m
。命令最後加個1
。爲什麼要加上
1
呢?看上面(1)
的圖中的第二個紅框,這個1
對應紅框中的6a3c30c
版本。而如果填2
,則對應b7831df
。繼續看log,會發現
6a3c30c
是merge這個Pull Request之前的狀態。而b7831df
則是當前版本之前的一個merge。輸入命令回車後,會跳出一個文本。
目前無視它就行。關閉文本,回到shell,回車。
回退成功!這個回退不會刪除掉中間的commit記錄,而是將這次revert作爲一個commit加到commit記錄上面。
獲取某一commit的修改
假設有commit a
b c
,從左到右,c
爲最新版。
這時你發現 b
的一個修改有問題,想回退到 a
。但是如果回退到 a
, c
的commit也會被取消。
這時可以用 git
cherry-pick 版本號
這個命令獲取 c
的commit。
下圖是示例的log記錄,從①可以看出,這裏從②回退到⑤。
現在我想獲取④的commit。使用 git
cherry-pick 版本號
將選定版本的提交合併到當前版本。
將低版本push到Github(刪掉高版本Commit)
有時候會因爲各種原因,想要回退版本。如果沒有關聯Github或者沒有push上去,那問題不大。但是如果你已經push到Github上了,這時候就比較尷尬了,因爲普通的push是會被Github拒絕的。雖然Github提供了Revert功能,但是這並不能完全消去一個commit。
先看看reset後被拒絕的樣子:
解決方法就是:
- 先用
git reset --hard 版本號
回到你想要的版本 -
執行
git push --force
再看看Github:
當然,一般是推薦用
git push origin HEAD --force
的,能防止因爲其他沒配置好而產生錯誤。對我來說差別並不大……