Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion web/docs/how-to/discarding-changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Treq doesn't support discarding specific lines directly. As a workaround, commit

## Recovery

There's no direct undo for discarded changes. Check your editor's local history (VS Code, IntelliJ), look for auto-save copies, or check git reflog if changes were previously committed.
There's no direct undo for discarded changes. Check your editor's local history (VS Code, IntelliJ), look for auto-save copies, or check the [git reflog](/learn/concepts/git/git-reflog) if changes were previously committed.

Before discarding uncertain changes, create a safety net with `git stash push -m "backup"` or [commit](/docs/concepts/commit-management) to a temporary branch.

Expand Down
2 changes: 1 addition & 1 deletion web/docs/how-to/moving-files-between-workspaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,5 @@ git reset HEAD~1

## Recovery

If you moved the wrong files and haven't committed in the destination, discard there and check the source's stash or reflog. If already committed, reset the commit in the destination and move files back.
If you moved the wrong files and haven't committed in the destination, discard there and check the source's stash or [reflog](/learn/concepts/git/git-reflog). If already committed, reset the commit in the destination and move files back.

125 changes: 125 additions & 0 deletions web/learn/concepts/git/git-reflog.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
---
sidebar_position: 6
---

import DefinitionCard from "@site/src/components/DefinitionCard";

# What is the Git Reflog?

_The reflog is a local journal of where `HEAD` and branch refs pointed over time._

## Introduction

Git's commit history is the directed acyclic graph of parent links. The **reflog** records something else: each time a local reference moves. Checkouts, commits, resets, [rebases](./merge-vs-rebase), and similar commands append entries so you can find commits that no longer hang from any branch tip.

That journal stays on the machine that wrote it. `git push` and `git fetch` do not send reflogs, so recovery with them is always local.

## Understanding the Concept

A **reflog** is an append-only log of reference updates for one [clone](./git-worktrees-vs-clones). Global `HEAD` updates go in `.git/logs/HEAD`. Branch updates go in files such as `.git/logs/refs/heads/main`. Each entry stores the previous and new tip hashes, who made the change, a timestamp, and a short description of the action.

<DefinitionCard
term="Reflog"
definition="A local, append-only log of updates to HEAD or another Git reference, stored under .git/logs/ and never shared by fetch or push."
/>

Commit history answers which commits are ancestors of a tip. The reflog answers which commits a reference pointed at after each local command, including tips that are no longer reachable from any branch.

| | Commit history | Reflog |
| --- | --- | --- |
| Shape | Parent links in the commit graph | Chronological list of ref updates |
| Scope | Shared across clones after fetch or push | Local to one repository |
| Lifetime | Objects remain while reachable or until pruned | Entries expire on configured schedules |
| Use | Inspect lineage and collaboration history | Recover moved or orphaned tips |

After a hard reset, a failed rebase, or deleting an unmerged branch, commits can leave the branch topology while their objects stay in the object database. The reflog still names those tips until its entries expire and garbage collection removes the unreachable objects.

Git also writes **`ORIG_HEAD`** before some rewrite operations such as reset, merge, and rebase. That ref is a single bookmark of the prior `HEAD`, useful for a quick undo without scanning the full log.

<DefinitionCard
term="ORIG_HEAD"
definition="A local reference Git sets to the previous HEAD value before selected rewrite operations, so you can reset back to that tip quickly."
/>

## Applying It in Practice

Inspect recent `HEAD` movements:

```bash
git reflog
git reflog show main
```

Address a prior tip with positional or time-based syntax:

```bash
git show HEAD@{2}
git log -1 main@{one.week.ago}
git checkout HEAD@{2.hours.ago}
```

`HEAD@{n}` means the nth prior recorded tip for that ref, counting from zero as the current position. Time forms such as `main@{yesterday}` select the tip as of that wall-clock time in the local reflog.

Restore a branch after a mistaken hard reset:

```bash
git reflog
git reset --hard HEAD@{1}
```

Create a branch at an orphaned tip you still need, including after `git branch -D`:

```bash
git reflog
# find checkout: moving from feature/login to main
git branch feature/login abc1234
```

Deletion removes the name under `.git/refs/heads/`. It does not remove the commits. The `HEAD` reflog keeps tip hashes from earlier checkouts, so you can [recreate the branch](/learn/how-to/recover-deleted-git-branch) while those entries and objects remain.

Use `ORIG_HEAD` when you know the last rewrite was the mistake:

```bash
git reset --hard ORIG_HEAD
```

Message search such as `HEAD^{/fix login}` walks ancestors of `HEAD` by commit message. That is revision syntax on the commit graph, not a reflog query.

## Engineering Considerations

The reflog recovers commits that were once referenced locally. It does not recover uncommitted working-tree edits or deleted untracked files, because those states never entered the object database.

It also cannot recover history rewritten only on a remote by someone else. Another clone's reflog never reaches you. A branch that was never checked out in this clone leaves no local `HEAD` footprint, so remote pull-request metadata or another clone must supply the tip hash.

Keep protected branches free of unexpected force pushes, and coordinate when a shared tip must move.

Recovery races the retention window. Once an entry expires and `git gc` prunes the unreachable objects, the tip is gone from that clone.

Jujutsu logs repository-changing commands in an [operation log](./version-control). `jj undo` and `jj op log` cover a similar recovery need with a different command model. In a colocated repository you can still inspect Git reflogs for Git-side ref movement.

## Scaling and Operations

`git gc` expires reflog entries using two settings:

| Setting | Default | Applies to |
| --- | --- | --- |
| `gc.reflogExpire` | 90 days | Entries whose tips remain reachable |
| `gc.reflogExpireUnreachable` | 30 days | Entries whose tips are unreachable |

After expiration, disconnected blobs and trees become eligible for removal on the next prune. Shorten these windows only when disk use matters more than local recovery depth.

Force immediate expiry when you must reclaim space after filtering leaked secrets from history:

```bash
git reflog expire --expire=now --all
git gc --prune=now --aggressive
```

Do that only after you have rotated credentials and confirmed no remaining local tip still needs those objects. Aggressive prune is permanent on that clone.

## Next Steps

- [What is Version Control?](./version-control): review commits, branches, and recovery basics
- [Merge vs Rebase](./merge-vs-rebase): understand rewrite operations that move refs
- [Cherry-pick vs Rebase](./cherry-pick-vs-rebase): compare selective replay with branch rewriting
- [What are Git Worktrees?](./git-worktrees): each worktree keeps its own `HEAD` and reflog entries
2 changes: 1 addition & 1 deletion web/learn/concepts/git/git-worktrees-vs-clones.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ A **linked worktree** has its own working tree, `HEAD`, and index. It shares the
definition="An additional working directory attached to an existing Git repository, with its own HEAD and index but a shared object database and shared refs."
/>

A **clone** has its own Git directory. Its local branches, remote-tracking refs, config, reflogs, stash, and object database all move on their own, with no effect on another clone.
A **clone** has its own Git directory. Its local branches, remote-tracking refs, config, [reflogs](./git-reflog), stash, and object database all move on their own, with no effect on another clone.

<DefinitionCard
term="Clone"
Expand Down
5 changes: 5 additions & 0 deletions web/learn/concepts/git/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ Start with Git's data model, then learn how to manage parallel and dependent bra
href: "/learn/concepts/git/merge-vs-rebase",
label: "Merge vs Rebase",
},
{
type: "link",
href: "/learn/concepts/git/git-reflog",
label: "What is the Git Reflog?",
},
{
type: "link",
href: "/learn/concepts/git/cherry-pick-vs-rebase",
Expand Down
3 changes: 2 additions & 1 deletion web/learn/concepts/git/version-control.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ jj bookmark create feature/add-login
jj git push --bookmark feature/add-login
```

Jujutsu also logs every command that changes the repository. `jj undo` reverses the last one, and `jj op log` shows earlier states. Git gives you the same kind of rescue at a lower level, through refs and reflogs.
Jujutsu also logs every command that changes the repository. `jj undo` reverses the last one, and `jj op log` shows earlier states. Git gives you the same kind of rescue at a lower level, through refs and [reflogs](./git-reflog).

Pick Jujutsu because its working-copy, conflict, and history-editing model suits your team. Do not pick it expecting Git hosting and tooling to go away, because most collaboration still crosses a Git boundary.

Expand All @@ -118,4 +118,5 @@ Keep generated files, credentials, and build output out of commits unless the pr
- [What are Git Worktrees?](./git-worktrees): use several working directories with one repository
- [Git Worktrees vs Clones](./git-worktrees-vs-clones): compare shared and independent repositories
- [Merge vs Rebase](./merge-vs-rebase): choose how to integrate diverged histories
- [What is the Git Reflog?](./git-reflog): recover local tips after resets and rewrites
- [What are Stacked PRs?](./stacked-prs): organize dependent changes for review
1 change: 1 addition & 0 deletions web/learn/how-to/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ For guides on the Treq app itself, such as pushing, discarding changes, and sett
{type: 'link', href: '/learn/how-to/review-ai-generated-prs', label: 'Review AI-Generated PRs'},
{type: 'link', href: '/learn/how-to/merge-conflicts-with-coding-agents', label: 'Fix Merge Conflicts from Coding Agents'},
{type: 'link', href: '/learn/how-to/git-worktrees-vs-clones-for-agents', label: 'Git Worktrees vs Clones for Agents'},
{type: 'link', href: '/learn/how-to/recover-deleted-git-branch', label: 'Recover a Deleted Git Branch'},
]} />
72 changes: 72 additions & 0 deletions web/learn/how-to/recover-deleted-git-branch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
sidebar_position: 15
description: Recover a locally deleted Git branch by finding its tip in the HEAD reflog and recreating the branch ref.
---

# Recover a Deleted Git Branch

_Find the tip in the local `HEAD` reflog, then recreate the branch ref at that commit._

## Goal

Restore a branch deleted with `git branch -d` or `git branch -D` while its tip is still in the local object database.

## Why deletion is reversible

`git branch -D` removes the name under `.git/refs/heads/`. It does not delete the commits those names pointed at. The objects stay in the database until garbage collection prunes unreachable tips.

The branch's own log under `.git/logs/refs/heads/` usually disappears with the name. Recovery depends on the **[`HEAD` reflog](/learn/concepts/git/git-reflog)**, which still records checkouts that moved onto or off that branch. Those entries keep the tip hash you need.

If you never checked the branch out in this [clone](/learn/concepts/git/git-worktrees-vs-clones), the local `HEAD` reflog has no footprint to search. Use a remote that still has the tip, closed pull-request metadata, or another clone that did check it out.

## Recover the branch

List recent `HEAD` movements:

```bash
git reflog
```

Find the last tip of the deleted branch. Checkout lines often look like `checkout: moving from feature/login to main`. The hash on that line is the tip of `feature/login` at the moment you left it.

Recreate the name at that commit:

```bash
git branch feature/login abc1234
```

Or check it out in one step:

```bash
git switch -c feature/login abc1234
```

Confirm the tip and recent history:

```bash
git log --oneline -5 feature/login
```

The new ref makes those commits reachable again. [Push](/docs/how-to/pushing-to-remote) when you need the branch on a remote:

```bash
git push -u origin feature/login
```

## When this fails

Local recovery needs a local record of the tip. These cases do not provide one:

- The branch existed only on a hosting service and was never checked out here.
- The branch tip was merged through a remote pull request without a local checkout of that branch.
- The matching reflog entry expired and `git gc` already pruned the unreachable objects.

In the remote-only cases, open the closed pull request or hosting UI and copy the head commit hash, then run `git branch <name> <hash>` after fetching that object if needed. Hosting platforms do not share their internal reflogs with `git fetch`.

Act before retention windows lapse. Unreachable reflog entries default to about 30 days under `gc.reflogExpireUnreachable`. After prune, the tip is gone from this clone.

## Related

- [Discarding Changes](/docs/how-to/discarding-changes): recovery options when uncommitted work is gone
- [What is Version Control?](/learn/concepts/git/version-control): commits, branches, and local recovery basics
- [Merge vs Rebase](/learn/concepts/git/merge-vs-rebase): rewrite operations that move refs and leave tips to recover
Loading