前言
這篇可能頭腦清醒一點再看會比較好,因為操作部驟比較多,又牽涉到兩個用戶端。
已經推了幾個 commit 後,發現其中一個 commit 需要加料,原因是客戶臨時又改變需求了。
但是我不想多推另一個 commit, 因為要改的地方跟某個 commit 算是一起的,而且這也還是測試分支,
我想確定都改好也測試好就是同一個 commit, 之後到正式分支就不用再合併一次了。
確認狀況
看一下本地端的 git log 前3個 commit
$ git log -3
commit bbd1613aabf14ca0504a17009bca3e1128c90832
Author: Logo-Kuo <logo@forblind.org.tw>
Date: Tue Jan 12 12:51:55 2021 +0800
type: fix
system: leave
scope: view/self/controller/model/js
subject: 在留停紀錄頁面加入查詢與刪除詳細留停紀錄功能
commit 13ca4376799a9f43c2b9ee1b25d51bcd26913f10
Author: Logo-Kuo <logo@forblind.org.tw>
Date: Tue Jan 12 13:48:42 2021 +0800
document pdf 2
commit 4fe152957fbd2e9a072861a1e3522d6e14ef1e2f
Author: Logo-Kuo <logo@forblind.org.tw>
Date: Fri Jan 8 22:36:17 2021 +0800
type: fix
system: leave
scope: view/model/controller/self/js
subject: 新增查詢所有員工的年資與留停紀錄
我要改的 commit 是第2個,也就是 document pdf 2, id 為 13ca437,
而其他 commit 都不動,繼續保留。
我們找出想改的 commit 的前一個 commit id 是 4fe1529,
然後使用 rebase 的交互模式:
rebase
$ git rebase -i 4fe1529
pick 13ca437 document pdf 2
pick bbd1613 type: fix system: leave scope: view/self/controller/model/js subject: 在留停紀錄頁面加入查詢與刪除詳細留停紀錄功能
# 提醒一下,rebase 的 commit 跟 git log 相反,越新是越下面喔
# 接著,我們把 document pdf 2 的 commit 前面動作 pick 改成 edit 像這樣:
edit 13ca437 document pdf 2
# 對其他動作有興趣的可以看我之前的文章,這個畫面的下方也有被註解掉的說明可以參考
# 改好存檔離開
Stopped at 13ca437... document pdf 2
# 他會停在這個 edit 的 commit
You can amend the commit now, with
git commit --amend
# 你可以使用上面指令來修改這個 commit 的訊息
Once you are satisfied with your changes, run
git rebase --continue
# 如果你確定已經處理好了那可以使用上面指令讓 rebase 繼續跑完
回到提示符號後,來看一下 log:
$ git log -1
commit 13ca4376799a9f43c2b9ee1b25d51bcd26913f10 (HEAD)
Author: Logo-Kuo <logo@forblind.org.tw>
Date: Tue Jan 12 13:48:42 2021 +0800
document pdf 2
看到最後一個 commit 是我們要改的 commit 才是正確的。
因為我們現在在 rebase 裡面,並沒有做退版或合併之類的動作,可以想成它把之後的 commit 先藏起來了,
這樣我們才方便處理當下這個 commit.
# 看一下狀態
$ git status
interactive rebase in progress; onto 4fe1529
# 我們處在這個 commit 的 rebase 交互模式裡
Last command done (1 command done):
edit 13ca437 document pdf 2
# 最後一個指令停在這個 commit 上面
Next command to do (1 remaining command):
pick bbd1613 type: fix system: leave scope: view/self/controller/model/js sub
ject: 在留停紀錄頁面加入查詢與刪除詳細留停紀錄功能
# 下一個 commit 是被保留的,也就是比 document pdf 2 較新的那些 commit
(use "git rebase --edit-todo" to view and edit)
# 使用上面的指令可以回到 rebase 的交互編輯模式,例如 edit 寫錯了
You are currently editing a commit while rebasing branch 'dev' on '4fe1529'.
# 現在在 dev 分支 處理某個 commit
(use "git commit --amend" to amend the current commit)
# 使用上面指令改 commit 訊息
(use "git rebase --continue" once you are satisfied with your changes)
# 使用上面指令讓 rebase 繼續跑完
nothing to commit, working tree clean
# 上面這句應該很熟悉吧 ,工作目錄乾淨
軟退版
接下來,我們要把 document pdf 2 拆到工作目錄下,因為我們打算繼續加料進去。
所以我們退一版,這時候不能用 --hard
因為我們需要把 commit 動過的檔案拆到工作目錄。
$ git reset HEAD~
Unstaged changes after reset:
M web_data/sysLlibrary/PDF/sysPDF.php
M web_data/sysLlibrary/PDF/template/document/document.tpl
兩個檔案被拆到工作目錄了
看一下 log
$ git log -1
commit 4fe152957fbd2e9a072861a1e3522d6e14ef1e2f (HEAD)
Author: Logo-Kuo <logo@forblind.org.tw>
Date: Fri Jan 8 22:36:17 2021 +0800
type: fix
system: leave
scope: view/model/controller/self/js
subject: 新增查詢所有員工的年資與留停紀錄
# 沒錯,document pdf 2 拆掉了
# 看一下狀態
$ git status
interactive rebase in progress; onto 4fe1529
Last command done (1 command done):
edit 13ca437 document pdf 2
Next command to do (1 remaining command):
pick bbd1613 type: fix system: leave scope: view/self/controller/model/js sub
ject: 在留停紀錄頁面加入查詢與刪除詳細留停紀錄功能
(use "git rebase --edit-todo" to view and edit)
# 上面都解釋過了
You are currently splitting a commit while rebasing branch 'dev' on '4fe1529'.
# 現在我們在 dev 分支的這個 commit rebase 交互模式下切了另一個 commit 下來
(Once your working directory is clean, run "git rebase --continue")
# 上面解數了,接下來是我們熟悉的 status 內容
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: web_data/sysLlibrary/PDF/sysPDF.php
modified: web_data/sysLlibrary/PDF/template/document/document.tpl
no changes added to commit (use "git add" and/or "git commit -a")
# 就是要你處理好後繼得 add 然後推 commit
加料與提交
接著就是看我們想做什麼,就像一般在處理工作一樣,想開檔案繼續寫程式或刪除什麼之類的,
好,那假設都弄好了,就是 git add .
跟 git commit
下面是寫完 commit 訊息,我寫的是 document pdf 3:
$ git commit
[detached HEAD 93ac02e] document pdf 3
2 files changed, 8 insertions(+), 34 deletions(-)
# 注意一下,關鍵字 detached
# 因為我們處在 rebase 交互模式下,所以斷頭中
# 看最新的兩個 log
$ git log -2
commit 93ac02e65ff295426c7c8a4c35634a53d3321077 (HEAD)
Author: Logo-Kuo <logo@forblind.org.tw>
Date: Tue Jan 12 15:54:14 2021 +0800
document pdf 3
commit 4fe152957fbd2e9a072861a1e3522d6e14ef1e2f
Author: Logo-Kuo <logo@forblind.org.tw>
Date: Fri Jan 8 22:36:17 2021 +0800
type: fix
system: leave
scope: view/model/controller/self/js
subject: 新增查詢所有員工的年資與留停紀錄
# 沒問題,原本的 document pdf 2 被我們拆掉,做好之後重新 commit 成為 document pdf 3
# 看狀態
$ git status
interactive rebase in progress; onto 4fe1529
Last command done (1 command done):
edit 13ca437 document pdf 2
Next command to do (1 remaining command):
pick bbd1613 type: fix system: leave scope: view/self/controller/model/js sub
ject: 在留停紀錄頁面加入查詢與刪除詳細留停紀錄功能
(use "git rebase --edit-todo" to view and edit)
You are currently editing a commit while rebasing branch 'dev' on '4fe1529'.
(use "git commit --amend" to amend the current commit)
(use "git rebase --continue" once you are satisfied with your changes)
# 上面都解釋過了
nothing to commit, working tree clean
# 因為已經重新推 commit 了,所以工作目錄乾淨
完成 rebase
那就讓 rebase 繼續完成
$ git rebase --continue
Successfully rebased and updated refs/heads/dev.
# 順立成功
# 看最新的 3 個 commit
$ git log -3
commit 97e1228aa7d70cf4d9ec984a6cc97b2595c2d3cb
Author: Logo-Kuo <logo@forblind.org.tw>
Date: Tue Jan 12 12:51:55 2021 +0800
type: fix
system: leave
scope: view/self/controller/model/js
subject: 在留停紀錄頁面加入查詢與刪除詳細留停紀錄功能
# 這個是當時被 rebase 保留的新 commit
# rebase 完成,當然也還給我們了
# 不過從我們 edit 之後的 commit id 全部都會被改
# 就是之後的 commit 其實都重新做了
# 所以如果調整的是很舊的 commit 那麼 continue 就要等一下了
commit 93ac02e65ff295426c7c8a4c35634a53d3321077
Author: Logo-Kuo <logo@forblind.org.tw>
Date: Tue Jan 12 15:54:14 2021 +0800
document pdf 3
# 這個是我們新改好推上來的 commit
commit 4fe152957fbd2e9a072861a1e3522d6e14ef1e2f
Author: Logo-Kuo <logo@forblind.org.tw>
Date: Fri Jan 8 22:36:17 2021 +0800
type: fix
system: leave
scope: view/model/controller/self/js
subject: 新增查詢所有員工的年資與留停紀錄
# 這個是舊的,完全不動,包括 commit id
# 看狀態
$ git status
On branch dev
nothing to commit, working tree clean
# 很好,一切正常
推上遠端倉庫
如果是基礎課程,到上面就應該結束了,
但我們是實務應用,所以要把整個分支推上遠端倉庫。
$ git push origin dev
logo@192.168.7.11's password:
To 192.168.7.11:/xxx/yyyy
! [rejected] dev -> dev (non-fast-forward)
error: failed to push some refs to '192.168.7.11:/xxx/yyyy'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
這下慘了,推不上去,因為有 rebase 又退版之類的動作
我確定目前本地端是對的,那就硬推了。
$ git push origin dev -f
logo@192.168.7.11's password:
Enumerating objects: 47, done.
Counting objects: 100% (47/47), done.
Delta compression using up to 6 threads
Compressing objects: 100% (24/24), done.
Writing objects: 100% (25/25), 4.31 KiB | 315.00 KiB/s, done.
Total 25 (delta 18), reused 0 (delta 0), pack-reused 0
To 192.168.7.11/xxx/yyyy
+ bbd1613...97e1228 dev -> dev (forced update)
# 好了,但故事還沒完喔
server 端的狀況
我已經完成工作了,但其他合作開發的伙伴就慘了。
因為做了上述動作,是必其他合作伙伴的分支也會受到影響
不說別的,server 端的 dev 分支也是 client 端,所以來看一下會發生什麼事情。
我們就假設其他伙伴或處理 server 端的人不知情好了,首先,他應該會先更新遠端倉庫的狀態:
logo@sys:/xxx/test_sys$ git remote update
Fetching origin
logo@127.0.0.1's password:
remote: Enumerating objects: 13, done.
remote: Counting objects: 100% (13/13), done.
remote: Compressing objects: 100% (7/7), done.
remote: Total 7 (delta 5), reused 0 (delta 0)
Unpacking objects: 100% (7/7), done.
From 127.0.0.1:/xxx/yyyy
0c97c3b..b4935b3 master -> origin/master
* [new tag] 3.9.2 -> 3.9.2
更新好了,不過要註意的地方有:
- server 端就是跟 git 遠端倉庫同一臺機器,所以 ip 會變成 127.0.0.1
- 我們的 server 端是 linux 環境,所以提示符號長不太一樣,不是 windows git bash
- 因為是整個遠端倉庫狀態的更新,所以其他分支像 master 有變動也會更新,雖然我們是在 dev 分支
# 看狀態
logo@sys:/xxx/test_sys$ git status
On branch dev
Your branch and 'origin/dev' have diverged,
and have 2 and 2 different commits each, respectively.
# 比較細心的應該就發現不對了
# 就算沒發現,直接推拉也會有錯誤提示
(use "git pull" to merge the remote branch into yours)
nothing to commit, working tree clean
它說我們的狀態跟遠端倉庫比起來有兩個不同
那看一下最新的2個 log
logo@sys:/xxx/test_sys$ git log -2
commit bbd1613aabf14ca0504a17009bca3e1128c90832 (HEAD -> dev)
Author: Logo-Kuo <logo@forblind.org.tw>
Date: Tue Jan 12 12:51:55 2021 +0800
type: fix
system: leave
scope: view/self/controller/model/js
subject: 在留停紀錄頁面加入查詢與刪除詳細留停紀錄功能
commit 13ca4376799a9f43c2b9ee1b25d51bcd26913f10
Author: Logo-Kuo <logo@forblind.org.tw>
Date: Tue Jan 12 13:48:42 2021 +0800
document pdf 2
應該很熟悉,基本上就是跟我們文章剛開始還沒動工的時候一樣。
如果自己本身已經推新的 commit 的話會需要再多處理一下,這部分我們下一篇會分享
拉回來衝突了
照理就是也看一下遠端倉庫的 log, 才知道要怎麼調整,不過我們先裝傻,就給它拉回來更新看看:
logo@sys:/xxx/test_sys$ git pull origin dev
logo@127.0.0.1's password:
From 127.0.0.1:/xxx/yyyy
* branch dev -> FETCH_HEAD
Auto-merging web_data/sysLlibrary/PDF/template/document/document.tpl
CONFLICT (content): Merge conflict in web_data/sysLlibrary/PDF/template/document
/document.tpl
Automatic merge failed; fix conflicts and then commit the result.
不妙了,拉回來合併失敗了,檔案產生衝突。
# 看狀態
logo@sys:/xxx/test_sys$ git status
On branch dev
Your branch and 'origin/dev' have diverged,
and have 2 and 2 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
# 你有還沒合併的檔案,看是要處理後 commit 還是放棄合併,回到 pull 之前
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: web_data/sysLlibrary/PDF/template/document/document.tpl
# 這個檔案衝突了,處理後 add 進來再 commit
no changes added to commit (use "git add" and/or "git commit -a")
其實提示就很清楚該怎麼做了,讓我們把衝突的檔案打開,
參考之前處理衝突的文章所述,解決衝突並存檔。
推 commit 時會有 merge 訊息,我先直接使用,推好後看狀態
logo@sys:/xxx/test_sys$ git status
On branch dev
Your branch is ahead of 'origin/dev' by 3 commits.
(use "git push" to publish your local commits)
# 變成領先3個 commit
nothing to commit, working tree clean
# 看一下 log
logo@sys:/xxx/test_sys$ git log -4
df0c5db2d46c3f07118e0b6 (HEAD -> dev)
Merge: bbd1613 97e1228
Author: logo <logo@sys.sys.forblind.org.tw>
Date: Tue Jan 12 16:06:27 2021 +0800
Merge branch 'dev' of 127.0.0.1:/xxx/yyyy into dev
# 第一個是 merge commit 遠端倉庫沒有
commit 97e1228aa7d70cf4d9ec984a6cc97b2595c2d3cb (origin/dev)
Author: Logo-Kuo <logo@forblind.org.tw>
Date: Tue Jan 12 12:51:55 2021 +0800
type: fix
system: leave
scope: view/self/controller/model/js
subject: 在留停紀錄頁面加入查詢與刪除詳細留停紀錄功能
# 第二個,這個也是 pull 回來的 commit
commit 93ac02e65ff295426c7c8a4c35634a53d3321077
Author: Logo-Kuo <logo@forblind.org.tw>
Date: Tue Jan 12 15:54:14 2021 +0800
document pdf 3
# 第三個,這個也是 pull 回來的 commit
commit bbd1613aabf14ca0504a17009bca3e1128c90832
Author: Logo-Kuo <logo@forblind.org.tw>
Date: Tue Jan 12 12:51:55 2021 +0800
type: fix
system: leave
scope: view/self/controller/model/js
subject: 在留停紀錄頁面加入查詢與刪除詳細留停紀錄功能
# 從這個開始才是舊的,兩邊分支完全一樣的地方
問題似乎解決了,但如果沒有 push 回去的話,之後就會一直要 merge 了。
先退後拉
讓我們回到還沒 pull 的狀態,還有沒有另外一種不要 merge 也不需要解決衝突的作法。
因為事情其實沒那麼複雜,既然我們 server 端這邊沒有推新的 commit 的話,
那就是完全以遠端倉庫的版本為主就好,這樣整個分支的架構也不會跟遠端倉庫不一制。
從之前的 status 看出有兩個不同 commit, 那我們 server 端就直接退兩個版本再拉回就好。
硬退版
這次我們沒有要把 commit 拆解到工作目錄,所以採用的是有加 --hard
的硬退版。
而且我退了三個版,反正超過兩個就好,理論上不管退幾個都沒關係的,
因為兩個 commit 之前的分支狀況是兩邊完全相同的。
其實,退三個的真正原因是我直接從 merge 完領先3個 commit 的狀態下操作的。
logo@sys:/xxx/test_sys$ git reset --hard HEAD~~~
# 也可以用 ~3
HEAD is now at 4fe1529 type: fix system: leave scope: view/model/controller/self
/js subject: 新增查詢所有員工的年資與留停紀錄
# 看最新的 log
logo@sys:/xxx/test_sys$ git log -1
commit 4fe152957fbd2e9a072861a1e3522d6e14ef1e2f (HEAD -> dev)
Author: Logo-Kuo <logo@forblind.org.tw>
Date: Fri Jan 8 22:36:17 2021 +0800
type: fix
system: leave
scope: view/model/controller/self/js
subject: 新增查詢所有員工的年資與留停紀錄
# 再看一下狀態
logo@sys:/xxx/test_sys$ git status
On branch dev
Your branch is behind 'origin/dev' by 2 commits, and can be fast-forwarded.
(use "git pull" to update your local branch)
nothing to commit, working tree clean
# 變成落後兩個了,那就拉回來更新即可
logo@sys:/xxx/test_sys$ git pull origin dev --tags
logo@127.0.0.1's password:
From 127.0.0.1:/xxx/yyyy
* branch dev -> FETCH_HEAD
Updating 4fe1529..97e1228
Fast-forward
sys/controllers/leaveAdminController.php | 20 ++++++
sys/models/leaveAdminModel.php | 39 +++++++++++-
sys/self/settings.php | 8 +++
sys/static/js/query_stay_time.js | 72 +++++++++++++++++++++-
sys/template/admin/leave/query_stay_time.tpl | 43 +++++++++++--
web_data/sysLlibrary/PDF/sysPDF.php | 30 ---------
.../sysLlibrary/PDF/template/document/document.tpl | 12 ++--
7 files changed, 182 insertions(+), 42 deletions(-)
# 加了 --tags 是因為我們的 commit 有加版本標籤,這部分可參考之前的基礎教學
# 最後再看一下最新的兩個 commit
logo@sys:/xxx/test_sys$ git log -2
commit 97e1228aa7d70cf4d9ec984a6cc97b2595c2d3cb (HEAD -> dev, origin/dev)
Author: Logo-Kuo <logo@forblind.org.tw>
Date: Tue Jan 12 12:51:55 2021 +0800
type: fix
system: leave
scope: view/self/controller/model/js
subject: 在留停紀錄頁面加入查詢與刪除詳細留停紀錄功能
commit 93ac02e65ff295426c7c8a4c35634a53d3321077
Author: Logo-Kuo <logo@forblind.org.tw>
Date: Tue Jan 12 15:54:14 2021 +0800
document pdf 3
# 沒問題,新的有拉回來了
# 看狀態
logo@sys:/xxx/test_sys$ git status
On branch dev
Your branch is up to date with 'origin/dev'.
nothing to commit, working tree clean
終於可以收工了
結語
其實所有操作在之前的文章都有提過,但還是覺得應該多幾次實務操作讓大家熟悉。
之前關於其他合作伙伴的部分都是簡單幾句話說明,現在會儘可能呈現實際操作過程。
但也因為這樣文章會變得比較冗長。