13

If I delete a file, I can revert it in git with:

git checkout filename

If I want to revert all deleted files, I can list them with:

git diff --diff-filter=D --name-only

What I then want to do is restore them, but

git diff --diff-filter=D --name-only | git checkout

Doesn't work, it only repeats the list to stdout, and git checkout seems to receive no input. Ditto for | git checkout HEAD -- and so on.

I've tried this in Windows Command Prompt, in Powershell, and in Git Bash, with the same result each time.

How do I correctly pipe input to git checkout?

Roderick
  • 1,205
  • 11
  • 24

2 Answers2

34

You cannot use a pipe for this. You can however use Unix's xargs:

git diff --diff-filter=D --name-only | xargs git checkout

xargs is a tool that reads from stdin and puts the lines as arguments next to its own arguments and calls the result. So if git diff generates a line a and a line b, xargs git checkout will - at least conceptually - generate the line git checkout a b and call this as a command.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • 3
    Alternative to not use `xargs`: `git checkout -- $(git diff --diff-filter=D --name-only | tr '\n' ' ')` – Antonio Pérez Feb 12 '16 at 12:38
  • 1
    Both of these solutions work with Git Bash on Windows. The xargs version works fine with Windows Command Prompt, though the alternative using $() does not. – Roderick Feb 12 '16 at 12:56
  • I think this is because git bash basically emulates a linux bash shell. But @AntonioPérez indeed shows a nice way to do it removing the `xargs` dependency (although it requires `tr` or another string processing tool which can be a weak spot as well). +1 for antonios comment. – Willem Van Onsem Feb 12 '16 at 13:06
  • Helpful, but... the output of your command gives relative pathnames to the git root, even if you are sitting in a subdir. In my case, I had just mistakenly added all untracked files in a subdir. Is there a way to tame the output of git diff --name-only to give relative pathnames instead? – Starman Jan 15 '18 at 20:08
  • 1
    @Starman: add the `--relative` parameter to the command before the pipe. – Willem Van Onsem Jan 15 '18 at 20:59
  • Nice! I've been looking for a similar solution: `git branch | grep | xargs git checkout` – Dmtzz Aug 18 '21 at 20:18
  • Sorry for the wrong edit (immediately reverted). – VonC Oct 07 '21 at 06:43
3

A pipeline results in the standard output of the command to the left of the pipe being used as the standard input of the command to the right of the pipe. The pipeline git checkout | git diff --diff-filter=D --name-only results in the standard output of the git checkout command being used as the standard input of the git diff --diff-filter=D --name-only command. The git diff command does not use standard input, so the git checkout output is silently ignored and you end up with the output of the git diff command.

Instead, try something like git ls-files --deleted -z | xargs -0 git checkout HEAD --. This uses the null character (\0) to delimit file names and will result in deleted files being checked out. This will work for any valid file names, including those containing spaces and other special characters.

Go Dan
  • 15,194
  • 6
  • 41
  • 65