<?xml version="1.0" encoding="utf-8"?> 
<rss version="2.0"
  xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
  xmlns:atom="http://www.w3.org/2005/Atom">

<channel>

<title>Blog — George Mishurovsky: posts tagged refactoring</title>
<link>https://mishurovsky.com/blog/?go=tags/refactoring/</link>
<description>A blog by George Mishurovsky — a senior software engineer with a medical degree. Drawing from both engineering and scientific thinking, he explores software, architecture, design, psychology, and product thinking.</description>
<author></author>
<language>en</language>
<generator>Aegea 11.3 (v4134e)</generator>

<itunes:owner>
<itunes:name></itunes:name>
<itunes:email>george@mishurovsky.com</itunes:email>
</itunes:owner>
<itunes:subtitle>A blog by George Mishurovsky — a senior software engineer with a medical degree. Drawing from both engineering and scientific thinking, he explores software, architecture, design, psychology, and product thinking.</itunes:subtitle>
<itunes:image href="https://mishurovsky.com/blog/pictures/userpic/userpic-square@2x.jpg?1753619610" />
<itunes:explicit>no</itunes:explicit>

<item>
<title>Renaming Entities Project-Wide with find, grep, sed, and rename</title>
<guid isPermaLink="false">17</guid>
<link>https://mishurovsky.com/blog/?go=all/how-to-bulk-rename-some-entity-and-files-in-a-project/</link>
<pubDate>Mon, 20 Oct 2025 15:07:33 +0200</pubDate>
<author></author>
<comments>https://mishurovsky.com/blog/?go=all/how-to-bulk-rename-some-entity-and-files-in-a-project/</comments>
<description>
&lt;p&gt;There are times in software projects when a big shift happens in domain representation. This results in changes of project structure, class responsibilities, and occasionally, requires bulk renames of entities across the whole codebase.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://mishurovsky.com/blog/pictures/bulk-rename@2x.png" width="667" height="388" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Imagine we need to rename every &lt;span class="inline-code"&gt;Employee&lt;/span&gt; to &lt;span class="inline-code"&gt;Worker&lt;/span&gt;. This change should affect both file paths and textual occurrences throughout the project.&lt;/p&gt;
&lt;p&gt;Renaming may sound like a simple problem: assuming there are no external dependencies using the target name, we just need to rename all occurrences of it inside a repository. But there multiple caveats:&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;We must rename both file names and folder names.&lt;/li&gt;
&lt;li&gt;We must rename all code and text occurrences.&lt;/li&gt;
&lt;li&gt;Casing must be preserved: &lt;span class="inline-code"&gt;Employee → Worker&lt;/span&gt;, and &lt;span class="inline-code"&gt;employee → worker&lt;/span&gt;.&lt;/li&gt;
&lt;li&gt;Both plain and compound usages must be properly renamed: &lt;span class="inline-code"&gt;createEmployee → createWorker&lt;/span&gt;.&lt;/li&gt;
&lt;li&gt;Non-code,  non-document files must not be affected (consider binary files which by coincidence might have an &lt;span class="inline-code"&gt;...employee...&lt;/span&gt; fragment inside).&lt;/li&gt;
&lt;li&gt;There are folders or files which we would want to omit from renaming (e. g., &lt;span class="inline-code"&gt;.git&lt;/span&gt;).&lt;/li&gt;
&lt;li&gt;No IDE provides such functionality, so we cannot rely on existing solutions.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I will address all these challenges in a solution below, but there is an important complexity that cannot be tackled with automation. If by any chance your code depends on a library with the target name (e. g., &lt;span class="inline-code"&gt;employee.js&lt;/span&gt;) or uses exports from a library containing the target name (&lt;span class="inline-code"&gt;import type { valuableEmployeee } from ‘employee-js’&lt;/span&gt;), you’ll have to resolve issues manually after renaming.&lt;/p&gt;
&lt;h2&gt;Reviewing Expected Changes&lt;/h2&gt;
&lt;p&gt;First, remove any folders and files that are recreated during project builds or setup: &lt;span class="inline-code"&gt;build/&lt;/span&gt;, &lt;span class="inline-code"&gt;dist/&lt;/span&gt;, &lt;span class="inline-code"&gt;node_modules/&lt;/span&gt;, &lt;span class="inline-code"&gt;.storybook-static/&lt;/span&gt;, etc. This step isn’t strictly necessary, but it can help iterate faster if commands encounter errors.&lt;/p&gt;
&lt;p&gt;Now, let’s start with renaming text occurrences by listing all files that might get affected with &lt;span class="inline-code"&gt;find&lt;/span&gt; command. Here I am using &lt;span class="inline-code"&gt;-iname&lt;/span&gt; for case-insensitive search and `-not -path ‘&lt;name&gt;’` syntax to exclude folders we need to protect from changes.&lt;/p&gt;
&lt;div class="e2-code-block" data-language="sh"&gt;&lt;div class="e2-code-header"&gt;&lt;span class="e2-code-language"&gt;Shell&lt;/span&gt;&lt;button class="e2-code-copy" type="button" aria-label="Copy code to clipboard" data-copy-text="Copy" data-copied-text="Copied!" data-failed-text="Failed"&gt;&lt;span class="e2-svgi"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"&gt;&lt;mask id="cutout"&gt;&lt;rect width="100%" height="100%" fill="white"/&gt;&lt;rect x="1.75" y="5.25" width="9" height="9" stroke-width="1.33" rx="1" fill="black" stroke="black"/&gt;&lt;/mask&gt;&lt;rect x="5.25" y="1.75" width="9" height="9" rx="1" stroke-width="1.33" fill="none" mask="url(#cutout)"/&gt;&lt;rect x="1.75" y="5.25" width="9" height="9" rx="1" stroke-width="1.33" fill="none"/&gt;&lt;/svg&gt;
&lt;/span&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class="hljs language-sh"&gt;find . -not -path &amp;#039;*/.*&amp;#039; -not -path &amp;#039;src/protected&amp;#039; -iname &amp;#039;*employee*&amp;#039;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Revise the output: make sure it does not contain folders or files you do not want to be changed.&lt;/p&gt;
&lt;p&gt;Then, let’s see which text occurrences inside our files will be affected. Same approach: case-insensitive search in all files, excluding protected directories or files.&lt;/p&gt;
&lt;div class="e2-code-block" data-language="sh"&gt;&lt;div class="e2-code-header"&gt;&lt;span class="e2-code-language"&gt;Shell&lt;/span&gt;&lt;button class="e2-code-copy" type="button" aria-label="Copy code to clipboard" data-copy-text="Copy" data-copied-text="Copied!" data-failed-text="Failed"&gt;&lt;span class="e2-svgi"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"&gt;&lt;mask id="cutout"&gt;&lt;rect width="100%" height="100%" fill="white"/&gt;&lt;rect x="1.75" y="5.25" width="9" height="9" stroke-width="1.33" rx="1" fill="black" stroke="black"/&gt;&lt;/mask&gt;&lt;rect x="5.25" y="1.75" width="9" height="9" rx="1" stroke-width="1.33" fill="none" mask="url(#cutout)"/&gt;&lt;rect x="1.75" y="5.25" width="9" height="9" rx="1" stroke-width="1.33" fill="none"/&gt;&lt;/svg&gt;
&lt;/span&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class="hljs language-sh"&gt;grep -RIn -i --exclude-dir=&amp;#039;*/.*&amp;#039; --exclude-dir=&amp;#039;src/protected&amp;#039; &amp;#039;employee&amp;#039; .&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the output you’ll see all lines containing the target name. Revise all them carefully: if you want to protect some names from changes, you might want to add file names to exclusion, or rename such occurrences manually to some special value (e. g. &lt;span class="inline-code"&gt;em#plo#yee&lt;/span&gt;), so you can revert it later.&lt;/p&gt;
&lt;h2&gt;Renaming Text Occurences&lt;/h2&gt;
&lt;p&gt;Now we can rename all text occurrences, handling separately each casing. It will require some &lt;span class="inline-code"&gt;sed&lt;/span&gt; magic:&lt;/p&gt;
&lt;div class="e2-code-block" data-language="sh"&gt;&lt;div class="e2-code-header"&gt;&lt;span class="e2-code-language"&gt;Shell&lt;/span&gt;&lt;button class="e2-code-copy" type="button" aria-label="Copy code to clipboard" data-copy-text="Copy" data-copied-text="Copied!" data-failed-text="Failed"&gt;&lt;span class="e2-svgi"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"&gt;&lt;mask id="cutout"&gt;&lt;rect width="100%" height="100%" fill="white"/&gt;&lt;rect x="1.75" y="5.25" width="9" height="9" stroke-width="1.33" rx="1" fill="black" stroke="black"/&gt;&lt;/mask&gt;&lt;rect x="5.25" y="1.75" width="9" height="9" rx="1" stroke-width="1.33" fill="none" mask="url(#cutout)"/&gt;&lt;rect x="1.75" y="5.25" width="9" height="9" rx="1" stroke-width="1.33" fill="none"/&gt;&lt;/svg&gt;
&lt;/span&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class="hljs language-sh"&gt;LC_CTYPE=UTF-8 find . -type f \
  -not -path &amp;#039;*/.*&amp;#039; \
  \( -name &amp;#039;*.ts&amp;#039; -o -name &amp;#039;*.tsx&amp;#039; -o -name &amp;#039;*.js&amp;#039; -o -name &amp;#039;*.json&amp;#039; \) \
  -exec sed -i &amp;#039;s/Employee/Worker/g; s/employee/worker/g&amp;#039; {} +&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There are two important points here. First, &lt;span class="inline-code"&gt;LC_CTYPE=UTF-8&lt;/span&gt; allows us to treat all file characters as UTF-8, even if the situation is different. Without it, &lt;span class="inline-code"&gt;sed&lt;/span&gt; stops when encounters non-UTF-8 characters. Second, we use &lt;span class="inline-code"&gt;-o -name ‘*.ext’&lt;/span&gt; syntax to list file extensions to be affected. This prevents accidental changes of binary or image file contents.&lt;/p&gt;
&lt;h2&gt;Renaming Paths&lt;/h2&gt;
&lt;p&gt;Hopefully, file content renaming finished successfully. From here we will proceed with renaming of file and folder names. For this we will use &lt;span class="inline-code"&gt;rename&lt;/span&gt; command ingesting &lt;span class="inline-code"&gt;find&lt;/span&gt; output:&lt;/p&gt;
&lt;div class="e2-code-block" data-language="sh"&gt;&lt;div class="e2-code-header"&gt;&lt;span class="e2-code-language"&gt;Shell&lt;/span&gt;&lt;button class="e2-code-copy" type="button" aria-label="Copy code to clipboard" data-copy-text="Copy" data-copied-text="Copied!" data-failed-text="Failed"&gt;&lt;span class="e2-svgi"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"&gt;&lt;mask id="cutout"&gt;&lt;rect width="100%" height="100%" fill="white"/&gt;&lt;rect x="1.75" y="5.25" width="9" height="9" stroke-width="1.33" rx="1" fill="black" stroke="black"/&gt;&lt;/mask&gt;&lt;rect x="5.25" y="1.75" width="9" height="9" rx="1" stroke-width="1.33" fill="none" mask="url(#cutout)"/&gt;&lt;rect x="1.75" y="5.25" width="9" height="9" rx="1" stroke-width="1.33" fill="none"/&gt;&lt;/svg&gt;
&lt;/span&gt;Copy&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class="hljs language-sh"&gt;find . -not -path &amp;#039;*/.*&amp;#039; -depth -name &amp;#039;*Employee*&amp;#039; \
  -exec rename &amp;#039;s/Employee/Worker/g&amp;#039; {} +
find . -not -path &amp;#039;*/.*&amp;#039; -depth -name &amp;#039;*employee*&amp;#039; \
  -exec rename &amp;#039;s/employee/worker/g&amp;#039; {} +&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;These commands might produce warnings. If you have file paths that include multiple occurrences of the target name, the renames will be performed only for the first one, so you will have to run the commands multiple times until the paths are fully renamed.&lt;/p&gt;
&lt;p&gt;And that’s it! ✨&lt;br /&gt;
If you created any specially-renamed entities, rename them back manually. Then run &lt;span class="inline-code"&gt;git add&lt;/span&gt; and &lt;span class="inline-code"&gt;git commit&lt;/span&gt; — git should detect all path renames automatically.&lt;/p&gt;
</description>
</item>


</channel>
</rss>