Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Q&A

Welcome to Software Development on Codidact!

Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.

Post History

72%
+6 −1
Q&A How can I git checkout the previous HEAD?

There are many ways to get the previous states of HEAD, and which one to use will depend on each situation. Git keeps reference logs (also called "reflogs"), that "record when the tips of branch...

posted 3mo ago by hkotsubo‭  ·  edited 3mo ago by hkotsubo‭

Answer
#3: Post edited by user avatar hkotsubo‭ · 2024-08-21T19:18:21Z (3 months ago)
  • There are many ways to get the previous states of `HEAD`, and which one to use will depend on each situation.
  • ---
  • Git keeps reference logs (also called ["reflogs"](https://git-scm.com/docs/git-reflog)), that "_record when the tips of branches and other references were updated in the local repository_".
  • To provide a simple example, let's start an empty repository and add some commits to it (for the sake of brevity, some outputs were ommited):
  • ```shell
  • $ mkdir project
  • $ cd project/
  • $ git init
  • # create first and second commits
  • $ echo first >> file.txt && git add . && git commit -m"first"
  • $ echo second >> file.txt && git commit -am"second"
  • # see commit history
  • $ git log --oneline
  • 899ed6c (HEAD -> master) second
  • d142056 first
  • ```
  • Now we can run `git reflog` to see the reference logs:
  • ```shell
  • $ git reflog
  • 899ed6c (HEAD -> master) HEAD@{0}: commit: second
  • d142056 HEAD@{1}: commit (initial): first
  • ```
  • Basically, this is the history of how `HEAD` has changed (most recent first). We can also note the notation `HEAD@{N}`, that specifies the N<sup>th</sup> prior value of `HEAD`.
  • Therefore, we can use this in any command that expects a commit/reference, such as `git log HEAD@{1}`, `git diff HEAD@{1}`, `git checkout HEAD@{1}` and so on. `HEAD@{N}` will use the reflogs to search for the commit that corresponds to the N<sup>th</sup> prior value of `HEAD`, and all will work as if you provided the commit hash directly.
  • > Therefore, `HEAD@{0}` is the same as `HEAD`.
  • The reflogs also record when you switch between branches:
  • ```shell
  • # create a branch and switch to it
  • $ git switch -c somebranch # or "git checkout -b somebranch" if Git version is older than 2.23.0
  • $ git reflog
  • 899ed6c (HEAD -> somebranch, master) HEAD@{0}: checkout: moving from master to somebranch
  • 899ed6c (HEAD -> somebranch, master) HEAD@{1}: commit: second
  • d142056 HEAD@{2}: commit (initial): first
  • # add a commit to the branch
  • $ echo branch >> file.txt && git commit -am"branch"
  • $ git reflog
  • d0e4769 (HEAD -> somebranch) HEAD@{0}: commit: branch
  • 899ed6c (master) HEAD@{1}: checkout: moving from master to somebranch
  • 899ed6c (master) HEAD@{2}: commit: second
  • d142056 HEAD@{3}: commit (initial): first
  • $ git log --oneline
  • d0e4769 (HEAD -> somebranch) branch
  • 899ed6c second
  • d142056 first
  • ```
  • Note how it records the branch switching from `master` to `somebranch`. It's also noteworthy that all the `HEAD@{N}` references had also changed (ex: `HEAD@{0}` was pointing to commit `899ed6c`, now it's `d0e4769`). The reflogs numbers are updated everytime there's a new record in it, with `{0}` being the most recent one.
  • Just to add one more example, let's say someone else updated the remote repository and I want to get those updates:
  • ```shell
  • $ git switch master # or "git checkout master" if Git version is older than 2.23.0
  • $ git pull origin master # get updates from the remote
  • $ git reflog
  • 0ff62c8 (HEAD -> master, origin/master) HEAD@{0}: pull origin master: Fast-forward
  • 899ed6c HEAD@{1}: checkout: moving from somebranch to master
  • d0e4769 (origin/somebranch, somebranch) HEAD@{2}: commit: branch
  • 899ed6c HEAD@{3}: checkout: moving from master to somebranch
  • 899ed6c HEAD@{4}: commit: second
  • d142056 HEAD@{5}: commit (initial): first
  • ```
  • <sup>I skipped the parts where I configured the remote and added commit `0ff62c8` to it.</sup>
  • `git pull` also updates `HEAD`, hence this change is recorded in the reflogs as well. As you can see, the reflog is a general way to know how `HEAD` has changed in a particular repository.
  • ---
  • But `git pull` also created two additional references:
  • ```shell
  • $ git log FETCH_HEAD --oneline -1
  • 0ff62c8 (HEAD -> master, origin/master) another
  • $ git log ORIG_HEAD --oneline -1
  • 899ed6c second
  • ```
  • Those are described in the [documentation][1]:
  • - `FETCH_HEAD`: records the branch which you fetched from a remote repository with your last `git fetch` invocation. _Note: [`git pull` calls `git fetch`](https://git-scm.com/docs/git-pull/en#_description), that's why this was created._
  • - `ORIG_HEAD`: is created by commands that move your `HEAD` in a drastic way (`git am`, `git merge`, `git rebase`, `git reset`), to record the position of `HEAD` before their operation, so that you can easily change the tip of the branch back to the state before you ran them. _Note: after fetching, `git pull` also does a merge or a rebase (depending on the configuration or command line options), that's why this was created._
  • So `FETCH_HEAD` refers to the remote branch that was fetched from the remote repository (in this case, `origin/master`, which corresponds to commit `0ff62c8`), and `ORIG_HEAD` points to where `HEAD` was before merging it to `0ff62c8`. We can see those in the commit history:
  • ```shell
  • $ git log --oneline
  • 0ff62c8 (HEAD -> master, origin/master) another
  • 899ed6c second
  • d142056 first
  • ```
  • In the [same documentation][1] you'll also find some other special references, such as `MERGE_HEAD`, that records the commit(s) which you are merging into your branch. Usually it exists only during the merge, and it's deleted after it finishes (so you can check it when there's a conflict, as it's deleted only after you solve or abort it).
  • Those might be helpful if you want more details about the status of `HEAD` during a specific operation. But as general solution, you can always check the reflogs.
  • ---
  • The [documentation][1] also describes some alternative ways to get previous states of `HEAD`, such as `HEAD@{yesterday}`, `HEAD@{5.minutes.ago}` or `HEAD@{2024-08-21T08:30:00}` - you can also use spaces, but in this case the reference must be quoted: `git log "HEAD@{5 minutes ago}"` works, `git log HEAD@{5 minutes ago}` doesn't.
  • And remind that this notation works not only with `HEAD`, but **with any other branch**. So you can use things like `master@{yesterday}` (where the master branch was pointing to yesterday) or `somebranch@{2}` (the second previous value of `somebranch`).
  • And if you ommit the reference, it'll refer to the current branch. So if your current branch is `master`, then `@{yesterday}` will be equivalent to `master@{yesterday}`. **But note that it might not be the same as `HEAD@{yesterday}`**, because `HEAD` could be pointing at a different branch at that time.
  • As a curiosity, `@` is a shortcut for `HEAD`.
  • > Beware: if you use negative numbers, it's a totally different thing. `@{-N}` means "*the N<sup>th</sup> branch/commit checked out before the current one*". And you can't put a reference before it, so `HEAD@{-1}` doesn't work. Negative numbers always refer to commits that were checked out before. As a curiosity, the `git checkout -` command you mentioned is a shortcut for `git checkout @{-1}` ([since version 1.6.2](https://github.com/git/git/blob/master/Documentation/RelNotes/1.6.2.txt)).
  • ---
  • Finally, it's important to remember that **the reflog is stored locally**, and it's not shared with the remote repositories when you fetch, pull or push.
  • Even if you clone the same remote repository in another folder of the same machine, the new clone will have its own separate reflog (which means that `HEAD@{N}` might not be the same in every clone).
  • And if you're using [git-worktree](https://git-scm.com/docs/git-worktree), each worktree will also have its own separate reflog.
  • [1]: https://git-scm.com/docs/gitrevisions "Documentation for Git Revisions"
  • There are many ways to get the previous states of `HEAD`, and which one to use will depend on each situation.
  • ---
  • Git keeps reference logs (also called ["reflogs"](https://git-scm.com/docs/git-reflog)), that "_record when the tips of branches and other references were updated in the local repository_".
  • To provide a simple example, let's start an empty repository and add some commits to it (for the sake of brevity, some outputs were ommited):
  • ```shell
  • $ mkdir project
  • $ cd project/
  • $ git init
  • # create first and second commits
  • $ echo first >> file.txt && git add . && git commit -m"first"
  • $ echo second >> file.txt && git commit -am"second"
  • # see commit history
  • $ git log --oneline
  • 899ed6c (HEAD -> master) second
  • d142056 first
  • ```
  • Now we can run `git reflog` to see the reference logs:
  • ```shell
  • $ git reflog
  • 899ed6c (HEAD -> master) HEAD@{0}: commit: second
  • d142056 HEAD@{1}: commit (initial): first
  • ```
  • Basically, this is the history of how `HEAD` has changed (most recent first). We can also note the notation `HEAD@{N}`, that specifies the N<sup>th</sup> prior value of `HEAD`.
  • Therefore, we can use this in any command that expects a commit/reference, such as `git log HEAD@{1}`, `git diff HEAD@{1}`, `git checkout HEAD@{1}` and so on. `HEAD@{N}` will use the reflogs to search for the commit that corresponds to the N<sup>th</sup> prior value of `HEAD`, and all will work as if you provided the commit hash/branch name directly.
  • > Therefore, `HEAD@{0}` is the same as `HEAD`.
  • The reflogs also record when you switch to another branch:
  • ```shell
  • # create a branch and switch to it
  • $ git checkout -b somebranch # or "git switch -c somebranch" for Git version >= 2.23.0
  • $ git reflog
  • 899ed6c (HEAD -> somebranch, master) HEAD@{0}: checkout: moving from master to somebranch
  • 899ed6c (HEAD -> somebranch, master) HEAD@{1}: commit: second
  • d142056 HEAD@{2}: commit (initial): first
  • # add a commit to the branch
  • $ echo branch >> file.txt && git commit -am"branch"
  • $ git reflog
  • d0e4769 (HEAD -> somebranch) HEAD@{0}: commit: branch
  • 899ed6c (master) HEAD@{1}: checkout: moving from master to somebranch
  • 899ed6c (master) HEAD@{2}: commit: second
  • d142056 HEAD@{3}: commit (initial): first
  • $ git log --oneline
  • d0e4769 (HEAD -> somebranch) branch
  • 899ed6c second
  • d142056 first
  • ```
  • Note how it records the branch switching from `master` to `somebranch`. It's also noteworthy that all the `HEAD@{N}` references had also changed (ex: `HEAD@{0}` was pointing to commit `899ed6c`, now it's `d0e4769`). The reflogs numbers are updated everytime there's a new record in it, with `{0}` being the most recent one.
  • Just to add one more example, let's say someone else updated the remote repository and I want to get those updates:
  • ```shell
  • $ git checkout master # or "git switch master" for Git version >= 2.23.0
  • $ git pull origin master # get updates from the remote
  • $ git reflog
  • 0ff62c8 (HEAD -> master, origin/master) HEAD@{0}: pull origin master: Fast-forward
  • 899ed6c HEAD@{1}: checkout: moving from somebranch to master
  • d0e4769 (origin/somebranch, somebranch) HEAD@{2}: commit: branch
  • 899ed6c HEAD@{3}: checkout: moving from master to somebranch
  • 899ed6c HEAD@{4}: commit: second
  • d142056 HEAD@{5}: commit (initial): first
  • ```
  • > PS: I skipped the parts where I configured the remote and added commit `0ff62c8` to it.
  • `git pull` also updates `HEAD`, hence this change is recorded in the reflogs as well. As you can see, the reflog is a general way to know how `HEAD` has changed in a particular repository.
  • ---
  • But `git pull` also created two additional references:
  • ```shell
  • $ git log FETCH_HEAD --oneline -1
  • 0ff62c8 (HEAD -> master, origin/master) another
  • $ git log ORIG_HEAD --oneline -1
  • 899ed6c second
  • ```
  • Those are described in the [documentation][1]:
  • - `FETCH_HEAD`: records the branch which you fetched from a remote repository with your last `git fetch` invocation. _Note: [`git pull` calls `git fetch`](https://git-scm.com/docs/git-pull/en#_description), that's why this was created._
  • - `ORIG_HEAD`: is created by commands that move your `HEAD` in a drastic way (`git am`, `git merge`, `git rebase`, `git reset`), to record the position of `HEAD` before their operation, so that you can easily change the tip of the branch back to the state before you ran them. _Note: after fetching, `git pull` also does a merge or a rebase (depending on the configuration or command line options), that's why this was created._
  • So `FETCH_HEAD` refers to the remote branch that was fetched from the remote repository (in this case, `origin/master`, which corresponds to commit `0ff62c8`), and `ORIG_HEAD` points to where `HEAD` was before merging it to `0ff62c8`. We can see those in the commit history:
  • ```shell
  • $ git log --oneline
  • 0ff62c8 (HEAD -> master, origin/master) another
  • 899ed6c second
  • d142056 first
  • ```
  • In the [same documentation][1] you'll also find some other special references, such as `MERGE_HEAD`, that records the commit(s) which you are merging into your branch. Usually it exists only during the merge, and it's deleted after it finishes (so you can check it when there's a conflict, as it's deleted only after you solve or abort it).
  • Those might be helpful if you want more details about the status of `HEAD` during a specific operation. But as general solution, you can always check the reflogs.
  • ---
  • The [documentation][1] also describes some other ways to get previous states of `HEAD` in a particular point in time, such as `HEAD@{yesterday}`, `HEAD@{5.minutes.ago}` or `HEAD@{2024-08-21T08:30:00}`. You can also use spaces, but in this case the reference must be quoted: `git log "HEAD@{5 minutes ago}"` works, `git log HEAD@{5 minutes ago}` doesn't.
  • And remind that this notation works not only with `HEAD`, but **with any other branch**. So you can use things like `master@{yesterday}` (where the master branch was pointing to yesterday) or `somebranch@{2}` (the second previous value of `somebranch`).
  • And if you omit the reference, it'll refer to the current branch. So if your current branch is `master`, then `@{yesterday}` will be equivalent to `master@{yesterday}`. **But note that it might not be the same as `HEAD@{yesterday}`**, because `HEAD` could be pointing to a different branch at that time.
  • As a curiosity, `@` is a shortcut for `HEAD`.
  • > Beware: if you use negative numbers, it's a totally different thing. `@{-N}` means "*the N<sup>th</sup> branch/commit checked out before the current one*". And you can't put a reference before it, so `HEAD@{-1}` doesn't work. Negative numbers always refer to commits that were checked out before. As a curiosity, the `git checkout -` command you mentioned is a shortcut for `git checkout @{-1}` ([since version 1.6.2](https://github.com/git/git/blob/master/Documentation/RelNotes/1.6.2.txt)).
  • ---
  • Finally, it's important to remember that **the reflog is stored locally**, and it's not shared with the remote repositories when you fetch, pull or push.
  • Even if you clone the same remote repository in another folder of the same machine, the new clone will have its own separate reflog (which means that `HEAD@{N}` might not be the same in every clone).
  • And if you're using [git-worktree](https://git-scm.com/docs/git-worktree), each worktree will also have its own separate reflog.
  • [1]: https://git-scm.com/docs/gitrevisions "Documentation for Git Revisions"
#2: Post edited by user avatar hkotsubo‭ · 2024-08-21T14:53:40Z (3 months ago)
  • There are many ways to get the previous states of `HEAD`, and which one to use will depend on each situation.
  • ---
  • Git keeps reference logs (also called ["reflogs"](https://git-scm.com/docs/git-reflog)), that "_record when the tips of branches and other references were updated in the local repository_".
  • To provide a simple example, let's start an empty repository and add some commits to it (for the sake of brevity, some outputs were ommited):
  • ```shell
  • $ mkdir project
  • $ cd project/
  • $ git init
  • # create first and second commits
  • $ echo first >> file.txt && git add . && git commit -m"first"
  • $ echo second >> file.txt && git commit -am"second"
  • # see commit history
  • $ git log --oneline
  • 899ed6c (HEAD -> master) second
  • d142056 first
  • ```
  • Now we can run `git reflog` to see the reference logs:
  • ```shell
  • $ git reflog
  • 899ed6c (HEAD -> master) HEAD@{0}: commit: second
  • d142056 HEAD@{1}: commit (initial): first
  • ```
  • Basically, this is the history of how `HEAD` has changed (most recent first). We can also note the notation `HEAD@{N}`, that specifies the N<sup>th</sup> prior value of `HEAD`.
  • Therefore, we can use this in any command that expects a commit/reference, such as `git log HEAD@{1}`, `git diff HEAD@{1}`, `git checkout HEAD@{1}` and so on. `HEAD@{N}` will use the reflogs to search for the commit that corresponds to the N<sup>th</sup> prior value of `HEAD`, and all will work as if you provided the commit hash directly.
  • > Therefore, `HEAD@{0}` is the same as `HEAD`.
  • The reflogs also record when you switch between branches:
  • ```shell
  • # create a branch and switch to it
  • $ git switch -c somebranch # or "git checkout -b somebranch" if Git version is older than 2.23.0
  • $ git reflog
  • 899ed6c (HEAD -> somebranch, master) HEAD@{0}: checkout: moving from master to somebranch
  • 899ed6c (HEAD -> somebranch, master) HEAD@{1}: commit: second
  • d142056 HEAD@{2}: commit (initial): first
  • # add a commit to the branch
  • $ echo branch >> file.txt && git commit -am"branch"
  • $ git reflog
  • d0e4769 (HEAD -> somebranch) HEAD@{0}: commit: branch
  • 899ed6c (master) HEAD@{1}: checkout: moving from master to somebranch
  • 899ed6c (master) HEAD@{2}: commit: second
  • d142056 HEAD@{3}: commit (initial): first
  • $ git log --oneline
  • d0e4769 (HEAD -> somebranch) branch
  • 899ed6c second
  • d142056 first
  • ```
  • Note how it records the branch switching from `master` to `somebranch`. It's also noteworthy that all the `HEAD@{N}` references had also changed (ex: `HEAD@{0}` was pointing to commit `899ed6c`, now it's `d0e4769`). The reflogs numbers are updated everytime there's a new record in it, with `{0}` being the most recent one.
  • Just to add one more example, let's say someone else updated the remote repository and I want to get those updates:
  • ```shell
  • $ git switch master # or "git checkout master" if Git version is older than 2.23.0
  • $ git pull origin master # get updates from the remote
  • $ git reflog
  • 0ff62c8 (HEAD -> master, origin/master) HEAD@{0}: pull origin master: Fast-forward
  • 899ed6c HEAD@{1}: checkout: moving from somebranch to master
  • d0e4769 (origin/somebranch, somebranch) HEAD@{2}: commit: branch
  • 899ed6c HEAD@{3}: checkout: moving from master to somebranch
  • 899ed6c HEAD@{4}: commit: second
  • d142056 HEAD@{5}: commit (initial): first
  • ```
  • <sup>I skipped the parts where I configured the remote and added commit `0ff62c8` to it.</sup>
  • `git pull` also updates `HEAD`, hence this change is recorded in the reflogs as well. As you can see, the reflog is a general way to know how `HEAD` has changed in a particular repository.
  • ---
  • But `git pull` also created two additional references:
  • ```shell
  • $ git log FETCH_HEAD --oneline -1
  • 0ff62c8 (HEAD -> master, origin/master) another
  • $ git log ORIG_HEAD --oneline -1
  • 899ed6c second
  • ```
  • Those are described in the [documentation][1]:
  • - `FETCH_HEAD`: records the branch which you fetched from a remote repository with your last `git fetch` invocation. _Note: [`git pull` calls `git fetch`](https://git-scm.com/docs/git-pull/en#_description), that's why this was created._
  • - `ORIG_HEAD`: is created by commands that move your `HEAD` in a drastic way (`git am`, `git merge`, `git rebase`, `git reset`), to record the position of `HEAD` before their operation, so that you can easily change the tip of the branch back to the state before you ran them. _Note: after fetching, `git pull` also does a merge or a rebase (depending on the configuration or command line options), that's why this was created._
  • So `FETCH_HEAD` refers to the remote branch that was fetched from the remote repository (in this case, `origin/master`, which corresponds to commit `0ff62c8`), and `ORIG_HEAD` points to where `HEAD` was before merging it to `0ff62c8`. We can see those in the commit history:
  • ```shell
  • $ git log --oneline
  • 0ff62c8 (HEAD -> master, origin/master) another
  • 899ed6c second
  • d142056 first
  • ```
  • In the [same documentation][1] you'll also find some other special references, such as `MERGE_HEAD`, that records the commit(s) which you are merging into your branch. Usually it exists only during the merge, and it's deleted after it finishes (so you can check it when there's a conflict, as it's deleted only after you solve or abort it).
  • Those might be helpful if you want more details about the status of `HEAD` during a specific operation. But as general solution, you can always check the reflogs.
  • ---
  • The [documentation][1] also describes some alternative ways to get previous states of `HEAD`, such as `HEAD@{yesterday}`, `HEAD@{5.minutes.ago}` or `HEAD@{2024-08-21T08:30:00}` - you can also use spaces, but in this case the reference must be quoted: `git log "HEAD@{5 minutes ago}"` works, `git log HEAD@{5 minutes ago}` doesn't.
  • And remind that this notation works not only with `HEAD`, but **with any other branch**. So you can use things like `master@{yesterday}` (where the master branch was pointing to yesterday) or `somebranch@{2}` (the second previous value of `somebranch`).
  • And if you ommit the reference, it'll refer to the current branch. So if your current branch is `master`, then `@{yesterday}` will be equivalent to `master@{yesterday}`. **But note that it might not be the same as `HEAD@{yesterday}`**, because `HEAD` could be pointing at a different branch at that time.
  • As a curiosity, `@` is a shortcut for `HEAD`.
  • > Beware: if you use negative numbers, it's a totally different thing. `@{-N}` means "*the N<sup>th</sup> branch/commit checked out before the current one*". And you can't put a reference before it, so `HEAD@{-1}` doesn't work. Negative numbers always refer to commits that were checked out before. As a curiosity, the `git checkout -` command you mentioned is a shortcut for `git checkout @{-1}` ([since version 1.6.2](https://github.com/git/git/blob/master/Documentation/RelNotes/1.6.2.txt)).
  • Finally, it's important to remember that **the reflog is stored locally**, and it's not shared with the remotes when you fetch, pull or push. Even if you clone the same repository in another folder of the same machine, the new clone will have its own separate reflog (which means that `HEAD@{N}` might not be the same in every clone).
  • [1]: https://git-scm.com/docs/gitrevisions "Documentation for Git Revisions"
  • There are many ways to get the previous states of `HEAD`, and which one to use will depend on each situation.
  • ---
  • Git keeps reference logs (also called ["reflogs"](https://git-scm.com/docs/git-reflog)), that "_record when the tips of branches and other references were updated in the local repository_".
  • To provide a simple example, let's start an empty repository and add some commits to it (for the sake of brevity, some outputs were ommited):
  • ```shell
  • $ mkdir project
  • $ cd project/
  • $ git init
  • # create first and second commits
  • $ echo first >> file.txt && git add . && git commit -m"first"
  • $ echo second >> file.txt && git commit -am"second"
  • # see commit history
  • $ git log --oneline
  • 899ed6c (HEAD -> master) second
  • d142056 first
  • ```
  • Now we can run `git reflog` to see the reference logs:
  • ```shell
  • $ git reflog
  • 899ed6c (HEAD -> master) HEAD@{0}: commit: second
  • d142056 HEAD@{1}: commit (initial): first
  • ```
  • Basically, this is the history of how `HEAD` has changed (most recent first). We can also note the notation `HEAD@{N}`, that specifies the N<sup>th</sup> prior value of `HEAD`.
  • Therefore, we can use this in any command that expects a commit/reference, such as `git log HEAD@{1}`, `git diff HEAD@{1}`, `git checkout HEAD@{1}` and so on. `HEAD@{N}` will use the reflogs to search for the commit that corresponds to the N<sup>th</sup> prior value of `HEAD`, and all will work as if you provided the commit hash directly.
  • > Therefore, `HEAD@{0}` is the same as `HEAD`.
  • The reflogs also record when you switch between branches:
  • ```shell
  • # create a branch and switch to it
  • $ git switch -c somebranch # or "git checkout -b somebranch" if Git version is older than 2.23.0
  • $ git reflog
  • 899ed6c (HEAD -> somebranch, master) HEAD@{0}: checkout: moving from master to somebranch
  • 899ed6c (HEAD -> somebranch, master) HEAD@{1}: commit: second
  • d142056 HEAD@{2}: commit (initial): first
  • # add a commit to the branch
  • $ echo branch >> file.txt && git commit -am"branch"
  • $ git reflog
  • d0e4769 (HEAD -> somebranch) HEAD@{0}: commit: branch
  • 899ed6c (master) HEAD@{1}: checkout: moving from master to somebranch
  • 899ed6c (master) HEAD@{2}: commit: second
  • d142056 HEAD@{3}: commit (initial): first
  • $ git log --oneline
  • d0e4769 (HEAD -> somebranch) branch
  • 899ed6c second
  • d142056 first
  • ```
  • Note how it records the branch switching from `master` to `somebranch`. It's also noteworthy that all the `HEAD@{N}` references had also changed (ex: `HEAD@{0}` was pointing to commit `899ed6c`, now it's `d0e4769`). The reflogs numbers are updated everytime there's a new record in it, with `{0}` being the most recent one.
  • Just to add one more example, let's say someone else updated the remote repository and I want to get those updates:
  • ```shell
  • $ git switch master # or "git checkout master" if Git version is older than 2.23.0
  • $ git pull origin master # get updates from the remote
  • $ git reflog
  • 0ff62c8 (HEAD -> master, origin/master) HEAD@{0}: pull origin master: Fast-forward
  • 899ed6c HEAD@{1}: checkout: moving from somebranch to master
  • d0e4769 (origin/somebranch, somebranch) HEAD@{2}: commit: branch
  • 899ed6c HEAD@{3}: checkout: moving from master to somebranch
  • 899ed6c HEAD@{4}: commit: second
  • d142056 HEAD@{5}: commit (initial): first
  • ```
  • <sup>I skipped the parts where I configured the remote and added commit `0ff62c8` to it.</sup>
  • `git pull` also updates `HEAD`, hence this change is recorded in the reflogs as well. As you can see, the reflog is a general way to know how `HEAD` has changed in a particular repository.
  • ---
  • But `git pull` also created two additional references:
  • ```shell
  • $ git log FETCH_HEAD --oneline -1
  • 0ff62c8 (HEAD -> master, origin/master) another
  • $ git log ORIG_HEAD --oneline -1
  • 899ed6c second
  • ```
  • Those are described in the [documentation][1]:
  • - `FETCH_HEAD`: records the branch which you fetched from a remote repository with your last `git fetch` invocation. _Note: [`git pull` calls `git fetch`](https://git-scm.com/docs/git-pull/en#_description), that's why this was created._
  • - `ORIG_HEAD`: is created by commands that move your `HEAD` in a drastic way (`git am`, `git merge`, `git rebase`, `git reset`), to record the position of `HEAD` before their operation, so that you can easily change the tip of the branch back to the state before you ran them. _Note: after fetching, `git pull` also does a merge or a rebase (depending on the configuration or command line options), that's why this was created._
  • So `FETCH_HEAD` refers to the remote branch that was fetched from the remote repository (in this case, `origin/master`, which corresponds to commit `0ff62c8`), and `ORIG_HEAD` points to where `HEAD` was before merging it to `0ff62c8`. We can see those in the commit history:
  • ```shell
  • $ git log --oneline
  • 0ff62c8 (HEAD -> master, origin/master) another
  • 899ed6c second
  • d142056 first
  • ```
  • In the [same documentation][1] you'll also find some other special references, such as `MERGE_HEAD`, that records the commit(s) which you are merging into your branch. Usually it exists only during the merge, and it's deleted after it finishes (so you can check it when there's a conflict, as it's deleted only after you solve or abort it).
  • Those might be helpful if you want more details about the status of `HEAD` during a specific operation. But as general solution, you can always check the reflogs.
  • ---
  • The [documentation][1] also describes some alternative ways to get previous states of `HEAD`, such as `HEAD@{yesterday}`, `HEAD@{5.minutes.ago}` or `HEAD@{2024-08-21T08:30:00}` - you can also use spaces, but in this case the reference must be quoted: `git log "HEAD@{5 minutes ago}"` works, `git log HEAD@{5 minutes ago}` doesn't.
  • And remind that this notation works not only with `HEAD`, but **with any other branch**. So you can use things like `master@{yesterday}` (where the master branch was pointing to yesterday) or `somebranch@{2}` (the second previous value of `somebranch`).
  • And if you ommit the reference, it'll refer to the current branch. So if your current branch is `master`, then `@{yesterday}` will be equivalent to `master@{yesterday}`. **But note that it might not be the same as `HEAD@{yesterday}`**, because `HEAD` could be pointing at a different branch at that time.
  • As a curiosity, `@` is a shortcut for `HEAD`.
  • > Beware: if you use negative numbers, it's a totally different thing. `@{-N}` means "*the N<sup>th</sup> branch/commit checked out before the current one*". And you can't put a reference before it, so `HEAD@{-1}` doesn't work. Negative numbers always refer to commits that were checked out before. As a curiosity, the `git checkout -` command you mentioned is a shortcut for `git checkout @{-1}` ([since version 1.6.2](https://github.com/git/git/blob/master/Documentation/RelNotes/1.6.2.txt)).
  • ---
  • Finally, it's important to remember that **the reflog is stored locally**, and it's not shared with the remote repositories when you fetch, pull or push.
  • Even if you clone the same remote repository in another folder of the same machine, the new clone will have its own separate reflog (which means that `HEAD@{N}` might not be the same in every clone).
  • And if you're using [git-worktree](https://git-scm.com/docs/git-worktree), each worktree will also have its own separate reflog.
  • [1]: https://git-scm.com/docs/gitrevisions "Documentation for Git Revisions"
#1: Initial revision by user avatar hkotsubo‭ · 2024-08-21T13:14:49Z (3 months ago)
There are many ways to get the previous states of `HEAD`, and which one to use will depend on each situation.

---

Git keeps reference logs (also called ["reflogs"](https://git-scm.com/docs/git-reflog)), that "_record when the tips of branches and other references were updated in the local repository_".

To provide a simple example, let's start an empty repository and add some commits to it (for the sake of brevity, some outputs were ommited):

```shell
$ mkdir project
$ cd project/
$ git init

# create first and second commits
$ echo first >> file.txt && git add . && git commit -m"first"
$ echo second >> file.txt && git commit -am"second"

# see commit history
$ git log --oneline
899ed6c (HEAD -> master) second
d142056 first
```

Now we can run `git reflog` to see the reference logs:

```shell
$ git reflog
899ed6c (HEAD -> master) HEAD@{0}: commit: second
d142056 HEAD@{1}: commit (initial): first
```

Basically, this is the history of how `HEAD` has changed (most recent first). We can also note the notation `HEAD@{N}`, that specifies the N<sup>th</sup> prior value of `HEAD`.

Therefore, we can use this in any command that expects a commit/reference, such as `git log HEAD@{1}`, `git diff HEAD@{1}`, `git checkout HEAD@{1}` and so on. `HEAD@{N}` will use the reflogs to search for the commit that corresponds to the N<sup>th</sup> prior value of `HEAD`, and all will work as if you provided the commit hash directly.

> Therefore, `HEAD@{0}` is the same as `HEAD`.

The reflogs also record when you switch between branches:

```shell
# create a branch and switch to it
$ git switch -c somebranch # or "git checkout -b somebranch" if Git version is older than 2.23.0
$ git reflog
899ed6c (HEAD -> somebranch, master) HEAD@{0}: checkout: moving from master to somebranch
899ed6c (HEAD -> somebranch, master) HEAD@{1}: commit: second
d142056 HEAD@{2}: commit (initial): first

# add a commit to the branch
$ echo branch >> file.txt && git commit -am"branch"
$ git reflog
d0e4769 (HEAD -> somebranch) HEAD@{0}: commit: branch
899ed6c (master) HEAD@{1}: checkout: moving from master to somebranch
899ed6c (master) HEAD@{2}: commit: second
d142056 HEAD@{3}: commit (initial): first

$ git log --oneline 
d0e4769 (HEAD -> somebranch) branch
899ed6c second
d142056 first
```

Note how it records the branch switching from `master` to `somebranch`. It's also noteworthy that all the `HEAD@{N}` references had also changed (ex: `HEAD@{0}` was pointing to commit `899ed6c`, now it's `d0e4769`). The reflogs numbers are updated everytime there's a new record in it, with `{0}` being the most recent one.

Just to add one more example, let's say someone else updated the remote repository and I want to get those updates:

```shell
$ git switch master  # or "git checkout master" if Git version is older than 2.23.0
$ git pull origin master # get updates from the remote
$ git reflog
0ff62c8 (HEAD -> master, origin/master) HEAD@{0}: pull origin master: Fast-forward
899ed6c HEAD@{1}: checkout: moving from somebranch to master
d0e4769 (origin/somebranch, somebranch) HEAD@{2}: commit: branch
899ed6c HEAD@{3}: checkout: moving from master to somebranch
899ed6c HEAD@{4}: commit: second
d142056 HEAD@{5}: commit (initial): first
```

<sup>I skipped the parts where I configured the remote and added commit `0ff62c8` to it.</sup>

`git pull` also updates `HEAD`, hence this change is recorded in the reflogs as well. As you can see, the reflog is a general way to know how `HEAD` has changed in a particular repository.

---

But `git pull` also created two additional references:

```shell
$ git log FETCH_HEAD --oneline -1
0ff62c8 (HEAD -> master, origin/master) another

$ git log ORIG_HEAD --oneline -1
899ed6c second
```

Those are described in the [documentation][1]:

- `FETCH_HEAD`: records the branch which you fetched from a remote repository with your last `git fetch` invocation. _Note: [`git pull` calls `git fetch`](https://git-scm.com/docs/git-pull/en#_description), that's why this was created._
- `ORIG_HEAD`: is created by commands that move your `HEAD` in a drastic way (`git am`, `git merge`, `git rebase`, `git reset`), to record the position of `HEAD` before their operation, so that you can easily change the tip of the branch back to the state before you ran them. _Note: after fetching, `git pull` also does a merge or a rebase (depending on the configuration or command line options), that's why this was created._

So `FETCH_HEAD` refers to the remote branch that was fetched from the remote repository (in this case, `origin/master`, which corresponds to commit `0ff62c8`), and `ORIG_HEAD` points to where `HEAD` was before merging it to `0ff62c8`. We can see those in the commit history:

```shell
$ git log --oneline
0ff62c8 (HEAD -> master, origin/master) another
899ed6c second
d142056 first
```

In the [same documentation][1] you'll also find some other special references, such as `MERGE_HEAD`, that records the commit(s) which you are merging into your branch. Usually it exists only during the merge, and it's deleted after it finishes (so you can check it when there's a conflict, as it's deleted only after you solve or abort it).

Those might be helpful if you want more details about the status of `HEAD` during a specific operation. But as general solution, you can always check the reflogs.

---

The [documentation][1] also describes some alternative ways to get previous states of `HEAD`, such as `HEAD@{yesterday}`, `HEAD@{5.minutes.ago}` or `HEAD@{2024-08-21T08:30:00}` - you can also use spaces, but in this case the reference must be quoted: `git log "HEAD@{5 minutes ago}"` works, `git log HEAD@{5 minutes ago}` doesn't.

And remind that this notation works not only with `HEAD`, but **with any other branch**. So you can use things like `master@{yesterday}` (where the master branch was pointing to yesterday) or `somebranch@{2}` (the second previous value of `somebranch`).

And if you ommit the reference, it'll refer to the current branch. So if your current branch is `master`, then `@{yesterday}` will be equivalent to `master@{yesterday}`. **But note that it might not be the same as `HEAD@{yesterday}`**, because `HEAD` could be pointing at a different branch at that time.

As a curiosity, `@` is a shortcut for `HEAD`.

> Beware: if you use negative numbers, it's a totally different thing. `@{-N}` means "*the N<sup>th</sup> branch/commit checked out before the current one*". And you can't put a reference before it, so `HEAD@{-1}` doesn't work. Negative numbers always refer to commits that were checked out before. As a curiosity, the `git checkout -` command you mentioned is a shortcut for `git checkout @{-1}` ([since version 1.6.2](https://github.com/git/git/blob/master/Documentation/RelNotes/1.6.2.txt)).

Finally, it's important to remember that **the reflog is stored locally**, and it's not shared with the remotes when you fetch, pull or push. Even if you clone the same repository in another folder of the same machine, the new clone will have its own separate reflog (which means that `HEAD@{N}` might not be the same in every clone).


  [1]: https://git-scm.com/docs/gitrevisions "Documentation for Git Revisions"