目錄:
- 減少【.git】文件夾的大小和文件數
- 更換git for windows的文本編輯器
- 修改已經提交的commit說明
- 合並commit
- 解決merge時出現的沖突
- 回退一個merge
- 獲取某一commit的修改
- 將低版本push到Github(刪掉高版本Commit)
減少【.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
的,能防止因為其他沒配置好而產生錯誤。對我來說差別並不大……