Git 提交时的 Detached HEAD 问题

4,804 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情

1. 场景再现

某个版本开发过程中,由于代码最新提交存在一定问题,需要对历史提交版本进行修改并发布上线。

为了方便,就选择使用 IDEA 中版本控制的 git checkout [commitId] 命令切换到指定版本。

切换是成功的,并且在当前版本运行打包都没有问题,但是,当对代码进行了修改并进行提交时,就会发现,无法提交!显示 Detached HEAD!

2. Detached HEAD 含义

Git 中正常的流程应该是 HEAD 指向某个分支,分支又有对应的 commitId,这样 HEAD 可以在不同的分支之间进行切换,且每个分支的版本提交也不断进行迭代。

Detached Head,指 HEAD 处于游离状态的,代表 Git 中 HEAD 指针指向了某一个具体的 commitId,而不是指向具体分支。

3. Detached HEAD 的产生和解决方法

3.1 切换到远程分支

使用 git clone 拉取远程项目到本地后,默认拉取远程的 master 并在本地创建同名分支与远程关联;

如果仓库中存在多个分支,使用 git checkout [remoteBranchName] 切换到指定远程分支时,本地并不存在对应的分支,且此时 git 不会自动创建同名分支;

最终可以切换成功,但是会导致出现 Detached HEAD 状态,即此时 HEAD 直接指向了远程分支的最新 commitId。

此种情况下,本地修改的代码无法进行提交,并且在切换分支后 git 会删除修改记录。

解决方法

如果希望切换到指定的远程分支后本地可以正常使用,需要使用命令参数确保 git 切换分支时本地存在关联分支;

git checkout -b [remoteBranchName] 命令来进行分支切换,该命在切换分支时会检查如果本地没有同名分支,则 git 会在本地创建同名分支并进行关联。

3.2 切换到历史版本

在当前分支中,可以使用 git checkout [commitId] 来切换到历史版本并查看历史修改内容;

如果针对切换后代码仅是查看,则没有任何问题;但是当需要在此基础上修改并提交代码时,则会出现大问题!

在使用 git checkout [commitId]git checkout [tagXXX] 命令切换到历史版本后,此时的 HEAD 指向了对应的 commitId,而并没有产生新的分支,因此会成 Detached HEAD 状态!

此时在 git 控制台中使用 git status 查看状态显示:

$ git status
HEAD detached at 232sged
  • HEAD 游离在 232sged 的提交版本处

还可以使用 git branch 查看当前分支信息显示:

$ git branch
* (HEAD detached at 232sged)
V20220527
master
  • HEAD 停留在了一个临时分支之上,即游离状态

解决方法

对于该问题,可以通过创建新分支的方式来解决,保证 HEAD 指向具体的分支,具体流程为:

  1. 针对指定 commitId 创建一个新分支,git branch [branch-name] commitId
  2. 在新分支中进行修改并提交 commit
  3. 切换到目标分支并将新分支合并到目标分支
  4. 将合并后的 commit 记录提交到远程分支
  5. 最后删除临时分支

4. 总结

对于 Git 使用过程中出现的 Detached HEAD 问题,通常是因为操作导致 HEAD 没有指向具体的分支,而是指向了远程分支的 commitId 或本地历史版本 commitId,最终导致在此情况下发生的修改不能正确提交。

可以通过在本地创建分支的方法,将修改设置到具体分支上,并将分支合并到最终需要的分支上,以此委婉的完成修改。

另外,如果确定最新提交记录不再需要,可以使用 git reset 命令回滚到指定版本来进行修改,而不是使用 git checkout [commitId]