* [[https://backlogtool.com/git-guide/tw/|連猴子都能懂的Git入門指南]] * [[https://gitbook.tw/|為你自己學 Git]] * [[https://ihower.tw/git/|Git 版本控制系統]] * [[http://sethrobertson.github.io/GitFixUm/fixup.html|On undoing, fixing, or removing commits in git]] 先設定環境帳號。請見 * [[http://plog.longwin.com.tw/my_note-unix/2009/05/15/git-initial-env-setup-2009|Git 基礎設定 (帳號的環境參數設定)]]。 * [[http://blog.gogojimmy.net/2012/01/17/how-to-use-git-1-git-basic/|Git 教學(1) : Git 的基本使用]] # 設定都存放在 ~/.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 基礎知識請見 [[http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=giteveryone-101022053442-phpapp02|寫給大家的 Git 教學]]。 * [[https://gitbook.tw/chapters/using-git/working-staging-and-repository.html|工作區、暫存區與儲存庫]] {{https://gitbook.tw/images/using-git/working-staging-and-repository/all-states.png?500}} * [[https://gitbook.tw/chapters/gitflow/why-need-git-flow.html|Git Flow 是什麼?為什麼需要這種東西?]] * [[https://about.gitlab.com/2016/10/25/gitlab-workflow-an-overview/|GitLab Workflow: An Overview]] * [[https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow|Gitflow Workflow]] * [[http://www.devops-blog.net/git/git-flow-how-its-used-and-why-you-should|Git-Flow | How it’s used and why you should]] ====== 初始設定 ====== * [[http://sweetme.at/2013/09/13/git-logs-with-color/|Git Logs With Color and Graphs]] * [[http://codeinthehole.com/writing/a-useful-template-for-commit-messages/|A useful template for commit messages]] * [[https://chris.beams.io/posts/git-commit/|How to Write a Git Commit Message]] $ 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 主要用來和上游同步。 * [[https://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging/|3.2 Git Branching - Basic Branching and Merging]] * [[https://www.digitalocean.com/community/tutorials/how-to-use-git-branches|How To Use Git Branches]] * [[http://stackoverflow.com/questions/5531362/why-git-keeps-showing-my-changes-when-i-switch-branches-modified-added-deleted|Why git keeps showing my changes when I switch branches (modified,added, deleted files) no matter if I run git add or not?]] * [[http://stackoverflow.com/questions/16329776/how-to-keep-a-git-branch-in-sync-with-master|How to keep a git branch in sync with master]] $ git branch -b dev ====== 切換分支 ====== * 避免切換分支時,將分支 dev 未 commit 的修改帶到分支 master。 * [[https://git-scm.com/book/en/v1/Git-Tools-Stashing|6.3 Git Tools - Stashing]] $ 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 負責跟上游同步。 * [[https://git-scm.com/book/en/v2/Git-Branching-Rebasing|3.6 Git Branching - Rebasing]] * [[https://blog.yorkxin.org/2011/07/29/git-rebase|Git-rebase 小筆記]] $ git checkout master $ git pull $ git checkout dev $ git rebase master ====== 合併提交 ====== * 在分支 dev 上開發,最後將數個 commit 合併成一個 commit 給 reviewer/committer 審閱。 * [[http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html|squashing commits with rebase]] * [[https://ariejan.net/2011/07/05/git-squash-your-latests-commits-into-one/|Git: Squash your latests commits into one]] $ git rebase -i HEAD~4 # 合併最近 4 個 commit ====== 分割提交 ====== * 避免單一 commit 過大,將其分割成數個 commit,各自相對獨立且可測試。 * [[https://emmanuelbernard.com/blog/2014/04/14/split-a-commit-in-two-with-git/|Split a commit in two with Git]] * [[http://stackoverflow.com/questions/4307095/how-can-i-split-up-a-git-commit-buried-in-history|How can I split up a Git commit buried in history?]] ====== 修改提交訊息或內容 ====== * [[http://stackoverflow.com/questions/179123/how-to-modify-existing-unpushed-commits|How to modify existing, unpushed commits?]] * [[https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History|7.6 Git Tools - Rewriting History]] * [[https://ihower.tw/blog/archives/2622|Git 版本控制系統(3) 還沒 push 前可以做的事]] $ git commit --amend # 修改最近一個 commit 的訊息 ====== 刪除提交 ====== * git revert 和 git reset 作用方式不同。git reset 只用在私人分支,git revert 只用在公共分支。 * [[https://www.atlassian.com/git/tutorials/resetting-checking-out-and-reverting|Reset, Checkout, and Revert]] * [[https://www.atlassian.com/git/tutorials/undoing-changes|Undoing Changes]] * [[http://stackoverflow.com/questions/4850717/how-to-cancel-a-local-git-commit|How to cancel a local git commit]] * [[http://stackoverflow.com/questions/927358/how-to-undo-last-commits-in-git|How to undo last commit(s) in Git?]] * [[http://stackoverflow.com/questions/1338728/delete-commits-from-a-branch-in-git|Delete commits from a branch in Git]] $ git reset HEAD~1 # 刪除最近一個 commit,其內容會保留在當前的工作目錄。 # 修改被刪除的最近一個 commit 內容。 $ git commit -c ORIG_HEAD # 重新 commit 被刪除的最近一個 commit,沿用原本的 commit message。 $ git reset --hard HEAD~1 # 刪除最近一個 commit,不保留其內容。 ====== 子模組 ====== * [[https://git-scm.com/book/zh-tw/v1/Git-%E5%B7%A5%E5%85%B7-%E5%AD%90%E6%A8%A1%E7%B5%84-Submodules|6 Git 工具 - 子模組 (Submodules)]] * `git submodule update --init` 下載之後,進入 submodule 會發現它們不在各自的 master branch。這是因為基本上 parent repo 只用 commit 號來認這些 submodule。 * [[http://josephj.com/entry.php?id=357|Git Submodule 的常見錯誤]] * [[https://yodalee.blogspot.com/2018/01/git-submodule.html|使用 git submodule 管理 project 所需的其他模組]] * [[https://blog.wu-boy.com/2011/09/introduction-to-git-submodule/|Git Submodule 介紹與使用]] ====== 發送補丁 ====== * [[http://alblue.bandlem.com/2011/12/git-tip-of-week-patches-by-email.html|Git Tip of the Week: Patches by Email]] * [[https://git-scm.com/blog/2010/03/10/bundles.html|Git's Little Bundle of Joy]] * [[http://stackoverflow.com/questions/3635952/how-to-use-git-bundle-for-keeping-development-in-sync|How to use git-bundle for keeping development in sync?]] $ 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 * [[http://crazycode.iteye.com/blog/311564|使用git bisect快速定位引入错误的版本]] * [[http://lists.gnu.org/archive/html/qemu-devel/2012-02/msg02856.html|[Qemu-devel] [PATCH] Fix dependency issue introduced by commit 7b93fadf3a38d1ed65ea5536a52efc2772c6e3b8]] * [[http://lists.gnu.org/archive/html/qemu-devel/2012-02/msg02917.html|[Qemu-devel] [PATCH v2] Fix dependency issue introduced by commit 7b93fadf3a38d1ed65ea5536a52efc2772c6e3b8]] ====== 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 * [[http://ariejan.net/2009/10/26/how-to-create-and-apply-a-patch-with-git/|How to create and apply a patch with Git]] * [[http://blog.longwin.com.tw/2009/05/git-send-patch-commit-use-email-2009/|Git 透過 Email 傳送 Patch / Commit]] * [[http://morefedora.blogspot.com/2009/02/configuring-git-send-email-to-use-gmail.html|Configuring git send-email to use Gmail SMTP]] * [[http://weylan.blog.edu.cn/2010/546263.html|git-sendmail 好方便]] * [[http://felipec.wordpress.com/2009/10/25/git-send-email-tricks/|git send-email tricks]] * [[http://people.debian.org.tw/~chihchun/2010/12/01/sending-patch-with-git-imap-send/|用 git-imap-send 送 patch]] * [[http://search.cpan.org/~pmakholm/Encode-IMAPUTF7-1.05/lib/Encode/IMAPUTF7.pm|Encode::IMAPUTF7 ]] * [[http://webcache.googleusercontent.com/search?q=cache:uFhyPoLv9lkJ:blog.rmi.twbbs.org/2010/02/gmail-git-email-git-send-email-smtp.html+&cd=2&hl=zh-TW&ct=clnk|使用 gmail 做為 git-email (git-send-email) 的 smtp server]] * [[http://elinux.org/Git_usage#send-email|Git usage]] * [[http://oss.oracle.com/osswiki/GitRepositories|Git Repositories on oss.oracle.com]] * [[http://linux.die.net/man/1/git-format-patch|git-format-patch]] * [[http://wiki.qemu.org/Contribute/SubmitAPatch|SubmitAPatch]] * [[https://lists.gnu.org/archive/html/qemu-devel/2011-09/msg02786.html|[Qemu-devel] [PATCH] exec.c: Remove useless comment]] * [[https://lists.gnu.org/archive/html/qemu-trivial/2011-10/msg00059.html|[Qemu-trivial] [PATCH] exec.c: Remove useless comment ]] * [[http://lists.nongnu.org/archive/html/qemu-devel/2011-10/msg03163.html|Re : [Qemu-devel] [Qemu-trivial] [PATCH] exec.c: Remove useless comment]] * [[http://lists.gnu.org/archive/html/qemu-devel/2011-11/msg01025.html|Re: [Qemu-devel] [PATCH 0/6] Remove libqemu related stuff from QEMU source tree]] * [[http://lists.gnu.org/archive/html/qemu-devel/2011-11/msg01549.html|[Qemu-devel] [PATCH 0/6 v2] Remove libqemu related stuff from QEMU source tree]] * [[http://lists.gnu.org/archive/html/qemu-devel/2011-11/msg02038.html|[Qemu-devel] [PATCH v3 0/6] Remove libqemu related stuff from QEMU source tree]] * [[http://lists.nongnu.org/archive/html/qemu-trivial/2011-11/msg00036.html|[Qemu-trivial] [PATCH] linux-user/main.c: Add option to user-mode emulation so that user can specify log file name]] * qemu-trivial@nongnu.org * [[http://lists.gnu.org/archive/html/qemu-devel/2012-05/msg01958.html|[Qemu-devel] Posting a patch?]] * [[http://lists.gnu.org/archive/html/qemu-devel/2011-11/msg01989.html|[Qemu-devel] [PATCH v5 1.0] configure: build position independent executables across for x86 hosts]] * [[http://lists.gnu.org/archive/html/qemu-devel/2011-11/msg00117.html|[Qemu-devel] [PATCH v4 0/4] -net bridge: rootless bridge support for qemu]] * 學怎麼寫 v? 的不同。 * 單一 patch 在 "---" 後加上 v? 的說明。 Signed-off-by: Avi Kivity --- 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 * [[http://osdir.com/ml/git/2009-09/msg01492.html|'git am' doubt]] * [[http://linux.yyz.us/git-howto.html|Kernel Hackers' Guide to git]] ====== 常用 Git 服務 ====== * [[https://www.gerritcodereview.com/|Gerrit]] * rebase 保留舊有的 Changed-Id,就會維持在同一個 code review。 * [[https://www.phacility.com/|Phabricator]] ===== GitHub ===== 建議邊閱讀邊實際操作。 * [[https://guides.github.com/activities/hello-world/|Hello World 10 minute read]] * [[https://help.github.com/articles/which-remote-url-should-i-use/|Which remote URL should I use?]] * 官方建議使用 HTTPS clone repository。如果不想重複輸入帳號密碼,請見 [[https://help.github.com/articles/caching-your-github-password-in-git|Caching your GitHub password in Git]]。 $ git config --global credential.helper osxkeychain * [[http://hisham.hm/2016/01/01/how-to-make-a-pull-request-on-github-a-quick-tutorial/|How to make a pull request on GitHub - a quick tutorial]] * 利用 pull request 貢獻代碼到別人的 repository。 * [[https://www.peterdavehello.org/2014/02/update_forked_repository/|更新從 GitHub 上 fork 出來的 repository (或是同步兩個不同 server 端的 repository)]] * 發起 pull request 要先 fork 別人的 repository。 * [[https://gist.github.com/longtimeago/f7055aa4c3bba8a62197|How to squash commits in a GitHub pull request]] * 如果已經發送 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 * [[https://www.smashingmagazine.com/2014/08/build-blog-jekyll-github-pages/|Build A Blog With Jekyll And GitHub Pages]] * 透過網頁介面 commit ''_config.yml'' 觸發 GitHub 產生頁面。 * [[https://help.github.com/articles/what-is-github-pages/|What is GitHub Pages?]] * [[https://medium.com/@cwRichardKim/put-your-resume-pdf-on-a-website-that-updates-automatically-242ef7d023ec#.oyl0ieyod|Put your resume.pdf on a website that updates automatically]] * 將履歷放上 GitHub,統一維護。 * gh-page 設定好之後,只需更新 master 分支上的履歷。 * [[https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/|Adding an existing project to GitHub using the command line]] * 在 GitHub 上新建一個不含任何檔案的 repository,會跳出操作提示頁面。 ===== GitLab ===== * [[https://about.gitlab.com/|GitLab]] * [[https://www.youtube.com/watch?v=enMumwvLAug|Introduction to GitLab Workflow]] * [[https://about.gitlab.com/2016/10/25/gitlab-workflow-an-overview/|GitLab Workflow: An Overview]] * [[https://docs.gitlab.com/ce/workflow/README.html|Workflow - GitLab Document]] * 提供 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。 * [[https://medium.com/fcamels-notes/%E4%BD%BF%E7%94%A8-phabricaor-%E7%9A%84%E5%B7%A5%E4%BD%9C%E6%B5%81%E7%A8%8B-5247b04dd871|使用 Phabricator 的工作流程]] * [[https://willdemaine.ghost.io/a-simpler-phabricator-stacked-diff-workflow/|A Simpler Phabricator Stacked Diff Workflow]] * [[https://smacleod.ca/posts/commit-series-with-phabricator/|Commit Series with Phabricator]] * [[https://medium.com/@kurtisnusbaum/stacked-diffs-keeping-phabricator-diffs-small-d9964f4dcfa6| Stacked Diffs: Keeping Phabricator Diffs Small]] * 一個 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 ====== 外部連結 ====== * [[http://stackoverflow.com/questions/115983/how-do-i-add-an-empty-directory-to-a-git-repository|How do I add an empty directory to a git repository]] * [[http://www.youtube.com/watch?v=j45cs5_nY2k|Contributing with Git]] * [[http://blog.longwin.com.tw/2009/01/how-send-code-into-open-source-project-diff-patch-2009/|好文: 如何將程式送給 Open Source 的 Project 與 diff / patch 使用]] * [[http://ihower.tw/blog/archives/6696/|Git 教育訓練課程投影片]]