# Git 中階應用 視覺化 Git 操作 https://git-school.github.io/visualizing-git/ ## Outline ```markmap # Git ## Local Repository - init - add - commit - clone ## Branch Operation - branch - checkout - merge - rebase - tag ## Rework Skill - reset - cherry-pick - revert - squash - stash ## Merge Conflict - resolve - 2-way merge - 3-way merge ## Cowork with git - remote - fetch - pull - push ``` ## Local Repository 這是我的 Repository;我git,我不求人 ```markmap ## Local Repository - init - add - commit - clone ``` 1. 建立自己的 local repository ```bash= cd mysource git init git add . git commit -m "init commit" ``` 2. 把程式碼加入 repository - **working directory** 工作目錄,目錄裡有`.git`資料夾(repository)的目錄 - **untracked file** 還沒有被監管的檔案 當檔案曾經被`coomit`過,檔案就是被監管(tracking),所以`untracked file`就是新增的檔案 - **changes not staged for commit** 被監管的檔案有異動,還沒有被監管的檔案commit 被監管的檔案有被異動,不論修改或刪除都是這個狀態 - **staging area** 暫存區域 還沒`commit`之前,你可以在`staging area`檢視你的工作 - **repository** 本地端的儲存庫 被`commit`的記錄都會被放到儲存庫,用`git log`可以查看歷史記錄。你可以視它為資料庫,檔案型資料庫。 3. **init** `init`會在目錄下建立`.git`目錄,並初始化儲存庫 - `--bare` 亦裸裸的儲存庫,是用來做為共同開發時的單一來源庫,可以被用來`clone`的庫。你也可以在本機創建裸庫,作為`remote`。 4. **add** - stage `git`使用`edit/stage/commit`模式 - `add -p` `git add`預設是以檔案為單位,但也可以以`code block`為單位,放在`staging area`的東西是為之後的`commit`做準備 5. **commit** - 一個`commit`一個工作,要確保你的程式不論在那個`commit`的狀態下都是可用的 - `commit`會有其上游(base),以`sha1`來表示,使用上只要取`sha1`的前8位就可以代表一個`commit` 6. **clone** - 一生一次,之後的更就都使用`pull` - `--depth=1` 不要對整個`git tree`抓取,我只想要**快點取得**最新的程式碼,不要連整個歷史都給我 --- ## Branch Operation 我上下其手,在一棵名為 git 的樹上 ```markmap ## Branch Operation - branch - checkout - merge - rebase - tag ``` 1. branch & checkout - **HEAD** 指向作用中(current)的分支 - **detached HEAD** 當 HEAD 不是指向分支,而是其中的一個 commit 時 - **reset --soft** 通常不用,`--hard`才是王道 - **merge** 分支操作,把目標分支給合併到`HEAD`所在的分支,合併後,共享相同的未來 - **rebase** 我`HEAD`所在的分支的歷史和過去,建立在另一個分支之上,`rebase`後,你的過去就不一樣了 2. **tag** 標籤是被貼在特定的`commit`,貼了之後就不能移動,不像`branch`可以想方設法讓它移到別的`commit`。`tag`通常被用來做版本(發布)管理。 - 用`branch`管理需求 - `commit`管理技術工作 - `tag`管理發行版本。 --- ## Rework Skill 玩弄這棵樹 ```markmap ## Rework Skill - reset - cherry-pick - revert - squash - stash ``` 1. **reset** reposition HEAD - **hard** HEAD移到目標commit,且工作區的環境對齊目標 commit 狀態 - **mixed** HEAD移到目標commit,工作區不動,與 commit 差異放到 unstage - **soft** HEAD移到目標commit,工作區不動,與 commit 差異放到 stage area 2. **cherry-pick** 挑檢櫻桃,就跟它的名字一樣,你可以只挑你想要的櫻桃(commit)來吃 3. **commit --amend** 訊息寫的不夠好,你有機會重來 4. **revert** 有問題 commit,你可以針對它、墮掉它 5. **rebase -i** 在 rebase 時,順便把你的工作重新整理 6. **squash** 在 merge 時,把要被 merge 的分支上的差異壓成一個 commit 丟過來,不會產生 merge commit ![](https://learn.microsoft.com/en-us/azure/devops/repos/git/media/merging-with-squash/squash-branch-merge.png?view=azure-devops =450x) 7. **stash** - 你正在開發新工作,此時線上有個 bug 要解,你可以將工作到一半的東西先丟到一旁,之後在拿回來即可 - 會有這個需求的原因是,當你的工作區有異動沒有被 commit 時,你無法接換分支 --- ## Merge Conflict 三姑六婆,會造成理解上的障礙 ```markmap ## Merge Conflict - resolve - 2-way merge - 3-way merge ``` 1. **conlict** & resolved 意圖不明會發生在 - 有 2 個意圖 - 沒有前後關係 - 因為 2 個意圖都可以追朔到一個來源 - 且改動到相同的 code block 關係曖昧不明時,就需要有人從旁下指導 2. merge - 2-way merge - 3-way merge - manual merge --- ## Cowork with git 多人爬樹,原則還是不變 ```markmap ## Cowork with git - remote - fetch - pull - push ``` 1. remote - git 設計上是分散式的`SCM(source code management)`,所以你專案的上游`upstream`可以不只一個 - 當然,也可以只有一個上游,將 git 當成中央式(centralized repository)是通用的做法。 2. fetch & pull - FETCH_HEAD 指向遠端分支最新的位置,fetch 會更新它 - pull = fetch + merge 你都知道了,你也可以自己來 - fast-forward 3. push - tracking branch 你從遠端 checkout 出來的分支會 tracking 它的來源 - 預設 push 會找遠端相同名稱的分支推送,當然你也可以自己來 - don't FORCE push 樹根都被你改了,你要叫別人怎麼辦(用到的人全部重新 clone) 4. misc. - rebase **before** publish your own branch - **after** publish, always using merge - workflow is conventional - PR ---- ## 窗外篇 ### merge - 快轉 fast-forward ![](https://i.imgur.com/oPLxsue.png) - 完整記錄 ![](https://i.imgur.com/jtXK79v.png) ### commit - split your work - once a work been completed, commit it - commit offent ### commit message - ### ignore file <br>