0

When I rename an entire folder or do refactoring, I think it's good practice to isolate the rename operation on its own separate commit. If I mix it with other pending modifications, I'll only complicate the verification of the commit. So the commit should have only path rename operations with no other modifications, except when they are renamed references inherent to the refactoring operation (but I would manually stage those).

Is there a simple git command (or shell script / function that I could add to ~/.bash_aliases) that I can use to stage all files that were renamed with no other modifications, and only those?

For simplicity, you may assume nothing else is staged, so you could make it 2 step like:

  1. stage all files
  2. unstage all files that have modifications other than just path renaming

How would I do that?

geekley
  • 1,231
  • 10
  • 27

3 Answers3

2

git status --porcelain=v2 distinguishes between normal changes and renames/copies.
You can add this to bash_aliases:

function gitStageRenamed() {
  git add -A &&
  git status --find-renames=100% --porcelain=v2 |
  grep ^1 | cut -d' ' -f 9- | xargs -rd'\n' git reset
}

This takes all normal edits (lines starting with 1), gets the paths, and passes them to git reset.

If you are not using GNU xargs (Mac), get rid of the -rd'\n', although it will not be as robust (won't handle filenames with spaces and may run git reset even if there are only renames).

jmou
  • 465
  • 4
  • 7
  • Your answer worked for me after I added `--find-renames=100%` from the other answer. Without that, it stages renames with modifications as well (also a valid use case, but not what I prefer, because I want to verify those modifications and stage them manually). See my edit and I'll mark your answer as accepted. Thanks! – geekley Nov 13 '20 at 23:58
2

A cleaner way:

git add .
( IFS=$'\n'
  git reset $(git diff-index -M  --find-renames=100% --diff-filter=r --name-only @)
)
jthill
  • 55,082
  • 5
  • 77
  • 137
1

git status --find-renames=100% --porcelain will mark a "renamed" only pure renames.

Here is a script to make use of this :

#!/bin/bash

git add -A
git status --find-renames=100% --porcelain | grep -v "^R " | cut -c 4- | xargs git reset
LeGEC
  • 46,477
  • 5
  • 57
  • 104
  • `cut` is only returning 1 letter for each line. However, adding `--find-renames=100%` from your answer to the other answer did work, so thanks. – geekley Nov 13 '20 at 23:36
  • Note that the ability to provide `--find-renames=` to `git status` is somewhat new (first appeared in Git 2.18; a lot of distribution have been using older Git versions). – torek Nov 14 '20 at 00:39
  • @geekly : indeed, it should be `cut -c4-` (with an extra "dash", to say "from 4th position to the end") – LeGEC Nov 14 '20 at 13:43