場景:模擬兩個人維護同一個 Git 分支。
先在Github 倉庫裡基於 master
創建一個新的分支 feature/add_git_cmds
,點擊 Create branch 即可:
創建成功後,回到本地,在本地拉取兩個庫,模擬兩個人開發。
別忘了給兩個人設置不同的 user~
我們先看一下 Git 倉庫的全局配置( --global
):
我們讓 git_learning_A 使用默認的全局用戶配置,給 git_learning_B 設置局部用戶配置( --local
,優先級高於全局配置):
(配置可參考1 Git 基礎 --03 | 使用 git 之前需要做的最小配置)
最後在兩個本地倉庫裡,都基於遠端feature/add_git_cmds
分支創建相關聯的本地分支。
命令: git checkout -b feature/add_git_cmds origin/feature/add_git_cmds
,該命令會基於後面的遠端分支創建名為前者的本地分支,跟蹤遠端分支,並切換到新建的分支上來。
在兩個本地倉庫上都進行同樣的操作。
至此,模擬了兩個人在同一倉庫的同一分支上開發的場景,接下來針對 5 種情況一一進行試驗🧪吧!
34 | 不同人修改了不同文件如何處理?#
結論先行:直接 merge 即可。
git_learning_A:修改 readme.md 文件,並推送到遠端。
git push
很順利。
查看遠端倉庫:
查看提交記錄的作者,對應 git_learning_A 使用的全局用戶配置:
git_learning_B:修改另一個文件 xxx/css.x,推送之前需要先拉取,再嘗試推送。
先修改文件,假設直接推送,看看會發生什麼?
前面的步驟和 git_learning_A 的類似,但是在 git push
時發生了意外,是不是似曾相識?報錯和上一章中提到的一模一樣:3 Git 與 GitHub 的簡單同步 --33 | 把本地倉庫同步到 GitHub。
❌: git push -f
強行推送。
✅:先拉取,再合併,再推送。
git fetch
:
可以看到最新 commit 的 hash 值從 d7d648a 更新到了 192a3b3。
在分支說明上發現當前分支和遠端分支的狀態為:ahead 1(本地有更新我沒有推送到遠端), behind 1(遠端有更新我沒有合入到本地),那麼先進行合入。
git merge origin/feature/add_git_cmds
:
執行後會彈出 commit 信息的編輯,默認即可,或適當添加說明。
:wq
保存退出,可以看到 merge 成功以及修改的記錄。
藍線可以看到目前 ahead 2,也就本地多了兩個 commit,還沒有推送到遠端;
紅框即 ahead 的 2 條 commit 記錄。
這時候查看本地的 readme.md 和 xxx/css.x 文件,都是修改後的樣子,接下來直接 push 即可。
git push
:
推送成功!不同人在不同文件上進行協同辦公還是很方便的,所以協同辦公時以這種方式進行是不是很高效呢?再看看其他情況吧~
35 | 不同人修改了同文件的不同區域如何處理?#
結論先行:直接 merge 即可。
⚠️:先創造有不同區域的環境,在任一倉庫的 readme.md 文件中添加多行,再推送,兩個倉庫保持同步。readme.md 文件修改如下:
因為上一節中的文件都是 1 行,無法做到修改不同區域。
git_learning_A:修改 readme.md 的第 4 行,直接推送。
git_learning_B:修改 readme.md 的第 7 行,先 pull,再推送。
git pull
過程中,彈出 commit 信息的編輯後, :wq
保存退出,即合併成功。
⚠️:這裡直接 pull 會提示,沒有明確的 pull 策略是不推薦的。
1)可以手動配置 pull 的默認策略
2)或者在 git pull
命令後加入選項,如 --rebase
、 --no-rebase
、 --ff-only
3)或者使用 git fetch
後,再選擇合併策略
這時候查看本地的 readme.md 文件,符合預期,接下來直接 push 即可:
這種方式下的協同辦公也是比較順利的,Git 有能力自動進行合併~
36 | 不同人修改了同文件的同一区域如何处理?#
結論先行:在 merge 時會出現衝突,需要自行解決。
git_learning_A:修改 readme.md 的第 1 行,直接推送。
⚠️:別忘了先進行 git pull
,因為剛才 git_learning_B 做的更新還沒有同步。
git_learning_B:同樣修改 readme.md 的第 1 行,先 pull,手動解決衝突,再推送。
這次我們 git pull
帶了選項 --no-rebase
,表示通過 merge 的方式進行拉取。
緊接著, 產生衝突了,需要我們自己解決衝突,再進行提交。
vim readme.md
,打開產生衝突的文件 :
產生衝突的位置有明顯的標記,HEAD 與 === 之間代表本地的代碼,hash 值與 === 之間代表合入的代碼。
我們需要修改這部分代碼,並刪去這些特殊標記,可以這樣修改:(實際開發中,記得和相關人員交流後再進行修改❗️)
:wq
保存退出後,通過 git status
查看倉庫狀態:
紅框中,上者表示進行合併;下者則表示取消合併,回到合併前的狀態。
這裡我們實踐一下上者。⚠️:此時修改還在工作區,我們需要先添加到暫存區,再提交。
先進行添加和提交,再進行推送:
PS: -am
包含了添加和提交兩個操作。
這次我們發現 Git 沒有那麼智能,也不需要那麼智能,因為它肯定不知道誰的代碼應該被保留。
37 | 同時變更了文件名和文件內容如何處理?#
結論先行:直接 merge 即可。
git_learning_A:修改 xxx/css.x 的文件名為 xxx/css2.x。
還記得 git mv
命令嗎?可跳轉1 Git 基礎 --06 | 給文件重命名的簡便方法回顧。
git_learning_B:修改 xxx/css.x 中的內容(並不知道文件名已經修改)。
Cool~Git 可以自動解決這樣的問題。查看合併情況:
可以看到不僅文件名修改過來了,文件裡的修改也被保留了。
本質上,這裡修改的是同文件的不同區域~
38 | 把同一文件改成了不同的文件名如何處理?#
結論先行:在 merge 時會出現衝突,需要自行解決。
git_learning_A:修改 xxx/css2.x 的文件名為 xxx/cssA.x。
git_learning_B:修改 xxx/css2.x 的文件名為 xxx/cssB.x。(並不知道文件名已經修改)。
發生衝突了~
查看文件情況:
可以看到 Git 的做法是同時保留了兩個修改了文件名的文件,並且兩個文件的內容沒有區別。
通過 git status
也很清晰的告訴了我們文件名變更的情況,以及可以怎麼做。
git rm
不需要的文件, git add
最後決定要的文件,提交,推送,即可!
看了這幾種場景下的 Git 協同辦公,是不是對解決衝突不再恐懼了呢?