Because I wanted to look at the files in the last release, tagged v2.1
, to run it in isolation from my working directory, I created a tmp
directory
mkdir /tmp/lastRelease
and extracted the last release in that directory
git --work-tree=/tmp/lastRelease checkout tags/v2.1 -- .
The files are indeed extracted just fine to /tmp/lastRelease
.
But now when I run git status
in the working directory I find that very many files (all the files modified since tag v2.1?) appear as staged for commit, and another long list of files (that are in HEAD) appears as not staged for commit.
Was this last command the right way to extract a specific tag? How do I reset to HEAD? (The obvious git checkout HEAD
doesn't modify what git status
says, even though the files are there.)
CodePudding user response:
It doesn't (do anything to your current working tree). What it does effectively damage / mess-up is the (singular) index. (It also will affect HEAD
.)
Each non-bare Git repository has one working tree, one index, and one HEAD
. That one index is used by git checkout
or git switch
; that one HEAD
is set by it. When you run:
git --work-tree=<path> checkout ...
your Git extracts the specified commit—the ...
part—and writes it through the index into the working tree.
Normally, the working tree to which your git checkout
or git switch
would write is the (singular) working tree. But with --work-tree
you temporarily override that one working tree with one different working tree—so that is the working tree to which this Git operation writes. But you have not changed the (singular) index, nor the (singular) HEAD
, and git checkout
or git switch
will write to those as well.
The HEAD
keeps track of the current commit by containing:
- a raw hash ID, or
- the name of the current branch (with the branch name itself then containing the commit hash ID).
The index holds your proposed next commit, which starts out matching the current commit—so that when you switch commits, Git first removes the existing checked-out commit's files (as recorded in the index and stored in the existing in the working tree), and then plugs in the target commit's files (to the index and working tree). Using --work-tree
to re-point the working tree, without first cleaning out and removing the current working tree and index, leaves them out of sync.
If you don't mind the effect on HEAD
, and are otherwise using this git checkout
or git switch
for a special purpose, consider setting GIT_INDEX_FILE
to the name of a temporary file that does not exist now, and that you will delete once the git checkout
or git switch
finishes.
If you do mind the effect on HEAD
, or intend to do this for more general purposes, consider not using git --work-tree checkout
like this at all: instead, make sure your Git is at least 2.15, and begin using git worktree
. See the git worktree
documentation for more about git worktree
.
CodePudding user response:
This is only a partial answer. I don't know why the working directory gets messed up when extracting to an unrelated directory, but it's possible to return to a sane state—the one where the repo was just before the git --work-tree...
command—by running:
git reset --hard HEAD
CodePudding user response:
What you wanted to do was either
git archive v2.1 | tar Cx /path/to/tmp/tree
or
git worktree add /path/to/tmp/tree v2.1
or
git clone -sb v2.3 . /path/to/tmp/tree
or even
scratch=`mktemp -d`
GIT_INDEX_FILE=$PWD/.git/scratch-index git --work-tree=$scratch read-tree -um v2.1
because as @torek points out git checkout
is a convenience command, built for "standard" workflows where your work trees are for content you're actively tracking; the index is Git's manifest for what you last checked out or added there, and HEAD
is its ancestor commit.