聊聊 git 中 detached HEAD、amend、rebase 和 reset

聊聊 git 中 detached HEAD、amend、rebase 和 reset

20190609235612.png

⭐️ 更多前端技術和知識點,搜索訂閱號 JS 菌 訂閱

分離頭致使 commit 丟失

分離頭是指 checkout 歷史版本後,作了修改並提交 commit,這時切回別的分支,以前提交的 commit 就會被拋棄。若是想要保留須要手動建立一個新的分支。css

查看提交記錄前端

git log --oneline

能夠看到有兩個提交記錄git

7c53c63 (HEAD -> master) 建立文件
c034a61 init

這時 checkout 到歷史版本web

Note: checking out 'c034a61'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b <new-branch-name>

HEAD is now at c034a61 init

如今就出現了分離頭,在這個時候修改文件內容app

diff --git a/fdsa b/fdsa
index e69de29..2d7a928 100644
--- a/fdsa
+++ b/fdsa
@@ -0,0 +1 @@
+change file content
(END)

查看 status編輯器

HEAD detached at c034a61
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   fdsa

no changes added to commit (use "git add" and/or "git commit -a")

提交 commit 就會提示 detached HEAD 修改this

git commit -am 'modify'

[detached HEAD 9a78be9] modify
 1 file changed, 1 insertion(+)

若是此時 checkout 分支,這些提交的內容就會在之後的某個時間點被 git 拋棄。spa

git checkout master

Warning: you are leaving 1 commit behind, not connected to
any of your branches:

  9a78be9 modify

If you want to keep it by creating a new branch, this may be a good time
to do so with:

 git branch <new-branch-name> 9a78be9

Switched to branch 'master'

按照提示,使用命令 git branch xxx 9a78be9 就能夠建立分支,保留全部這些 commitcode

git branch -a

  another
* master
(END)

HEAD 版本比較兩種操做符的區別

diff commit 的時候常常須要查看當前 commit 和上一個版本或上上個版本的差別,^~ 的操做符兩個用法是不同的orm

git diff HEAD HEAD^

這個指的是 HEAD 和 HEAD 上一個版本的比較等同於 git diff HEAD HEAD^1 也等同於 git diff HEAD HEAD~1

git diff HEAD HEAD^^

這個指的是 HEAD 和 HEAD 的上上個版本的比較,等同於 git diff HEAD HEAD^1^1 也等同於 git diff HEAD HEAD~2

因此你覺得有 git diff HEAD HEAD^2 這樣的使用方法嗎?那就錯了,並無 HEAD^2 你必須寫成 HEAD~2 或者 HEAD^1^1 🤕

fatal: ambiguous argument 'HEAD^2': unknown revision or path not in the working tree.

amend 並不能修改歷史提交信息

一般咱們使用 git commit --amend 來修改最近一次提交的 message,那麼修改歷史提交的 commit message,怎麼操做呢。並無什麼 git commit --amend^ 之類的東西,正確的作法是使用 rebase

2842585 (HEAD -> master) add app.js
7c53c63 建立文件
c034a61 init

假設須要修改第二次的提交信息,將 建立文件 改爲 add main.css,那麼使用 rebase 的交互式命令:

git rebase -i c034a61

注意 hash 值是要修改的 commit 的上一個 commit

pick 7c53c63 建立文件
pick 2842585 add app.js

# Rebase c034a61..2842585 onto c034a61 (2 commands)
#

出現上述提示,咱們須要使用 reword 修改 commit 提交信息,修改第一個 pick 爲 reword:

reword 7c53c63 建立文件
pick 2842585 add app.js

保存,接着就會彈出新的窗口,這個時候就能夠修改 commit message 了,保存便可:

[detached HEAD 9ccb083] add main.css
 Date: Fri Jun 7 12:54:21 2019 +0800
 1 file changed, 1 insertion(+)
Successfully rebased and updated refs/heads/master.

提示修改爲功

c0bf3b1 (HEAD -> master) add app.js
9ccb083 add main.css
c034a61 init

另外 rebase 還有不少其餘用途,好比合並歷史 commit:

reword 9ccb083 add main.css
squash c0bf3b1 add app.js

將兩個 commit 合併,並修改最新的提交信息

[detached HEAD b46e9cc] init website
 Date: Fri Jun 7 12:54:21 2019 +0800
 1 file changed, 1 insertion(+)
[detached HEAD 209f417] init website
 Date: Fri Jun 7 12:54:21 2019 +0800
 2 files changed, 1 insertion(+)
 create mode 100644 app.js
Successfully rebased and updated refs/heads/master.

合併後效果以下:

209f417 (HEAD -> master) init website
c034a61 init

rebase 能夠合併多個非相鄰的 commit

若是咱們想要合併多個 commit 但這些 commit 並非緊挨着的,而是分散開來的。那麼使用 rebase 仍然仍是能夠合併的:

1421dc2 (HEAD -> master) init server app
209f417 init website
c034a61 init

假設有三個 commit 我須要將第一個和最新的 commit 合併,那麼使用 rebase:

git rebase -i c034a61

彈出編輯器:

pick 209f417 init website
pick 1421dc2 init server app

由於第一個沒有顯示,那麼須要手動添加

pick 209f417 init website
pick 1421dc2 init server app
pick c034a61

而後調整順序:

pick 1421dc2 init server app
squash c034a61
pick 209f417 init website

這樣 c034a61 就會和 init server app 合併

若是有衝突那麼解決衝忽然後 rebase --continue 或放棄 rebase --abort

checkout、clean 和 reset 的回退

checkout 和 reset 都是用於恢復文件的,但二者的區別是 checkout 是恢復工做區的,reset 則是恢復暫存區到工做區的。

假設目前是這種狀況:

On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   read.me

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   app.js

Untracked files:
  (use "git add <file>..." to include in what will be committed)

    readme.md

看到提示咱們將暫存區的 read.me 恢復則須要使用 reset;若是須要將修改後的工做區的文件 app.js 恢復則使用 checkout;另外還有未追蹤的文件 readme.md,這個文件的恢復則須要使用到 clean

咱們挨個來恢復:

git clean -f

首先使用 clean 命令清空工做區中未追蹤的文件

Removing readme.md

而後使用

git checkout .

清空工做區修改的文件

Updated 1 path from the index

最後再恢復暫存區中的文件:

git reset HEAD .

恢復完成後,暫存區的文件會變爲工做區的文件,這個時候還須要再次 checkout 或 clean 一下,這取決於你是新增的文件仍是修改已有的文件

JS 菌公衆帳號

請關注個人訂閱號,不按期推送有關 JS 的技術文章,只談技術不談八卦 😊

相關文章
相關標籤/搜索