Copying files from Stage to Working Directory in git

Viewed 5428

In git there is generally more than one way to do a thing. Broadly git has three concerned areas: The working directory, the stage(index) and the local repository. Every command in git generally moves/copies files from one of these areas to other. While moving files from working directory to stage and to the repository is common, I was wondering about copying/moving files from Stage to Working Directory. One command I know for this is the git checkout -- filename. This discards changes made to that file in the working directory and replaces them with last staged version of the file. I wanted to know if there are anymore different commands for doing the same?

4 Answers

You may unstage a file (move the file from stage back to the working directory) with:

git restore --staged <file>

This is the proposed way from git (version >= 2.23) if you run git status on your repository.

Running git reset will remove your changes in the index (and also in the repository) but will keep them in the working directory

For example, lets say you have added some text to a file and performed git add to add it to the staging area. If you now run:

git reset HEAD^

Then the added text won't be in the staging are (and neither in the repository for that matter), but it will still be present in the working directory. However this is not the same as git checkout -- <file>, since this command restores the files to the last recorded state and discard the changes without the possibility of getting them back. This is considered a risky command so be sure to know what you're doing when running it

In git there is generally more than one way to do a thing.

That's right: Git has a large set of tools, with overlap between them.

Broadly git has three concerned areas: The working directory, the stage(index) and the local repository.

This is also true.

Every command in git generally moves/copies files from one of these areas to other.

I think this is a bit of an overstatement as many of Git's tools don't: e.g., git branch just manipulates branch names, git tag just manipulates tag names, and so on. But there certainly are tools that do this sort of copying.

... I was wondering about copying/moving files from Stage to Working Directory

Prior to Git 2.23, the tools for this were somewhat scattered and clumsy.

In Git 2.23, the git checkout command was split into two separate, better-designed tools: git switch and git restore. The git restore command has tools to copy to index/staging-area, and to working tree. These can be used independently or together.

The git checkout command has only one form for copying from index/staging-area to working tree, which is the one you mentioned:

One command I know for this is the git checkout -- filename

The git reset command is like the old (and still present) git checkout in that it does too many jobs and is not packaged well, but it also can copy from index to working tree. The problem here is that to do so, it must first copy from commit to index. (Also worth noting: it only does this with git reset --hard, and when you use that mode, you're adjusting the entire working tree, not just a single file. This mode therefore has only very specific use cases, though they're somewhat common.)

The git checkout-index command can copy from index to working tree. It's not used very often: it is meant as a so-called plumbing command, used for writing new user-facing tools.

The git show and git cat-file commands can extract any internal object, including those in the index. You can use command-line redirection with these, e.g., git show :0:README.md > index-copy-of-README.md or git cat-file -p :Makefile | wc -l, to let any of your regular tools work with the data.

If you only want to unstage only a particular file you can use

git rm --cached <file>. 
Related