Find/replace all files in a directory? (recursively)

One task I still end up using an IDE for is project wide find-replace.

The steps are as follows.

• Select a directory to replace in
(this could default to the projects root).
• Select the file extensions to match
(this could initialize from other extensions variables, eg ffip-patterns, projectile-other-file-alist).
• Test the replacement, to see what it does.
• Show all replacements, giving the option to skip some.
• Execute or cancel the replacements for all files.

This is something I'm used to from an IDE, is there anything that gives similar functionality in Emacs.

Note that I've seen dired can almost do this, it's not too far from what I'm after, but requires opening and accepting changes in every file, the proceeding steps are a little cumbersome too, although I suppose they could be streamlined.

You say:

Note that I've seen dired can almost do this, it's not too far from what I'm after, but requires opening and accepting changes in every file...

Yes, every file you marked is visited. But it doesn't require you to accept each change individually, as far as I know. If you use either dired-do-find-regexp-and-replace (Q) or dired-do-query-replace-regexp the behavior is that of regular query-replace-regexp, for the most part. In particular, you can use ! to replace all subsequent occurrences in the current file.

And if you use Dired+ then you have a command similar to dired-do-query-replace-regexp, but that acts on files marked in the current listing and in subdirs, recursively: diredp-do-query-replace-regexp-recursive.

• "you can use ! to replace all subsequent occurrences in the current file." - thats the problem. It only operates on the current file. If you have a large code-base this makes it unusable. – ideasman42 Dec 11 '20 at 3:46
• Try pressing Y instead. That is y together with Shift. – Dmitry Dec 11 '20 at 14:20

Use counsel-git-grep from package counsel,

API definition,

(defun counsel-git-grep (&optional initial-input initial-directory cmd)


See its second parameter.

After grepping by calling counsel-git-grep,

• M-x ivy-occur (or press C-c C-o) to export candidates to a buffer
• M-x ivy-wgrep-change-to-wgrep-mode (or press w) to switch to wgrep-mode
• Edit text in buffer
• M-x wgrep-finish-edit (or press C-c C-c) to finalize the changes

See https://sam217pa.github.io/2016/09/11/nuclear-power-editing-via-ivy-and-ag/ for some use case.

In the article, the backend is ag instead of git-grep, but UI is exactly same. There are other grep backends counsel supports.

• I don't have ivy-occur only ivy-occur-mode, this seems to put the current buffer into a non-code mode, which doesn't seem like what I'm after. – ideasman42 Dec 11 '20 at 3:49
• @ideasman42 , the command and its hotkey has not been changed for ages, See github.com/abo-abo/swiper/blob/… – chen bin Dec 11 '20 at 6:23

I'm using projectile-replace projectile-replace-regexp for this purpose.

If the directory which you want to change is not git project still you can use this functions after creating .projectile file in this directory.