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

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

⭐️ 更多前端技术和知识点,搜索订阅号 JS 菌 订阅

分离头导致 commit 丢失

分离头是指 checkout 历史版本后,做了修改并提交 commit,这时切回别的分支,之前提交的 commit 就会被抛弃。如果想要保留需要手动创建一个新的分支。

查看提交记录

git log --oneline
复制代码

可以看到有两个提交记录

7c53c63 (HEAD -> master) 创建文件
c034a61 init
复制代码

这时 checkout 到历史版本

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
复制代码

现在就出现了分离头,在这个时候修改文件内容

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 修改

git commit -am 'modify'

[detached HEAD 9a78be9] modify
 1 file changed, 1 insertion(+)
复制代码

如果此时 checkout 分支,这些提交的内容就会在以后的某个时间点被 git 抛弃。

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 就可以创建分支,保留所有这些 commit

git branch -a

  another
* master
(END)
复制代码

HEAD 版本比较两种操作符的区别

diff commit 的时候经常需要查看当前 commit 和上一个版本或上上个版本的差异,^~ 的操作符两个用法是不一样的

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

转载于:https://juejin.im/post/5cfd2ca6e51d45777540fd81

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值