Question

I have been reading the examples of how stash command can ease the life and came across this code snippet:

# ... hack hack hack ...
$ git checkout -b my_wip
$ git commit -a -m "WIP"
$ git checkout master
$ edit emergency fix
$ git commit -a -m "Fix in a hurry"
$ git checkout my_wip
$ git reset --soft HEAD^
# ... continue hacking ... 

As I get, what happens here is the following:

We create a new branch at the current commit:

--1
  |
  master
  my_wip
  HEAD

Then we stage modified files and make new commit to my_wip branch:

--1 ------------ 2
  |              |
  master         my_wip
                 HEAD

Then we checkout master:

--1 ------------ 2
  |              |
  master         my_wip
  HEAD

Then we modify some files and make a new commit (with preliminary staging (-a flag)):

                 HEAD
                 master
                 |
    -------------3
   /
  /
--1 ------------ 2
                 |
                 my_wip

Then we checkout my_wip:

                 master
                 |
    -------------3
   /
  /
--1 ------------ 2
                 |
                 my_wip
                 HEAD

Then we do git reset --soft HEAD^.

After this command I expect git to move HEAD to its previous position, namely 3 commit. So I expect it would get us into this stage (with working directory and staging area from 2 commit):

                 HEAD
                 master
                 my_wip
                 |
    -------------3
   /
  /
--1 ------------ 2

But as I'm getting from the docs, it does this (as after unstashing we should get to the position where we were when decided to stash):

                master
                 |
    -------------3
   /
  /
--1 ------------ 2
  |              
  my_wip
  HEAD           

Does it mean that HEAD^ is the previous position of the current branch and so it is dependent of the branch selected (I always thought that HEAD^ is just the previous position of HEAD regardless of the current branch)? Or am I miscomprehending something?

Was it helpful?

Solution

In git the concept head is not general. It is so that every branch has, so to say, its own head pointing normally to the last commit in the timeline for that branch.

On the other hand HEAD exists just once per repository and points to the head of the current branch, that is the current head.

So HEAD is always used within the context of your branch and not of the whole repository. That's the reason why git reset --soft HEAD^ moves you one commit back and not to the previous position

If you take a look at the files within the .git folder you can clearly appreciate this concept:

.git/HEAD

This file contains a reference to the position where the HEAD (uppercase) of the repo is

.git/refs/heads

This folder contains one file for each branch with the reference to its head (lowercase). The previous file will usually point to one of these unless there is a detached HEAD

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top