聊聊 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 的技术文章,只谈技术不谈八卦 😊

相关文章
相关标签/搜索