Marcos Ramírez BETA
Terminal en Windows con comandos Git mostrando un renombrado de archivo con cambio de case

Git en Windows: renombrar un archivo cambiando solo el case

· ⏱ 10+ min lectura

Estaba reorganizando los archivos de skills de este blog para que siguieran una convención uniforme: todos los archivos de instrucciones deberían llamarse SKILL.md con la S en mayúsculas. Algunos ya lo cumplían. Otros estaban en minúsculas: skill.md. Parecía un cambio trivial. Hice el git mv, revisé el status… y no había pasado nada. El archivo seguía con el mismo nombre. Git no había registrado ningún cambio. Si has llegado hasta aquí, probablemente te ha pasado lo mismo.

Por qué Git ignora los cambios de case en Windows

El problema tiene dos capas, y las dos trabajan en tu contra. Primera capa: el sistema de archivos de Windows es case-insensitive. Para Windows, skill.md, Skill.md y SKILL.md son exactamente el mismo archivo. Cuando ejecutas mv skill.md SKILL.md, el sistema operativo no hace nada porque interpreta que origen y destino son lo mismo. Segunda capa: Git tiene core.ignorecase=true por defecto en Windows. Al inicializar un repositorio en Windows, Git activa esta opción automáticamente para adaptarse al comportamiento del sistema de archivos. Con ella activa, Git no detecta cambios en el case de los nombres de archivo, aunque esos cambios ocurrieran. El resultado es que el cambio se queda en tierra de nadie: ni el sistema operativo lo ejecuta, ni Git lo rastrea. El archivo sigue llamándose skill.md y los dos están perfectamente de acuerdo en que no ha pasado absolutamente nada.

# Esto NO funciona en Windows
git mv .agents/skills/copywriting/skill.md .agents/skills/copywriting/SKILL.md
# git status no muestra ningún cambio

La solución: el two-step rename

La técnica correcta es hacer el renombrado en dos pasos. Primero renombras el archivo a un nombre completamente diferente (un nombre temporal), y luego renombras ese temporal al nombre final deseado.

# Paso 1: renombrar a un nombre temporal
git mv .agents/skills/copywriting/skill.md .agents/skills/copywriting/skill.md.tmp
# Paso 2: renombrar al nombre final
git mv .agents/skills/copywriting/skill.md.tmp .agents/skills/copywriting/SKILL.md

¿Por qué funciona? En el primer paso hay un cambio de nombre real que tanto Windows como Git pueden registrar sin ambigüedad: de skill.md a skill.md.tmp son nombres distintos, sin historia de case. Git lo anota como rename. En el segundo paso ocurre lo mismo: de skill.md.tmp a SKILL.md es también un cambio claro. El resultado en el staging area de Git es un único rename de skill.md a SKILL.md. Exactamente lo que buscabas desde el principio.

git status
# renamed: .agents/skills/copywriting/skill.md -> .agents/skills/copywriting/SKILL.md

Cuando son varios archivos a la vez

Si tienes que renombrar varios archivos con el mismo patrón, encadenas los comandos en secuencia o los metes en un script. En mi caso eran cinco archivos:

git mv ".agents/skills/copywriting/skill.md" ".agents/skills/copywriting/skill.md.tmp"
git mv ".agents/skills/copywriting/skill.md.tmp" ".agents/skills/copywriting/SKILL.md"
git mv ".agents/skills/copywriting/links/skill.md" ".agents/skills/copywriting/links/skill.md.tmp"
git mv ".agents/skills/copywriting/links/skill.md.tmp" ".agents/skills/copywriting/links/SKILL.md"
git mv ".agents/skills/SEO/skill.md" ".agents/skills/SEO/skill.md.tmp"
git mv ".agents/skills/SEO/skill.md.tmp" ".agents/skills/SEO/SKILL.md"

Tedioso, sí, pero funciona de forma determinista. Tras cada par de comandos, el staging area refleja un rename limpio.

La alternativa: cambiar core.ignorecase

Hay otra forma: decirle a Git que deje de ignorar los cambios de case.

git config core.ignorecase false

Con esta configuración desactivada, Git sí detecta diferencias de case en los nombres de archivo. Puedes hacer el rename directamente:

# Con core.ignorecase=false esto sí funciona
git mv skill.md SKILL.md

Pero esta opción tiene riesgos que conviene conocer antes de tocarla:

  • En sistemas de archivos case-insensitive puedes crear situaciones confusas donde Git cree que tiene dos archivos distintos (skill.md y SKILL.md) pero el sistema operativo solo ve uno.
  • Si el repositorio lo comparten desarrolladores en macOS, Linux y Windows, desactivar core.ignorecase en Windows puede generar comportamientos inconsistentes entre plataformas.
  • Algunos flujos de CI/CD asumen el comportamiento por defecto y se rompen si lo cambias. Mi recomendación: usa el two-step rename. Es más verboso, sí, pero no toca la configuración del repositorio y no introduce sorpresas para el resto del equipo.

Cuándo te encuentras con este problema

Este escenario es mucho más habitual de lo que parece. Algunos casos reales: Convenciones de nombrado en proyectos: Muchos proyectos tienen reglas sobre el case de los archivos. Los componentes de React van en PascalCase (Button.jsx, no button.jsx). Los archivos de configuración suelen ir en mayúsculas (README.md, CHANGELOG.md, LICENSE). Si adoptas estas convenciones tarde en un proyecto, toca renombrar archivos existentes. Unificación de naming en equipos: Cuando un equipo adopta una guía de estilo nueva, los archivos heredados que no la cumplen hay que migrarlos. La migración implica exactamente este tipo de renombrado. Refactoring de módulos: Al reorganizar la estructura de un proyecto, mover módulos entre carpetas o ajustar la jerarquía puede incluir cambios de case que sin el two-step pasan desapercibidos en Windows. Herramientas de generación de código: Algunos scaffolders o generadores crean archivos con un case que luego quieres cambiar para seguir tu propia convención. Si el proyecto ya está en Git, el renombrado manual sin el two-step no llega al repositorio.

Cómo este problema rompe los pipelines de CI/CD

Este es el problema gordo. El que aparece dos semanas después de que el desarrollador haya “solucionado” el caso en su máquina local. El escenario típico: un desarrollador en Windows cambia el case de un archivo. En su máquina, el archivo funciona. Los imports del proyecto funcionan porque Windows no distingue mayúsculas de minúsculas, así que import Button from './button' encuentra Button.jsx sin problema. El desarrollador hace commit y push. Todo perfecto. Llega el pipeline de CI/CD. Normalmente corre en Linux, que sí distingue case. El sistema clona el repositorio, e importa button.jsx con minúscula, pero en el repositorio ese archivo se llama Button.jsx con mayúscula. Error. Build roto. Lo más confuso de esta situación es que el error solo lo ve el CI/CD, nunca el desarrollador local. En Windows el proyecto compila y funciona. En la máquina de CI falla. El desarrollador mira sus cambios, ve que “funciona en mi máquina” y no entiende qué está pasando. He visto esto exactamente en proyectos con Next.js: un componente creado como header.jsx que en algún momento alguien renombró a Header.jsx en Windows sin el two-step. El proyecto funcionaba perfectamente en local para todos los del equipo con Windows o macOS. Cuando se desplegaba en el servidor Linux, el build reventaba con un error de módulo no encontrado que tardaba 20 minutos en diagnosticar la primera vez. La forma de detectarlo antes de que llegue al CI: después de hacer el rename, ejecuta el build localmente con un flag que active el modo estricto de resolución de módulos, o simplemente usa WSL (Windows Subsystem for Linux) para el build final antes del push. WSL tiene el sistema de archivos de Linux y detecta estos problemas en el momento.

Por qué no vale con cambiar el nombre desde el explorador

Una cosa que mucha gente intenta antes de llegar al two-step es renombrar el archivo directamente desde el Explorador de Windows o desde el IDE. Cambias el nombre, guardas, ves que el archivo tiene el nuevo nombre… y el git status no muestra nada. Eso pasa exactamente por las dos capas que expliqué arriba. Windows acepta el rename visualmente, pero el sistema de archivos NTFS no hace ningún cambio real porque trata skill.md y SKILL.md como el mismo nombre. Para NTFS el case no existe en el identificador del archivo, solo en cómo se muestra. Puedes cambiar la capitalización de un nombre en el explorador y NTFS lo guarda como preferencia de visualización, pero no como un cambio de archivo. Git, que comprueba si el inode o el nombre han cambiado, tampoco ve ninguna diferencia. Con core.ignorecase=true encima, ni se molesta en investigar más. Resultado: el archivo visualmente tiene un nombre nuevo, pero para Git y para el sistema operativo es exactamente el mismo archivo de siempre.

Cómo verificar que el cambio se registró correctamente

Antes de hacer el commit, comprueba con git status que el rename aparece como esperas:

git status

Deberías ver algo así:

Changes to be committed:
  renamed: .agents/skills/copywriting/skill.md -> .agents/skills/copywriting/SKILL.md

Si el staging area no muestra nada después del git mv, el cambio no se registró. Asegúrate de que estás usando el two-step. Una vez verificado, el commit es un rename limpio sin modificaciones de contenido:

git commit -m "refactor: rename skill.md to SKILL.md for naming consistency"
git push

En el historial de Git el archivo conserva toda su historia anterior. No es un delete + create: es un rename genuino. Mantener el historial intacto vale mucho más que cualquier alternativa que implique borrar el archivo y volver a crearlo.

El caso de macOS y Linux

En macOS el sistema de archivos HFS+ es case-insensitive por defecto, igual que Windows, así que el problema existe en los mismos términos. El two-step funciona igual. La excepción: si formateaste el disco con APFS en modo “case-sensitive” (disponible desde macOS 10.13), el sistema sí distingue case y git mv directo funcionaría. Pero la mayoría de Macs usa el modo por defecto, que es case-insensitive. En Linux el sistema de archivos es case-sensitive, así que git mv skill.md SKILL.md funciona directamente sin trucos. Pero ojo: si desarrollas principalmente en Linux y alguien del equipo trabaja en Windows, el cambio puede pasar inadvertido en su máquina aunque esté correctamente registrado en el repositorio. Es una fuente habitual de confusión en equipos con mezcla de plataformas.

Preguntas frecuentes

¿Por qué git mv no da ningún error si el renombrado no funciona?

Porque desde la perspectiva de Git el comando se ejecuta sin problemas: el archivo origen existe y el destino es un nombre válido. El hecho de que el sistema de archivos trate ambos nombres como el mismo no genera ningún error. Git simplemente no registra el cambio porque core.ignorecase=true le indica que ignore las diferencias de case.

¿El two-step mantiene el historial del archivo?

Sí. Git rastrea el contenido, no el nombre. El archivo renombrado conserva todo su historial de commits anterior. En git log --follow SKILL.md verás todos los cambios anteriores aunque el archivo se llamara skill.md.

¿Puedo hacer el two-step rename con mv normal en lugar de git mv?

No. Si usas mv del sistema operativo en lugar de git mv, tendrás que hacer git add del archivo nuevo y git rm del antiguo manualmente. Con git mv el staging se gestiona automáticamente y el resultado es un rename limpio, no un delete + add.

¿El problema ocurre también en GitHub o solo en local?

El repositorio en GitHub corre sobre Linux, que es case-sensitive. El problema es estrictamente local: ocurre cuando trabajas en Windows o macOS. Una vez que el rename está correctamente registrado en tu máquina y haces push, GitHub lo almacena con el nombre correcto.


Compártelo si te ha resultado útil. Si tu empresa necesita implementar esto o tienes un problema parecido en un proyecto, hablamos. ¿Te ha pasado algo así con Git en Windows? Cuéntame. Y… ¡hasta aquí por hoy!

Artículos relacionados

Panel de Cloudflare con la sección Workers & Pages mostrando Pages escondida bajo el flujo de Workers

Cloudflare Pages está desapareciendo (y Workers sale ganando)

Cloudflare ha anunciado oficialmente que Pages y Workers se fusionan en una sola plataforma, y el panel ya refleja esa estrategia: Pages aparece enterrada como un enlace pequeño al final de una pantalla orientada a Workers. No es un fallo de UX. Es una decisión de negocio. Te explico qué significa para los sitios estáticos, cuánto te puede costar a futuro y por qué Pages sigue siendo la mejor opción para hosting estático mientras exista.

06:30 8 min Marcos RamírezLucía