Github使用(3)-Git的其他用法

目錄:


減少【.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裏的文件夾(事先不知道它會刪除文件夾,沒有截圖。。)

可以看到我們上面快照所在文件,即02f7文件夾已經不在objects這個文件夾裏面了。(info和pack兩個文件夾一直都在那裏)

點進pack文件夾:

.git 文件夾的46.5M都在這裏了。所以我們可以知道,git將之前兩個文件夾的快照文件合併到一起了。


更換git for windows的文本編輯器

git for windows默認使用vim作爲文本編輯器,爲此我專門寫了篇vim的基本操作:vim編輯器的簡單使用

如果你不想學習vim的使用,也可以把它換掉。

例如我想把它換成atom

  1. 先找到啓動atom的exe文件的路徑。我的在 C:\Users\Schaepher\AppData\Local\atom\app-1.13.0\atom.exe
  2. 啓動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的時候有可能會出現衝突。你可以打開每個衝突的文件,手工解決衝突;也可以藉助衝突處理工具來解決衝突。這裏分別介紹這兩種方式:

  1. 手工解決衝突

    衝突提示如下圖所示:

    CONFLICT表示有衝突,在這一行的末尾,顯示衝突文件。這裏有兩個文件衝突,分別是README.md和app.iml
    這裏以README.md爲例,解決衝突:

    被紅框框住的符號 ======= 是衝突的分割線。

    <<<<<<< HEAD 和分割線之間的是本地的文本,分割線和 >>>>>>> upstream/dev 之間的是遠程分支的文本

    你可以選擇保留其中一個版本的文本,然後將三個衝突符號都刪除。這樣表示已解決衝突。如果你想同時保留兩個版本,那麼只需將衝突符號刪除。

    解決衝突後如下圖所示:

  2. 藉助衝突處理工具
    個人認爲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

  1. 如果是merge一個GitHub的Pull Request,可以進入要回退的那個Pull Request,在下面有一個revert按鈕,可以用來revert一個Pull Request。如下圖紅框處:

  2. 在命令行裏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後被拒絕的樣子:

解決方法就是:

  1. 先用 git reset --hard 版本號 回到你想要的版本
  2. 執行 git push --force

    再看看Github:

    當然,一般是推薦用 git push origin HEAD --force 的,能防止因爲其他沒配置好而產生錯誤。對我來說差別並不大……

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章