# Git 開發流程 ## 基本知識 `origin`:我自己的遠端儲存庫(網頁上的) `upstream`:我原本 fork 的原專案 - 如果要更新到自己這邊就是 `origin` - 如果是想拉取原作者更新,就是拉 `upstream`。 ## 初始化本地端 repo 至 Github 假設我想要將我本地端的專案推到 github 上面,但這是第一次推,則可以遵循以下步驟: 1. 先在自己的 GitHub 帳號建立一個新的 repository 2. 切換到本地端的專案根目錄,依序輸入以下指令: ```shell git init git remote add origin <遠端repo的url> git remote -v // 檢查是否成功建立 ``` 到這裡應該會看到下列輸出: ```shell origin git@github.com:LinMarc1210/Agent-for-python.git (fetch) origin git@github.com:LinMarc1210/Agent-for-python.git (push) ``` 3. 將檔案加到 github 上面,依照以下指令: ```shell git add . git commit -m "commit 標題" git push -u origin main // 第一次 push 的指令,之後用 git push 即可 ``` 有可能會遇到無法推送的情況,通常是因為本地端預設分支的名字是 `master` 但遠端預設是 `main`,這時按照以下指令,輸入完再 push 一次即可。 ```shell git branch -M main // 將本地分支改名 ``` ## rebase:修改線性歷史 ### 用 rebase 合併分支 以下是示意圖,`feature` 是從 commit `C` 分支出來的,最常見的情況是 `feature` 分支開發到一半,`main` 也有更新: ``` main: A---B---C---D \ feature: E---F---G(rebase前) ``` 這時我們希望 `feature` 的開發歷史重新接在 `main` 的更新之後,就可以用 rebase,而且不會像 merge 還另外生成 commit。 ``` git checkout <branch> git rebase main ``` 注意這裡 `rebase main` 是去 rebase 本地端的 `main`,所以記得本地端的 `main` 要先拉取遠端 `main` 更新。 或者就直接 `git rebase origin/main` 也可以。 ``` main: A---B---C---D \ feature: E'---F'---G'(rebase後) ``` 這樣在這個分支歷史上,我做的變更就會直接接在別人在 `main` 做的變更之後,保持歷史乾淨。 ### interactive rebase 用互動式介面達成刪除、合併、重寫 commit 等操作,指令會帶上一個參數 `-i`,`HEAD~2` 代表要操作最近兩則 commit。 ``` git rebase -i HEAD~2 ``` 接下來就會跳到互動式介面,可以決定要對該 commit 做 pick, squash, drop 等操作。完成後本地 commit 歷史會和遠端的不一樣,若無衝突(改變的 commit 本來就還沒推送)則可直接用 `git push`,但若有衝突(改變的可能是之前就推送至遠端的),則需使用以下指令: ``` git push --force-with-lease origin <branch> ``` ## fork 別人的專案到自己的 GitHub 進行開發 面對貢獻開源專案,需要將原專案在網頁上先按下 fork 按鍵,就會跑到自己帳號底下的副本。接下來按照以下步驟開發: 1. 把新的 fork 複製到本地端 ``` git clone <自己帳號底下的專案副本> ``` 2. 設定遠端 `origin` 以及上游 `upstream`,設定後檢查。 ``` git remote add origin <自己帳號底下的專案副本> git remote add upstream <原作者底下的原專案> git remote -v ``` (若之前設定錯誤的 url 可以用以下命令更正) ``` git remote set-url origin <正確的url> ``` 3. (可選)可以另外開一個分支來開發,並在遠端的 origin 也建立分支 ``` git checkout -b <branch_name> git add . git commit git push -u origin <branch_name> ``` 4. 去網頁上發 PR(記得選你有變更的分支) ## Commit 的作者與 PR 的作者 Commit 的作者是跟著本地端的 config 設定走的,PR 作者則是看從哪個網頁上面發的(如果用 `gh pr create` 的話就看 `gh auth status` 顯示哪個帳號)。因此本地端我們需設定 `user.name` 和 `user.email`,才能讓 commit 顯示正確的作者: ``` git config --global user.name "LinMarc1210" git config --global user.email "marc1210899@gmail.com" ``` 若是需要對某些特定專案設定不同的帳號,要先切到該專案 repo 再設定局部的 config: ``` git config user.name "MarcLin-Advantech" git config user.email "Marc.Lin@advantech.com" ``` ## 多人開發情境(閉源專案、小型團隊適用) 以小型團隊來說,最常見的快速開發流程即為 GitHub Flow,較簡單的開發角色分為**主導者 A**以及其他人。整個專案 repo 會在 A 的 GitHub 帳號底下,並且其他人無法對主分支 `main` 進行更改。 ### 對於所有專案成員 #### 1. 先將 A 的主專案 clone 到本地端 當我們需要開分支開發新功能時,直接使用 `git clone` 去複製主分支,而不需用 `git fork`,這樣做是減少複雜性(若要先 fork 再 clone 也沒問題,參見[開源專案的多人開發情境](#多人開發情境(開源專案、大型團隊適用))) #### 2. 建立分支 通常專案成員不能直接更改 `main`,本地端的 `main` 僅用於與上游同步,因此需直接建立分支,並切換到分支進行開發。 ```shell git checkout -b <branch_name> ``` #### 3. 需要與原專案同步的狀況 這步適用於遠端有更新時,我們需要在本地端同步: ``` git checkout main git fetch upstream git merge upstream/main ``` 然後再切回功能分支開發,也拉取更新(解衝突也是這時候解) 若有衝突,rebase 可確保較乾淨的線性歷史,merge 則是可以確保遠端和我正在開發的功能歷史都留著。 ``` git checkout <branch_name> git rebase main ``` #### 4. 推送更新並在專案主管理者的 repo 底下建立分支 當網頁上還沒有這支分支時,以下指令可以在遠端新建一支與本地同名的分支,並且自動建立追蹤關係,之後只要使用 `git push` 就可以直接推送到這個分支了。 ``` git add . git commit git push -u origin <branch_name> ``` #### 5. 在網頁發送 PR(要選擇你開發的該分支) 因為是直接在原作者的 repo 底下建立分支,所以要跑去他的 github 帳號,並且到以下頁面按下 create pull request,就可以選你要發 PR 的分支了。  ## 多人開發情境(開源專案、大型團隊適用) 現在假設有 A,B,C 三個人開發:  接下來細部說明每一個步驟的開發流程: ### 對於專案成員 B,C #### 1. 先 push 剛剛開發完的本地變更到自己的分支 (這裡代稱 feature) 先確認自己在哪個分支: ```shell git branch ``` 接下來是最重要的一步,必須要先確保自己寫的東西有先被存到遠端上 ```shell git add <你要推上去的檔案> git commit # 也可以用 git commit -m "你想打的message標題" git push origin feature # 若已設定過確保自己在feature,可直接 git push ``` #### 2. 切換到自己的 master 切換前必須要將 `feature` 的變更都 `push` 完成,使用以下指令確認還有哪些檔案與網頁上的 `feature` 有差異: ```shell git status ``` 若出現一些你不想推上去的檔案,但你仍然想換分支,可以使用以下指令丟棄所有目前與網頁上的 `feature` 不同的部分: ```shell git stash ``` 確保本地檔案與網頁上的 `feature` 一樣後,再換至自己的 `master` ``` git checkout master ``` #### 3. 拉回原專案 master 的更新到自己的 master 如果還沒設定過上游,先用以下指令設定(若看到報錯代表已經設定過了): ```shell git remote add upstream https://github.com/A的帳號/專案.git ``` 確保自己的 `master` 有和原專案同步: ``` git fetch upstream git log # 只是用來看A相對於你的master做了哪些變更 git merge --ff-only upstream/main # --ff-only:只允許可快轉的,而fu ``` :::info `git pull` = `git fetch` + `git merge` 用 fetch 再 merge 會比較安全,才決定要不要 merge 用 pull 就會直接合併到底了 ::: #### 4. 更新自己遠端的 master 分支 概念:`origin/master` 是你自己 fork 過來的,`upstream/master` 才是專案管理者 A 的 master。剛剛同步完 `upstream/master` 到本地了,接下來要將新變更也 push 到我們的 `origin/master`。 ``` git push origin/master ``` #### 5. 把最新的 master 合併到自己的 feature 準備切回 `feature` 分支並且將上一步的更新 merge 進來: ``` git checkout feature git merge master ``` :::warning merge 如果遇到衝突怎麼辦? ::: :::success - 假如 B 開發了新的 script ,而剛剛從 A 那邊 merge 進來的是網頁的新功能,在這種「兩人改的檔案不重複」的狀況下,git 會自行處理合併,分別取用剛剛第 1 步 B 推上去的變更和第 4 步從 A merge 過來的新改動,而不會產生衝突 - 但若「兩個人改的檔案有重複」,終端機會跟你說哪些檔案有衝突,你需要手動打開那些檔案解決標記,大致上會長這樣: ```git <<<<<<< HEAD master 的內容 ======= feature 分支原來的內容 >>>>>>> some-commit-id ``` ::: #### 6. 在網頁上 feature 分支發 Pull Request 解決完衝突,確保 merge 完成後就可以至自己的 GitHub 頁面,並且點選 Compare & Pull Request 的按鈕,原專案管理者 A 就會收到其他人開發的新變更了! ## Gemini CLI:gh gh 是可以直接在 terminal 上面執行 github 登入、發PR、檢查 workflow 等動作的套件,就不用再另外開網頁了。幾個比較常見的如下: ### 登入 GitHub CLI 一開始要先使用這個命令,就會跳出網頁瀏覽器叫你登入 GitHub 帳號: ``` gh auth login ``` ### 建立 repo 不用另外開網頁建立,直接輸入以下命令即可: ``` gh create <repo_name> ``` ### 發送 Pull Request 當完成 `push` 到自己的 repo 之後,要發 PR 可以輸入以下指令,之後會互動式的詢問你 title 和 body: ``` gh pr create ``` ## SSH GitHub ssh key 是讓這台電腦認得是這個 GitHub 帳號的使用者。首先在電腦上生成,通常可以直接用 `ssh-keygen`,但有時候為了區分不同 GitHub 帳號的 SSH key,我們會加上帳戶與信箱。 ``` ssh-keygen ssh-keygen -t ed25519 -C "marc1210899@gmail.com" -f ~/.ssh/id_rsa_LinMarc1210 ``` 接下來查看並複製 ssh key,其中 `ed25519` 是前面 `keygen` 生成的名字,而 `.pub` 是公鑰的意思,若沒有加 `.pub` 就能看到只存在本機上的私鑰。 ``` ls ~/.ssh cat ~/.ssh/id_ed25519.pub ``` 將複製下來密鑰的貼到以下位置,為這把 ssh key 取名之後就完成了。 
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up