先設定環境帳號。請見
# 設定都存放在 ~/.gitconfig $ git config --global user.name "陳韋任 (Wei-Ren Chen)" $ git config --global user.email chenwj.cs97g@g2.nctu.edu.tw
origin(remote) 是遠端伺服器上的倉儲; master(branch) 是本地端正在修改的分支,master 是預設的分支名稱。關於 Git 基礎知識請見 寫給大家的 Git 教學。
初始設定
$ git config --global alias.lg "log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative"
創建分支
- 預設分支為 master,建立額外分支 dev,並在分支 dev 上開發,避免在 master 上進行試驗性改動。分支 master 主要用來和上游同步。
$ git branch -b dev
切換分支
- 避免切換分支時,將分支 dev 未 commit 的修改帶到分支 master。
$ git stash $ git checkout master $ git checkout dev $ git stash pop
刪除分支
- 分支 dev 合入 master,刪除分支 dev。
$ git branch -D dev
加入提交
$ git add -u :/
重定基準
- 建議先將分支 dev 基於分支 master 做 rebase,再做後續的合併提交。分支 master 負責跟上游同步。
$ git checkout master $ git pull $ git checkout dev $ git rebase master
合併提交
- 在分支 dev 上開發,最後將數個 commit 合併成一個 commit 給 reviewer/committer 審閱。
$ git rebase -i HEAD~4 # 合併最近 4 個 commit
分割提交
- 避免單一 commit 過大,將其分割成數個 commit,各自相對獨立且可測試。
修改提交訊息或內容
$ git commit --amend # 修改最近一個 commit 的訊息
刪除提交
- git revert 和 git reset 作用方式不同。git reset 只用在私人分支,git revert 只用在公共分支。
$ git reset HEAD~1 # 刪除最近一個 commit,其內容會保留在當前的工作目錄。 # 修改被刪除的最近一個 commit 內容。 $ git commit -c ORIG_HEAD # 重新 commit 被刪除的最近一個 commit,沿用原本的 commit message。 $ git reset --hard HEAD~1 # 刪除最近一個 commit,不保留其內容。
子模組
-
- `git submodule update –init` 下載之後,進入 submodule 會發現它們不在各自的 master branch。這是因為基本上 parent repo 只用 commit 號來認這些 submodule。
發送補丁
$ git bundle create commits.bundle commit_id..master # commit_id 之後包含你想要打包的 commit。 # 透過 email 或是 usb 傳送給對方。 $ git remote add commits /path/to/commits.bundle # 添加來自 commmits.bundle 的 remote。 $ git pull commits dev # 如果對方是在分支 dev 打包 bundle,則指從分支 dev pull。
Bisect
$ git clone git://git.qemu.org/qemu.git # 开始 git bisect。 $ git bisect start # 标记当前版本为错误。 $ git bisect bad # 標記一個只知好的版本,git 會自動選出一個中間版本,重新開始測試。 $ git bisect good v1.0.1 # 測試通過,標記為 good,選下一個中間版本。如果失敗,標記成 bad,選下一個中間版本。 $ git bisect good # 顯示引入錯誤的 commit 其內容。 $ git show 7b93fadf3a38d1ed65ea5536a52efc2772c6e3b8 ... 定位到引入錯誤的 commit,修正 ... # 返回到当前的 HEAD。 $ git bisect reset
Submit Patch
# git clone git://repo.or.cz/qemu.git $ git clone git://git.qemu.org/qemu.git $ cd qemu # 建立新的 branch,之後會自動生成 a 和 b 的 diff。 $ git checkout -b b ... 修改檔案 ... # 生成單一 patch $ git commit -a -m "exec.c: Remove useless comment" # 此訊息會是之後信件的 subject # 生成多個 patch。google git split patch $ git commit exec.c -m "exec.c: Make variable logfilename accessible from linux-user/main.c" $ git commit linux-user/main.c -m "linux-user/main.c: Add option to user-mode emulation so that user can specify log file name" $ git fetch origin $ git rebase origin # 產生單一 patch $ git format-patch -s origin --stdout > ../b.patch $ mutt -H b.patch # 產生多個 patch。--cover-letter 會產生 patchset 的第一封信,應該用來描述 patchset 的大致用途。 $ git format-patch -s origin --cover-letter -o tmp; cd tmp # 書寫 patch set 的開頭第一封信,並依序填寫 patch set 的內文解釋 patch。 # --compose 內文為空,沒有任何跟 patchset 有關的東西,和 cover letter 不一樣。 # 可以直接用 vim 修改 patch,且之前修改的內容都會留下。 # # 建議先改完,在 git send-email --annotate --suppress-from --to user@example.com * 一次送出。 # $ git send-email --annotate --suppress-from --to user@example.com 0000-cover-letter.patch Subject: [Qemu-trivial][PATCH 0/2] Add option to user-mode emulation so that user can specify log file name QEMU user-mode's default log file name is "/tmp/qemu.log". In order to change the log file name, user need to modify the source code then recompile QEMU. This patchset allow user use "-D filename" option to specify the log file name. Chen Wen-Ren (2): exec.c: Make variable logfilename accessible from linux-user/main.c linux-user/main.c: Add option to user-mode emulation so that user can specify log file name exec.c | 2 +- linux-user/main.c | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletions(-) -- 1.7.3.5
# 會送到 gmail 草稿夾 $ git format-patch --attach --stdout origin | git imap-send
-
- qemu-trivial@nongnu.org
-
- 學怎麼寫 v? 的不同。
- 單一 patch 在 "—" 後加上 v? 的說明。
Signed-off-by: Avi Kivity <address@hidden> --- v5: fix typos; only default enable for x86; mutually exclusive with -static v4: say it's v4 and for 1.0 v3: detect toolchain support for PIE at configure time v2: improve description to include relro
- 多個 patch,在 cover letter 上加上 v? 的說明。
v4: - Update has_vnet_hdr() to return bool - Update helper's main() to prevent errno clobbering - Let Kernel cleanup helper's file descriptors Corey Bryant (4): Add basic version of bridge helper Add access control support to qemu bridge helper Add cap reduction support to enable use as SUID Add support for net bridge
Apply Patch
# 查看 patch 但不 apply $ git apply --stat b.patch exec.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) # apply patch $ git apply --check b.patch # 保留 patch 的資訊 $ git am --signoff b.patch $ git log
# 使用 mutt 把包含 patch 的 mail 存到 mbox,下 s。例如存到 qemu-patch。 $ git am --utf8 --signoff ../qemu-patch cat: /z/tmp/chenwj/qemu/.git/rebase-apply/last: No such file or directory previous rebase directory /z/tmp/chenwj/qemu/.git/rebase-apply still exists but mbox given. $ git am --abort $ git am --utf8 --signoff ../qemu-patch
常用 Git 服務
-
- rebase 保留舊有的 Changed-Id,就會維持在同一個 code review。
GitHub
建議邊閱讀邊實際操作。
-
-
- 官方建議使用 HTTPS clone repository。如果不想重複輸入帳號密碼,請見 Caching your GitHub password in Git。
$ git config --global credential.helper osxkeychain
-
-
- 利用 pull request 貢獻代碼到別人的 repository。
-
- 發起 pull request 要先 fork 別人的 repository。
-
- 如果已經發送 pull request 的 commit 需要修改,一般會透過 squash 將更新的 commit 和原來已發送 pull request 的 commit 合併。流程如下:
# 和上游同步 $ git fetch upstream # 切換到自己的分支 $ git checkout b $ git rebase -i upstream/master # 修改後,透過 git rebase -i HEAD~2 squash commit # 覆寫自己 GitHub 上的分支 b。之前已發送的 pull request 會自動更新。 $ git push origin b -f
-
- 透過網頁介面 commit
_config.yml
觸發 GitHub 產生頁面。
-
- 將履歷放上 GitHub,統一維護。
- gh-page 設定好之後,只需更新 master 分支上的履歷。
-
- 在 GitHub 上新建一個不含任何檔案的 repository,會跳出操作提示頁面。
GitLab
-
- 提供 code review, issue tracker 和 wiki。
流程:
- 開 issue
- 開 branch
- git clone branch; git push; git push -f (類似 gerrit changed-id 的效果)
- 送 merge request
Phabricator
Phabricator 基本上一個 revision 就是一個 commit。如果當前任務需要多個 commit 完成,創建 dependent revision。
- 一個 branch,一個 commit,一個 review 單。
# 依賴關係: master -> ref_abc -> fix_abc (master) $ git checkout -b ref_abc (ref_abc) $ git commit (ref_abc) $ git checkout -b fix_abc (fix_abc) $ git commit (fix_abc) $ git checkout ref_abc (ref_abc) $ arc diff master # D1 (ref_abc) $ git checkout fix_abc (fix_abc) $ arc diff ref_abc # D2
- 更新 review 單。
(master) $ git checkout ref_abc (ref_abc) $ git pull --rebase origin master (ref_abc) $ git submodule update (ref_abc) $ git commit -a --amend (ref_abc) $ arc diff master --update D1 (ref_abc) $ git checkout fix_abc (fix_abc) $ git pull --rebase . ref_abc (fix_abc) $ git commit -a --amend (fix_abc) $ arc diff ref_abc --update D2
- approve 之後,由前往後依序合入代碼。
(master) $ git checkout ref_abc (ref_abc) $ arc land --onto master --revision D1 --merge (ref_abc) $ git checkout fix_abc (fix_abc) $ arc land --onto master --revision D2 --merge