05 - Push 與 Pull

04-GitHub入門 | 下一篇 → 06-分支管理


⬆️ Push:把本地推到 GitHub

# 第一次 push(需要設定 upstream)
git push -u origin main
 
# 之後每次 push 只需要
git push

-u--set-upstream 的縮寫,設定預設的推送目標。 第一次設定後,以後直接 git push 就夠了。

完整的第一次 push 流程

# 1. 初始化(如果還沒有)
git init
 
# 2. 加入所有檔案
git add .
 
# 3. 建立第一個 commit
git commit -m "Initial commit"
 
# 4. 連接 GitHub repo
git remote add origin git@github.com:username/repo-name.git
 
# 5. Push!
git push -u origin main

⬇️ Pull:從 GitHub 拉下最新版本

git pull

git pull 實際上是兩個指令的組合:

git fetch   ← 從 GitHub 抓取最新資料(但不合併)
+
git merge   ← 將抓下來的內容合併到本地

什麼時候要 pull?

  • 在多台電腦上工作時,每次開始工作前先 pull
  • 和別人合作時,在 push 之前先 pull

🔄 多台電腦的同步工作流程

電腦 A(家裡)完成工作後:

git add .
git commit -m "更新筆記"
git push

電腦 B(醫院)開始工作前:

git pull
# 現在就有最新的筆記了,可以繼續編輯

⚠️ Push 被拒絕怎麼辦?

最常見的錯誤訊息:

! [rejected]  main -> main (fetch first)
error: failed to push some refs

這代表 GitHub 上有你本地沒有的新 commit(例如在另一台電腦 push 過)。

解法

# 先 pull(把遠端的拉下來合併)
git pull
 
# 確認沒有衝突後,再 push
git push

🔁 git pull —rebase:更乾淨的拉取方式

預設的 git pull = fetch + merge,每次遇到遠端有新東西就會多一個 merge commit, 歷史會變得很雜(一堆 Merge branch 'main'...)。

git pull --rebase 改用 rebase 整合:把你本地的 commit「先收起來,套上遠端最新版,再把你的 commit 一個個重放上去」, 歷史是一條乾淨的直線,不會多 merge commit。

# 拉取並用 rebase 方式整合(推薦在自動同步環境用)
git pull --rebase origin main

什麼時候特別該用 --rebase?

當 repo 有背景自動同步(例如 obsidian-git 外掛每 10 分鐘自動 push), 遠端 main 隨時可能多出新 commit。push 前先 git pull --rebase 可以避免每次都產生 merge commit、 也降低衝突機率。完整實戰見 09-實戰工作流範例

設定成預設行為(選用)

# 讓以後的 git pull 預設就用 rebase
git config --global pull.rebase true

Rebase 過程中撞到衝突怎麼辦?

# 1. Git 會停下來告訴你哪個檔案衝突
# 2. 手動編輯解決衝突(刪掉 <<<<<<< ======= >>>>>>> 標記)
# 3. 把解決好的檔案加回暫存區
git add 衝突的檔案
 
# 4. 繼續 rebase(注意:不是 commit!)
git rebase --continue
 
# 如果想放棄整個 rebase、回到原狀
git rebase --abort

💥 Merge Conflict(合併衝突)

如果兩邊都修改了同一個檔案的同一個地方,Git 就不知道要保留哪個版本,會出現衝突。

CONFLICT (content): Merge conflict in notes.md
Automatic merge failed; fix conflicts and then commit the result.

Git 會在衝突的地方標記:

<<<<<<< HEAD
這是你本地的版本
=======
這是 GitHub 上的版本
>>>>>>> origin/main

解決衝突的步驟

  1. 打開衝突的檔案,手動選擇要保留的內容(刪掉 <<<<<<<=======>>>>>>> 這些標記)
  2. 存檔
  3. git add 衝突的檔案
  4. git commit -m "解決合併衝突"
  5. git push

實際走一遍:一個 conflict 的完整解法

假設你和遠端都改了 notes.md 的同一行,pull 後打開檔案看到:

## 治療
<<<<<<< HEAD
第一線用 drug A,劑量 5 mg。          ← 你本地寫的
=======
第一線用 drug A,劑量 10 mg。         ← 遠端(GitHub)的版本
>>>>>>> origin/main

你要親自判斷哪個對(或兩個都要),把整段改成最終想要的樣子, 連同 <<<<<<<=======>>>>>>> 三行標記全部刪掉

## 治療
第一線用 drug A,劑量 10 mg。

然後:

# 先確認還有沒有別的檔案也在衝突
git status        # 紅字 "both modified" 就是還沒解的
 
# 解完所有衝突後,加回暫存區
git add notes.md
 
# 完成合併
git commit -m "解決 notes.md 劑量衝突"
git push

三個實用招式

  • 想看「衝突前」雙方各自的版本git log --merge -p notes.md
  • 這次合併太亂、想整個放棄重來git merge --abort(回到 pull 之前的狀態)
  • 用編輯器的合併工具:VS Code 打開衝突檔會有「Accept Current / Incoming / Both」按鈕,比手刪標記更直覺。

解衝突 = 你在做決定

Git 無法替你判斷醫學內容哪個對。絕對不要無腦選一邊或亂刪, 尤其是別人(或自動同步)寫的內容,務必逐行確認再保留。


🔐 HTTPS vs SSH:兩種連線方式怎麼選?

連 GitHub 有兩種 URL 格式,決定了你怎麼驗證身份:

HTTPSSSH
URL 長相https://github.com/user/repo.gitgit@github.com:user/repo.git
驗證方式Personal Access Token(當密碼)SSH 金鑰對
第一次設定簡單,貼 URL 就能 clone要先產生並上傳 SSH key
之後每次 push需 token(可用 credential helper 記住)不用再輸入任何東西
公司防火牆通常都通(走 443 port)有些網路會擋 22 port
推薦對象偶爾用、或網路受限環境自己常用的主力機器

Token 認證(HTTPS 用)重點

GitHub 自 2021 年起不接受帳號密碼,HTTPS push 時的「密碼」欄位要填 Personal Access Token (PAT)

# push 時會跳出
Username: 你的 GitHub 帳號
Password: 這裡貼 PAT(不是你的登入密碼!)
  • 產生 PAT:GitHub → Settings → Developer settings → Personal access tokens(細節見 04-GitHub入門)。
  • 至少要勾 repo 權限;token 只會顯示一次,當下就複製存好。
  • 讓 git 記住 token,不用每次貼:
    git config --global credential.helper osxkeychain   # macOS
    git config --global credential.helper manager       # Windows
    git config --global credential.helper store         # Linux(明碼存檔,注意安全)

兩種方式互換

# 查目前用哪種
git remote -v
 
# 把 HTTPS 換成 SSH
git remote set-url origin git@github.com:user/repo.git
 
# 把 SSH 換回 HTTPS
git remote set-url origin https://github.com/user/repo.git

🗑️ 強制覆蓋遠端(危險!謹慎使用)

# 強制 push,會覆蓋遠端的版本
git push --force

只在你確定遠端的版本不重要時才使用。

多人協作時絕對不要用,會讓別人的工作消失!


📌 小結

指令用途
git push -u origin main第一次 push(設定 upstream)
git push之後的 push
git pull從 GitHub 拉取最新版本
git fetch只抓取,不合併

04-GitHub入門 | 下一篇 → 06-分支管理