<!-- .slide: data-background="#dfdfdf" --> # Git 深入淺出 ###### 04.09 鄭余玄 --- <!-- .slide: data-background="#dfdfdf" --> # Git 版本控制摘要 ![](https://i.imgur.com/trI58kW.png) ---- <!-- .slide: data-background="#dfdfdf" --> ## 常見版本管理系統 - **分散式** - **Git** - TFS (Team Foundation Server) - 集中式 - CVS, SVN ---- <!-- .slide: data-background="#dfdfdf" --> ## 本地端版本管理 ![](https://i.imgur.com/dJy4I0B.png) ---- <!-- .slide: data-background="#dfdfdf" --> ## 分散式版本管理 ![](https://i.imgur.com/6kXfSEp.png) --- <!-- .slide: data-background="#dfdfdf" --> # Git 環境設定 ---- <!-- .slide: data-background="#dfdfdf" --> ## git config - ```--local```: ```.git/config``` - ```--global```: ```~/.gitconfig``` - ```--system```: ```/etc/gitconfig``` ```bash git config --global color.ui auto git config --global log.abbrevCommit yes git config --global core.editor vim git config --global credential.https://github.com.使用者名稱 使用者名稱 git config --global credential.helper 'cache --timeout=3600' ``` - 預設編輯器:```vi``` - 環境參數:```GIT_EDITOR```, ```EDITOR```, ```VISUAL``` <!-- .element: class="fragment" data-fragment-index="1" --> ---- <!-- .slide: data-background="#dfdfdf" --> ## 憑證儲存 ``` git config --global credential.https://github.com.使用者名稱 使用者名稱 git config --global credential.helper 'cache --timeout=3600' ``` ---- <!-- .slide: data-background="#dfdfdf" --> ## alias ```bash git config --global alias.co checkout git config --global alias.br branch git config --global alias.ci commit git config --global alias.st status ``` - [Lesser known Git commands](https://hackernoon.com/lesser-known-git-commands-151a1918a60) - [Stop Aliasing Your Git Commands](https://shift.infinite.red/stop-aliasing-your-git-commands-248dace51f7c) ---- <!-- .slide: data-background="#dfdfdf" --> ## .gitignore - Lists all ignored files in this project. ```git ls-files --other --ignored --exclude-standard``` ---- <!-- .slide: data-background="#dfdfdf" --> ## .gitattribute ---- <!-- .slide: data-background="#dfdfdf" --> ## .gitkeep - git add 空資料夾 ---- <!-- .slide: data-background="#dfdfdf" --> ## ```vim``` - ```i``` 編輯模式 - ```:wq``` 存檔離開 --- <!-- .slide: data-background="#dfdfdf" --> # 程式碼倉儲 ## Repository ---- <!-- .slide: data-background="#dfdfdf" --> ## Commit 提交 - tree(專案結構) - author 作者資訊 - committer 提交者資訊 - commit message - parent commit ---- <!-- .slide: data-background="#dfdfdf" --> ## Object Store ![](https://i.imgur.com/XiDeOWG.png) - Blob, Tree, Commit, Tag - ```.git/``` 儲存元數據與資料庫 ---- <!-- .slide: data-background="#dfdfdf" --> ## Object IDs - SHA-1 - 根據檔案內容計算出幾乎唯一的檔案指紋 - [SHA-1 conflict](https://github.com/blog/2338-sha-1-collision-detection-on-github-com) ---- <!-- .slide: data-background="#dfdfdf" --> ## Refs - 一般 ref - 直接指向 object ID(通常是 commit 或 tag) - ex: ```refs/tags```, ```refs/heads``` - 符號 ref(symref) - 指向其他 ref ![](https://i.imgur.com/hdYCfqG.png) ---- <!-- .slide: data-background="#dfdfdf" --> ## ```HEAD``` - 指向當前分支最後 commit 的 ref - 簡而言之,就是最近一次的 commit - 下一次 commit 會指向現在的 ```HEAD``` ---- <!-- .slide: data-background="#dfdfdf" --> ## Treeish - 完整 SHA1 / 部份 SHA1 - ```bae865``` - 分支、Tag - ```master``` - 日期 - ```master@{yesterday}``` - ```master@{1 month ago}``` - 序數(前面第 n 個) - ```master@{5}``` ---- <!-- .slide: data-background="#dfdfdf" --> ## Treeish - Carrot Parent(第 n 個父節點) - ```master^2``` - 波浪號(第 n 個祖先) - ```master~5```,等同 ```master^^^^^``` ![](https://i.imgur.com/nR9RgoM.png) ---- <!-- .slide: data-background="#dfdfdf" --> # Repo 範例 ---- <!-- .slide: data-background="#dfdfdf" --> ![](https://i.imgur.com/eHrkKB6.png) ![](https://i.imgur.com/EDJszc9.png) ---- <!-- .slide: data-background="#dfdfdf" --> ![](https://i.imgur.com/BnuxLmR.png) ![](https://i.imgur.com/ajcLGll.png) ---- <!-- .slide: data-background="#dfdfdf" --> ![](https://i.imgur.com/s2hm6mM.png) ![](https://i.imgur.com/AvxL2tj.png) ---- <!-- .slide: data-background="#dfdfdf" --> ## History - DAG 有向無環圖 ![](https://i.imgur.com/FZGEU8N.png) ---- <!-- .slide: data-background="#dfdfdf" --> ## Traserval --- <!-- .slide: data-background="#dfdfdf" --> # 提交變更 ## Making Commit ---- <!-- .slide: data-background="#dfdfdf" --> ## ```git add``` - ```-p, --patch``` 部份預存 - ```-i, --interactive``` 互動式提交 ---- <!-- .slide: data-background="#dfdfdf" --> ## 追蹤相同檔案 - ```git rm 檔案``` 刪除檔案 - ```git mv 舊檔名 新檔名``` 重新命名檔案 ---- <!-- .slide: data-background="#dfdfdf" --> ## ```git commit``` - ```-a``` - good commit message ![](https://i.imgur.com/MxNaSn3.png) ---- <!-- .slide: data-background="#dfdfdf" --> ## ```git tag``` - 顯示 tag - ```git tag``` - ```git tag -l "v1.8.7*"``` - ```git show 標籤``` - 加 tag - ```git tag 標籤``` - ```git tag -a 標籤 -m 訊息``` ---- <!-- .slide: data-background="#dfdfdf" --> ## Working Directory ---- <!-- .slide: data-background="#dfdfdf" --> ## Index - 早期叫做 cache ---- <!-- .slide: data-background="#dfdfdf" --> # 工作流程範例 ---- <!-- .slide: data-background="#dfdfdf" --> ## ```git add``` ![](https://i.imgur.com/SOHYtC3.png) ![](https://i.imgur.com/XWgAY8I.png) ---- <!-- .slide: data-background="#dfdfdf" --> ## ```git commit``` ![](https://i.imgur.com/KTDWKS1.png) ---- <!-- .slide: data-background="#dfdfdf" --> ## 編輯檔案 ![](https://i.imgur.com/yJmQ090.png) ---- <!-- .slide: data-background="#dfdfdf" --> ## ```git add``` ![](https://i.imgur.com/gJNy2aE.png) ---- <!-- .slide: data-background="#dfdfdf" --> ## ```git commit``` ![](https://i.imgur.com/n8mN0Ow.png) --- <!-- .slide: data-background="#dfdfdf" --> # 還原變更 ## Roll Back ---- <!-- .slide: data-background="#dfdfdf" --> ![](https://i.imgur.com/sISR7aI.png) ---- <!-- .slide: data-background="#dfdfdf" --> ## ```git revert 提交``` - 還原特定提交 --- <!-- .slide: data-background="#dfdfdf" --> ## Reset - 還原前 n 次提交 - ```git reset --模式 提交``` 1. 移動 ```HEAD``` **指向**的 ref (```--soft```) 2. Index (```--mixed```) 3. Work Directory (```--hard```) ![](https://i.imgur.com/i2nIFqU.png) ---- <!-- .slide: data-background="#dfdfdf" --> ## ```git reset --soft 提交``` ![](https://i.imgur.com/7QrLMkL.png) ---- <!-- .slide: data-background="#dfdfdf" --> ## ```git reset 提交``` - ```git reset (--mixed) 提交``` ![](https://i.imgur.com/2sui0jX.png) ---- <!-- .slide: data-background="#dfdfdf" --> ## ```git reset --hard 提交``` ![](https://i.imgur.com/NMGJQuM.png) ---- <!-- .slide: data-background="#dfdfdf" --> ## ```git reset 檔案``` - ```git reset --mixed HEAD 檔案``` - 與 ```git add 檔案``` 相反 - 取消預存到編輯區 1. 移動 ```HEAD``` 指向的 ref 到 ```HEAD``` (不動作) 2. Index ---- <!-- .slide: data-background="#dfdfdf" --> ## ```git reset 檔案``` ![](https://i.imgur.com/Cln9q5T.png) ---- <!-- .slide: data-background="#dfdfdf" --> ## ```git reset 提交 檔案``` ![](https://i.imgur.com/09kBfCC.png) ---- <!-- .slide: data-background="#dfdfdf" --> ## ```git reset -p 檔案``` - ```-p, --patch``` 部份還原 - 與 ```git add -p 檔案``` 相反 --- <!-- .slide: data-background="#dfdfdf" --> ## Checkout 1. 移動 HEAD 2. Index 3. Work Directory ---- <!-- .slide: data-background="#dfdfdf" --> ## ```git checkout 分支``` - **安全**的指令,基本上*類似* ```reset --hard``` - 簡易 merge,更新未變更檔案 ---- <!-- .slide: data-background="#dfdfdf" --> ## 移動 ```HEAD``` ![](https://i.imgur.com/ZaF5s5n.png) ---- <!-- .slide: data-background="#dfdfdf" --> ## ```git checkout 提交``` - DETACHED HEAD ---- <!-- .slide: data-background="#dfdfdf" --> ## ```git checkout 檔案``` - ```git checkout (提交) 檔案``` ![](https://i.imgur.com/mawd59H.png) ---- <!-- .slide: data-background="#dfdfdf" --> ## ```git checkout -p 檔案``` - ```-p, --patch``` 部份還原 ---- <!-- .slide: data-background="#dfdfdf" --> ## 還原提交比較 | | HEAD | Index | Workdir | WD Safe? | |----------------------------|------|-------|---------|----------| | ```reset --soft 提交``` | REF | - | - | v | | ```reset 提交``` | REF | v | - | v | | ```reset --hard 提交``` | REF | v | v | **No** | | ```checkout 提交``` | HEAD | v | v | v | ---- <!-- .slide: data-background="#dfdfdf" --> ## 還原檔案比較 | | HEAD | Index | Workdir | WD Safe? | |----------------------------|------|-------|---------|----------| | ```reset 檔案``` | - | v | - | v | | ```checkout 檔案``` | - | v | v | **NO** | --- <!-- .slide: data-background="#dfdfdf" --> # 分支 ![](https://i.imgur.com/7OXNKIV.png) ---- <!-- .slide: data-background="#dfdfdf" --> ## ```git branch``` - 顯示分支 - ```git branch``` - ```git branch -vv``` - 新增分支 - ```git branch 分支名稱``` - ```git checkout -b 分支名稱``` - 刪除分支 - ```git branch -d 分支名稱``` ---- <!-- .slide: data-background="#dfdfdf" --> # 合併 ## Merge ---- <!-- .slide: data-background="#dfdfdf" --> ## Fast Forward ![](https://i.imgur.com/Q1KJO1P.png) ---- <!-- .slide: data-background="#dfdfdf" --> ## 3-way merge ![](https://i.imgur.com/MggTlWq.png) ---- <!-- .slide: data-background="#dfdfdf" --> ## Fast Forward ![](https://cdn-images-1.medium.com/max/800/1*QXa3znQiuNWDjxroX628VA.gif) --- <!-- .slide: data-background="#dfdfdf" --> # 追蹤遠端 ## Tracking Remote ---- <!-- .slide: data-background="#dfdfdf" --> ## ```git clone 網址``` 1. 建立一個新 repo 2. 新增並指向 ```origin``` 遠端 ``` [remote "origin"] fetch = +refs/heads/*:refs/remotes/origin/* url = server:dir/repo ``` ---- <!-- .slide: data-background="#dfdfdf" --> ## ```git fetch 遠端 分支``` - 與遠端同步 git 資料庫 - 不影響 ```Work Directory```, ```Index```, ```Head``` ---- <!-- .slide: data-background="#dfdfdf" --> ## ```git pull 遠端``` - ```fetch``` 後 ```merge``` ``` git fetch 遠端 git merge origin/當前分支. ``` ![](https://cdn-images-1.medium.com/max/800/1*IxDdJ5CygvSWdD8MCNpZNg.gif) ---- <!-- .slide: data-background="#dfdfdf" --> ## ```git push 遠端 分支``` - ```-u``` 設定 upstream - 只接受 fast-forward merge - ```--force``` *危險*,覆寫歷史 - ```--all``` 所有分支 - ```--tags``` ---- <!-- .slide: data-background="#dfdfdf" --> ## ```push.default``` - matching - 所有本地和遠端有相同名稱的分支 - upstream - 當前分支到 upstream - **simple** - 當前分支到同名稱 upstream - current - 當前分支到同名稱遠端(沒有則新增) ---- <!-- .slide: data-background="#dfdfdf" --> ## ```git remote``` - 遠端資訊 - ```git remote -v``` - ```git remote show 遠端``` - 重新命名 - ```git remote rename 舊遠端 新遠端``` --- <!-- .slide: data-background="#dfdfdf" --> # 歷史紀錄 ## History ---- <!-- .slide: data-background="#dfdfdf" --> ## ```git log``` - ```-n``` 顯示最近 n 筆 - ```--stat``` 顯示 diff - ```-p, --patch``` 顯示 patch - ```--pretty=``` 格式化 - ```--pretty=oneline``` - ```--pretty="%h - %an, %ar : %s"``` - ```git log master..另個分支``` - ```git show 提交``` ---- <!-- .slide: data-background="#dfdfdf" --> # Rebase --- <!-- .slide: data-background="#dfdfdf" --> # 第三方託管 - public - private ---- <!-- .slide: data-background="#dfdfdf" --> ## Github - GitHub $\neq$ Git - [Student Pack](https://education.github.com/pack) ---- <!-- .slide: data-background="#dfdfdf" --> ## TFS ![](https://i.imgur.com/BVXBiTM.png) ---- <!-- .slide: data-background="#dfdfdf" --> ## Others - Bitbucket - Gitlab - Gogs ---- <!-- .slide: data-background="#dfdfdf" --> ## 實用 plugin - [Octotree](https://chrome.google.com/webstore/detail/octotree/bkhaagjahfmjljalopjnoealnfndnagc?hl=zh-TW) ![](https://i.imgur.com/PBSae7g.png) --- <!-- .slide: data-background="#dfdfdf" --> # 其他 ---- <!-- .slide: data-background="#dfdfdf" --> ## 來不及講的主題 - 遠端存取 SSH Keys - submodule - [Removing sensitive data from a repository](https://help.github.com/articles/removing-sensitive-data-from-a-repository/) - ```git stash``` - ```git merge --squash``` - ```git blame``` - ```git bisect``` ---- <!-- .slide: data-background="#dfdfdf" --> ## 更深入 Git - GPG sign - worktree - Reflog - ```git log -g``` - Hook - Travis CI ---- <!-- .slide: data-background="#dfdfdf" --> ## 延伸閱讀 - [Git SCM](https://git-scm.com/book/zh-tw/v2/%E9%96%8B%E5%A7%8B-%E9%97%9C%E6%96%BC%E7%89%88%E6%9C%AC%E6%8E%A7%E5%88%B6) - [Atlassian Tut](https://www.atlassian.com/git/tutorials) - [Git in 2016](https://hackernoon.com/git-in-2016-fad96ae22a15) - [Git - a powerful version control tool](https://www.slideshare.net/KuoLeMei/git-a-powerful-version-control-tool-69568362) --- <!-- .slide: data-background="#dfdfdf" --> # QA