Keep commits made in detached HEAD

How-to Last tested 27 October 2026

To keep a Git commit made in detached HEAD, create a branch at the current commit before switching away. The branch gives the work a named reference, while the reflog is a time-limited local recovery aid if you have already moved away.

Give the detached commit a name

Create a branch at the detached Git commit before switching away to keep a name pointing to it. Detached HEAD means HEAD refers directly to a commit instead of to a branch name, so new commits move no branch. The switch reference distinguishes creating a branch from detaching the checkout1.

Check the current state before creating the name. An uncommitted file, a staged change and a commit are different things. Naming the commit does not automatically commit a working edit, and switching can be refused if it would overwrite local work. Keep a separate copy of valuable uncommitted content before experimenting with another checkout.

Follow the example’s two branches

The example starts with a committed note and a local bare remote. It detaches the checkout, adds a second line and creates a commit. The script records that commit’s identifier, confirms that no branch is checked out, then creates keep-detached-work at the current commit. Its assertion compares the branch tip with the recorded identifier.

The final switch returns to the original branch, while a log check confirms that the retained branch still identifies the detached change. The example does not push the new branch or test a hosting service. A local branch name is a useful reference in this repository; another clone will not see it until it is shared by an appropriate separate operation.

If you already switched away

A reflog records local movements of references, including recent movements of HEAD. It can help identify a previous position in this repository, but it is not a shared archive and it may not contain the position you need. The reflog documentation describes expiration of older and unreachable entries2. The exact retention policy can vary with configuration, so this page gives no promise that a particular entry will still exist.

When a candidate commit is found, inspect it before naming it. Similar subjects or a nearby timestamp can point to the wrong work. Record the identifier and compare the changes with what you expected; then create a suitable reference only after you understand the target. The example retains the commit before switching and does not test reflog recovery, expiration or removal of unreachable objects.

Separate a reference from a backup

A branch makes a commit reachable by name, but it remains inside this repository. It is not protection against loss of the entire repository, and it does not automatically preserve untracked files or edits that were never committed. If the work matters, use an appropriate backup and verify what it contains. The correct backup method depends on the repository and the material involved; this page does not prescribe a remote service.

Avoid force operations while identifying the state. A name already in use may point to work that must not be replaced. Choose a new name after checking existing branches, and stop if the command’s result differs from the expected state. The fictional example starts clean and has a known baseline; a real working tree may require additional inspection before any switch.

Check the state you intend to keep

The example compares the new branch tip with the identifier recorded immediately after the detached commit. That assertion checks a precise relationship: the new name points to that commit. The later subject check confirms the selected branch can still be read after returning to the original branch. Neither check says the commit is correct, reviewed or present on a remote.

If you are unsure whether the relevant work was committed, inspect both the working file and the staged state as well as the current commit. Untracked files can sit beside a clean commit without being part of it. A branch created at HEAD does not capture those files automatically. Save or commit them only after deciding what belongs together; the example intentionally begins with a simple tracked note and verifies its single added line through a commit.

The local reflog is useful precisely because it records movements, not because it guarantees a permanent copy. Expiration rules, deletion of logs and subsequent object cleanup can limit recovery. If a suspected commit is missing, do not assume another reflog or a colleague’s clone has it. Preserve the repository state and any known identifiers before taking further actions that could make investigation harder.

Run the complete local example

Before running: use an empty directory. This script creates example-work, including a fictional working repository and a local bare remote; it stops if that directory already exists. The script creates and switches branches only in its new example repository. Review the commands first and do not point it at a real project.

Download the complete MIT-licensed example and run it with Git 2.56.0. The printed script is the tested file. The two recorded runs used fresh directories and produced the same output; the remote in this example is a local directory.

#!/bin/sh
# SPDX-License-Identifier: MIT
set -eu
export TZ=UTC LC_ALL=C
export GIT_CONFIG_NOSYSTEM=1 GIT_CONFIG_GLOBAL=/dev/null
export GIT_AUTHOR_NAME='Example Author' GIT_AUTHOR_EMAIL='author@example.invalid'
export GIT_COMMITTER_NAME='Example Author' GIT_COMMITTER_EMAIL='author@example.invalid'
export GIT_AUTHOR_DATE='2026-10-27T12:00:00+00:00'
export GIT_COMMITTER_DATE='2026-10-27T12:00:00+00:00'
test "$(git --version)" = 'git version 2.56.0'
mkdir example-work
cd example-work
git init --bare -q --template= --initial-branch=main remote.git
git init -q --template= --initial-branch=main project
cd project
git config commit.gpgsign false
git config core.autocrlf false
git remote add origin ../remote.git
printf 'base\n' > note.txt
git add note.txt
git commit -qm 'Base note'
git push -q -u origin main
git switch -q --detach
printf 'detached work\n' >> note.txt
git add note.txt
git commit -qm 'Detached change'
saved=$(git rev-parse HEAD)
test -z "$(git branch --show-current)"
git switch -q -c keep-detached-work
test "$(git rev-parse keep-detached-work)" = "$saved"
printf 'Detached commit retained by branch keep-detached-work\n'
git switch -q main
test "$(git log -1 --format='%s' keep-detached-work)" = 'Detached change'
printf 'Original branch remains separate\n'

Both runs produced:

Detached commit retained by branch keep-detached-work
Original branch remains separate

The script leaves example-work in the directory where it ran, including the local repositories and their data. After inspecting the result, remove that example directory when it is no longer needed. Do not remove a directory with the same name in a real project unless you have verified its contents and decided it is safe to delete.

Not covered on this page

Sources

  1. git-switch — Git 2.56.0. Git 2.56.0; checked 27 October 2026 UTC. ↩

  2. git-reflog — Git 2.56.0. Git 2.56.0; checked 27 October 2026 UTC. ↩

How we test: methodology. Found a mistake? Corrections.