ProGit-读书简记
ProGit-讀書簡記
from: http://lanbing510.info/2016/12/07/ProGit.html?ref=myread寫在前面
Git是一個非常好的版本管理工具,最早是根據廖雪峰等人的博客進行的學習,一直只用到了一些常用的命令做簡單的備份回退等。最近結合《ProGit》和《Git權威指南》進行了查漏補缺和更系統深入的學習,下面是結合ProGit一書做的讀書簡記。
起步
1 初次運行Git前的配置
Git 自帶一個 git config 的工具來幫助設置控制 Git 外觀和行為的配置變量。這些變量存儲在三個不同的位置:
①. /etc/gitconfig 文件: 包含系統上每一個用戶及他們倉庫的通用配置。 如果使用帶有 --system 選項的git config 時,它會從此文件讀寫配置變量。
②. ~/.gitconfig 或 ~/.config/git/config 文件:只針對當前用戶。 可以傳遞 --global 選項讓 Git讀寫此文件。
③. 當前使用倉庫的 Git 目錄中的 config 文件(就是 .git/config):針對該倉庫。
每一個級別覆蓋上一級別的配置,所以 .git/config 的配置變量會覆蓋 /etc/gitconfig 中的配置變量。在 Windows 系統中,Git 會查找 $HOME 目錄下(一般情況下是 C:\Users\$USER)的 .gitconfig 文件。Git 同樣也會尋找 /etc/gitconfig 文件,但只限于 MSys 的根目錄下,即安裝 Git 時所選的目標位置。
2 git config --list命令可以列出所有Git當時能找到的配置。
基礎
1 Git不同于其他版本控制系統,Git是直接記錄快照,而不是差異比較。
2 Git有工作目錄、暫存(索引)區域、Git倉庫三種工作狀態(有時還有遠程倉庫),關系見下圖。
3 用git status查看當前文件狀態,git status --short或者git status -s可輸出更簡潔的狀態。
新添加的未跟蹤文件前面有 ?? 標記,新添加到暫存區中的文件前面有 A 標記,修改過的文件前面有 M 標記。你可能注意到了 M 有兩個可以出現的位置,出現在右邊的 M 表示該文件被修改了但是還沒放入暫存區,出現在靠左邊的 M 表示該文件被修改了并放入了暫存區。
4 .gitignore文件中可以指定忽略模式,支持正則表達式。要忽略指定模式以外的文件或目錄,可以在模式前加上驚嘆號(!)取反。
5 查看已暫存和未暫存的修改。git diff比較的是工作目錄中當前文件和暫存區域快照之間的差異,也就是修改之后還沒有暫存起來的變化內容。若要查看已暫存的將要添加到下次提交里的內容(和工作目錄中當前文件的差異),可以用git diff --cached命令。(Git 1.6.1 及更高版本還允許使用 git diff --staged,效果是相同的,但更好記些。)
6 'git commit -a'可以跳過暫存區直接提交(跳過git add),但盡量避免使用。
7 移除文件。使用git rm移除。如果要移除的文件已經修改過且暫存了,必須使用-f選項強制刪除。如果想要把文件從Git倉庫中刪除,但保留在工作目錄中,使用git rm --cached file。
8 重命名使用git mv file_from file_to。
9 查看提交歷史使用git log命令。下圖是其常用選項:
一些例子如下:
git log -p -2 #顯示最近兩次提交每次提交的差異 git --stat #在每次提交的下面列出額所有被修改過的文件、有多少文件被修改了以及被修改 git log --pretty=format:"%h %s" --graph #提交對象的簡短哈希字串 提交說明 圖顯限制輸出長度的選項有:
例如:
git log --since=2.weeks #列出所有最近兩周內的提交 git log -Sfunction_name #找出添加或移除了某一個特定函數的引用的提交10 遠程倉庫的使用。可以使用git remote --help查看詳細使用說明。
git remote -v #顯示遠程倉庫信息; git remote add [shortname] [url] #添加一個新的遠程Git倉庫 git fetch [remote-name] #從遠程倉庫中抓取,不同于git pull,并不會合并, git push [remote-name] [branch-name] #推送到遠程倉庫 git remote show [remote-name] #查看遠程倉庫 git remote rename [ori-name] [dst-name] #重命名 git remote rm [shortname] #移除11 打標簽。
git tag #列出標簽 git tag -a v1.4 -m 'my version 1.4' #使用-a創建附注標簽,-m指定存儲在標簽中的信息 git show v1.4 #查看標簽信息與對應的提交信息 git tag v1.4-lw #創建輕量標簽 git tag -a v1.2 9fceb02 #后期打標簽,9fceb02是之前的一個提交 git push origin v1.5 #共享標簽 git push origin --tags #一次推送多個標簽 git checkout -b [branchname] [tagname] #在特定的標簽上創建一個新分支12 Git別名。
git config --global alias.co checkout #為checkout起別名co git config --global alias.last 'log -1 HEAD' #git last 顯示最后一次提交 git config --global alias.visual '!gitk' #想要執行外部命令,而不是一個 Git 子命令。在命令前面加入 ! 符號Git分支
1 Git保存數據保存的是文件的快照,進行提交操作是會提交一個對象,該對象包含一個指向暫存內容快照的指針,還包含了作者的姓名和郵箱、提交時輸入的信息以及指向它的父對象的指針。內容快照使用的blob對象來保存。下圖是個直觀展示,該Git 倉庫中有五個對象:三個blob對象(保存著文件快照)、一個樹對象(記錄著目錄結構和blob對象索引)以及一個提交對象(包含著指向前述樹對象的指針和所有提交信息)。
2 常用命令:
git branch [branch_name] #創建分支 git checkout [branch_name] #切換分支 git checkout -b [branch_name] #新建并切換分支 git branch -d hotfix #刪除hotfix分支 git merge hotfix #合并hotfix分支,先切換到master分支。當合并有沖突后,git status查看,修改后add,重新合并。 git branch --merged|--no-merged #過濾這個列表中已經合并或尚未合并到當前分支的分支3 遠程分支。origin是運行git clone時默認的遠程倉庫名字。如果運行git clone -o lanbing510,那么默認的遠程分支名字會是lanbing510/master。
git checkout --track origin/serverfix #本地創建serverfix分支來跟蹤遠程倉庫上的serverfix分支 git checkout -b sf origin/serverfix #創建一個sf的本地分支來跟蹤遠程倉庫serverfix分支 git checkout -u origin/serverfix #設置已有分支來跟蹤遠程分支 git branch -vv #查看設置是所有跟蹤分支 git push origin --delete serverfix #刪除遠程分支4 變基。整個不同分支的修改有合并(merge)和變基(rebase)兩種方法。merge可以保留記錄,rebase使分支更清晰。使用變基友風險,謹記:不要對在你的倉庫外有副本的分支執行變基。
git rebase --onto master server client #取出 client 分支,找出處于 client 分支和 server 分支的共同祖先之后的修改,然后把它們在 master 分支上重演一遍 git rebase master serve #取出serve分支,在master分支上重演分布式Git
1 常見的分布式工作流程有:
① 集中式工作流
② 集成管理者工作流
③ 司令官與副官工作流。典型工作流程如下:
2 向一個項目貢獻
① 首先,你不會想要把空白錯誤(根據 git help diff 的描述,結合下面給出的圖片,空白錯誤是指行尾的空格、Tab 制表符,和行首空格后跟 Tab 制表符的行為)提交上去。Git 提供了一個簡單的方式來檢查這點:在提交前,運行 git diff --check,它將會找到可能的空白錯誤并將它們為你列出來;
② 接下來,嘗試讓每一個提交成為一個邏輯上的獨立變更集;
③ 最后一件要牢記的事是提交信息。有一個創建優質提交信息的習慣會使 Git 的使用與協作容易的多。一般情況下,信息應當以少于50個字符(25個漢字)的單行開始且簡要地描述變更,接著是一個空白行,再接著是一個更詳細的解釋。
④ 一些常用命令
git log --no-merges issue54..origin/master #要求 Git 只顯示所有在后面分支(在本例中是origin/master)但不在前面分支(在本例中是 issue54)的提交的列表 git log origin/master --not issue54 #作用同上一條命令 git log refA refB --not refC #refA 或 refB 包含的但是不被 refC 包含的提交 git log master...experiment #三點語法,查看master 或者 experiment 中包含的但不是兩者共有的提交 git log --left-right master...experiment #還會顯示出每次提交位于哪一側 git request-pull origin/master myfork #在派生項目中,生成拉取請求的內容 git merge --no-commit --squash featureB #--squash 選項接受被合并的分支上的所有工作,并將其壓縮至一個變更集,使倉庫變成一個真正的合并發生的狀態,而不會真的生成一個合并提交。這意味著你的未來的提交將會只有一個父提交,并允許你引入另一個分支的所有改動,然后在記錄一個新提交前做更多的改動。同樣 --no-commit 選項在默認合并過程中可以用來延遲生成合并提交 git format-patch -M origin/master #通過郵件的公開項目,使用該命令,format-patch 命令打印出它創建的補丁文件名字。-M 開關告訴 Git 查找重命名 cat *.patch |git imap-send #將patch通過郵箱發送出去,前提是.gitconfig中配置好了imap3 維護項目
一些常用命令:
git apply xx.patch #應用使用 git diff 或 Unix diff 命令(不推薦)創建的補丁 git apply --check xx.patch #應用補丁之前檢查是否可以順利應用 git am xx.patch #應用使用format-patch生成的補丁 git diff master...contrib #三點語法,顯示自當前特性分支與 master 分支的共同祖先起,該分支中的工作。 git archive master --prefix='project/' | gzip > `git describe master`.tar.gz #歸檔 git archive master --prefix='project/' --format=zip > `git describe master`.zip #歸檔 git shortlog --no-merges master --not v1.0.1 #制作提交簡報Git進階
1 儲藏與清理
下面是儲藏和清理的一些常用命令:
git stash #儲藏工作目錄,準備干凈的合并 git stash list #查看儲藏的東西 git stash apply #應用儲藏的東西 git stash apply stash@{2} #應用更舊的儲藏 git stash drop stash@{0} #移動指定的儲藏 git stash pop #應用并丟棄儲藏 git stash --include-untracked 或 -u #同時儲藏未跟蹤文件 git stash --keep-index #不儲藏任何你通過git add命令已暫存的東西 git stash branch [branch_name] #從儲藏創建一個分支 git clean #清理工作目錄 git stash --all #移除每一樣東西并存放在棧中 git clean -x #做一次完全干凈的構建而移除所有由構建生成的.o 文件 git clean -f -d #強制移除工作目錄中所有未追蹤的文件以及空的子目錄,可以使用git clean -d -n來做一次演習,看看要做什么2 搜索
git grep -n gmtime_r #尋找gmtime_r并輸出所找到的匹配行行號 git grep -count gmtime_r #使 Git 輸出概述的信息,僅僅包括哪些文件包含匹配以及每個文件包含了多少個匹配 git grep -p gmtime_r *.c #-p選項看匹配的行是屬于哪一個方法或者函數,該命令是查看哪個函數調用了gmtime_r git grep --break --heading -n -e '#define' --and \( -e LINK -e BUF_MAX \) v1.8.0 #查看在舊版本 1.8.0 的 Git 代碼庫中定義了常量名包含 “LINK” 或者 “BUF_MAX” 這兩個字符串所在的行,--break 和 --heading 選項來使輸出更加容易閱讀 git log -L :git_deflate_bound:zlib.c #查看 zlib.c 文件中`git_deflate_bound` 函數的每一次變更3 重寫歷史。
① git commit --amend修正最后一次提交。
② 修改多個提交信息。通過交互式變基工具,可以在任何想要修改的提交后停止,然后修改信息、添加文件或做任何想做的事情。可以通過給 git rebase 增加 -i選項來交互式地運行變基。例如:
git rebase -i HEAD~3 #修改最近三次提交信息,運行命令后會進入交互式界面,按照提示進行即可。③ git rebase -i 同樣可以進行排序提交,壓縮提交,拆分提交等操作,用到時可以詳細參考ProGit的相應部分。
④ 如果想要通過腳本的方式改寫大量提交的話可以使用 filter-branch 例如,全局修改你的郵箱地址或從每一個提交中移除一個文件。例:
git filter-branch --tree-filter 'rm -f passwords.txt' HEAD #從整個提交歷史中移除一個叫做 passwords.txt 的文件4 重置操作(reset)。
① git reset --soft只移動分支,不更新暫存(索引)和工作目錄;
② git reset --mixed 不指定--soft和--hard時的默認選項,更新暫存,不更新工作目錄;
③ git reset --hard 更新暫存和工作目錄;
④ 通過路徑來重置。
git reset file.txt #等價于git reset --mixed HEAD file.txt ,用HEAD分支的file.txt更新暫存(索引)區域 git reset eb43bf file.txt #用eb43bf提交的file.txt更新索引5 檢出(checkout)。
① 不帶路徑的情況。運行 git checkout [branch] 與運行 git reset --hard [branch] 非常相似,它會更新所有三棵樹使其看起來像 [branch],不過有兩點重要的區別:
首先不同于 reset --hard,checkout 對工作目錄是安全的,它會通過檢查來確保不會將已更改的文件吹走;
第二個重要的不同點在于如何更新 HEAD。reset 會移動 HEAD 分支的指向,而 checkout 只會移動 HEAD 自身來指向另一個分支。結合下圖會更清晰的理解:
② 帶路徑。運行 checkout 的另一種方式就是指定一個文件路徑,這會像 reset 一樣不會移動 HEAD。它就像 git reset [branch] file那樣用該次提交中的那個文件來更新索引,但是它也會覆蓋工作目錄中對應的文件。它就像是git reset --hard [branch] file(如果 reset 允許你這樣運行的話)- 這樣對工作目錄并不安全,它也不會移動 HEAD。
6 重置和檢出的總結速查。下面的速查表列出了命令對樹的影響。"HEAD" 一列中的 "REF" 表示該命令移動了 HEAD 指向的分支引用,而"HEAD" 則表示只移動了 HEAD 自身。特別注意 WD Safe? 一列 - 如果它標記為 NO,那么運行該命令之前請考慮一下。
7 高級合并
① 合并出現沖突后,Git索引會儲藏了所有版本(共同的版本stage1,我們的版本stage2,他們的版本stage3)。
② 合并出現沖突后,可以打開沖突的文件,根據指示修改。
③ 一些常用命令:
git merge --abort #嘗試恢復到你運行合并前的狀態。但當運行命令前,在工作目錄中有未儲藏、未提交的修改時它不能完美處理,除此之外它都工作地很好 git merge -Xignore-all-space 或 -Xignore-space-change [branch_name] #忽略任意數量的已有空白的修改 或 忽略所有空白修改 git show :1:hello.rb > hello.common.rb #導出共同版本 git show :2:hello.rb > hello.ours.rb #導出我們的版本 git merge-file -p hello.ours.rb hello.common.rb hello.theirs.rb > hello.rb #手動合并沖突修改后的文件,合并完畢后git clean來清理手動合并創建但不再使用的文件 git diff --ours #合并前比較結果與在你的分支上的內容,換一句話說,看看合并引入了什么 git diff --base #查看文件在兩邊是如何改動的 git checkout --conflict=diff3 hello.rb #重新檢出文件并替換合并沖突標記 git config --global merge.conflictstyle diff3 #通過設置 merge.conflictstyle 選項為 diff3 來做為以后合并沖突的默認選項 git log --oneline --left-right HEAD...MERGE_HEAD #得到此次合并中包含的每一個分支的所有獨立提交的列表 git log --oneline --left-right --merge #只顯示任何一邊接觸了合并沖突文件的提交 git revert -m 1 HEAD #-m 1 標記指出 “mainline” 需要被保留下來的父結點 git merge -Xours [branch_name] #選擇特定的一邊Ours并忽略另外一邊Theirs而不是讓你手動合并沖突 git merge-file --ours #合并單個文件8 rerere
git rerere功能是一個隱藏的功能。正如它的名字 "reuse recorded resolution" 所指,它允許你讓 Git 記住解決一個塊沖突的方法,這樣在下一次看到相同沖突時,Git 可以為你自動地解決它。為了啟用 rerere 功能,僅僅需要運行這個配置選項:git config --global rerere.enabled true也通過在特定的倉庫中創建 .git/rr-cache 目錄來開啟它,但是設置選項更干凈并且可以應用到全局。
9 打包
git bundle create repo.bundle HEAD master #打包,如果你在打包時沒有包含 HEAD 引用,你還需要在命令后指定一個 -b master 或者其他被引入的分支,否則Git 不知道應該檢出哪一個分支 git clone repo.bundle repo #解包 git bundle create commits.bundle master #獲取在我們的 master 分支而不在原始倉庫中的提交10 文件標注
git blame -L 12,22 simplegit.rb #文件標注,展示文件中每一行最后一次修改的提交 -L 選項來限制輸出范圍在第12至22行 git blame -C -L 141,153 GITPackUpload.m #在 git blame 后面加上一個-C,Git 會分析你正在標注的文件,并且嘗試找出文件中從別的地方復制過來的代碼片段的原始出處小注
本文對個人用戶基本用不到的鉤子、合并樹、憑證管理、搭建Git倉庫、底層命令等內容沒做總結,用到時可以直接閱讀原文。二八原則,掌握80%常用的內容就可以熟練運用Git,有需要的時候再繼續深入。最后,最好的學習方法就是實踐實踐再實踐,一定要多思考多實踐。
參考文獻
[1] ProGit Version 2. Scott Chacon and Ben Straub.
[2] Git權威指南. 蔣鑫.
[3] 阮一峰的網絡日志。
總結
以上是生活随笔為你收集整理的ProGit-读书简记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2013cvpr的总结
- 下一篇: 鱼眼校正之类1