web-dev-qa-db-fra.com

Gérer les renom de fichiers dans git

J'avais lu que lorsque renommer des fichiers dans git , vous devriez valider toutes les modifications, effectuer le changement de nom, puis organiser le fichier renommé. Git reconnaîtra le fichier à partir du contenu plutôt que de le voir comme un nouveau fichier non suivi et conservera l'historique des modifications.

Cependant, justement ce soir, j'ai fini par revenir à git mv.

> $ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   modified:   index.html
#

Renommez ma feuille de style dans le Finder de iphone.css à mobile.css

> $ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   modified:   index.html
#
# Changed but not updated:
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   deleted:    css/iphone.css
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#   css/mobile.css

Donc, git pense maintenant que j'ai supprimé un fichier CSS et en ai ajouté un nouveau. Pas ce que je veux, permet d'annuler le changement de nom et de laisser git faire le travail.

> $ git reset HEAD .
Unstaged changes after reset:
M   css/iphone.css
M   index.html

Retour à où j'ai commencé.

> $ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   modified:   index.html
#

Permet d'utiliser git mv à la place.

> $ git mv css/iphone.css css/mobile.css
> $ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   renamed:    css/iphone.css -> css/mobile.css
#
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   index.html
#

On dirait que nous sommes bons. Alors pourquoi git n’a-t-il pas reconnu le changement de nom la première fois que j’ai utilisé Finder?

410
Greg K

Pour git mv, le page de manuel dit

L'index est mis à jour après avoir terminé avec succès, [....]

Donc, vous devez d’abord mettre à jour vous-même l’index (en utilisant git add mobile.css). pourtant
git status affichera toujours deux fichiers différents

$ git status
# On branch master
warning: LF will be replaced by CRLF in index.html
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:   index.html
#       new file:   mobile.css
#
# Changed but not updated:
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       deleted:    iphone.css
#

Vous pouvez obtenir une sortie différente en exécutant git commit --dry-run -a, ce qui donne ce que vous attendez.

Tanascius@H181 /d/temp/blo (master)
$ git commit --dry-run -a
# On branch master
warning: LF will be replaced by CRLF in index.html
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:   index.html
#       renamed:    iphone.css -> mobile.css
#

Je ne peux pas vous dire exactement pourquoi nous voyons ces différences entre git status et
git commit --dry-run -a, mais voici un indice de Linus

git ne se soucie vraiment pas de toute la "détection de renom" en interne, et tous les commits que vous avez effectués avec les renommés sont totalement indépendants de l'heuristique que nous avons ensuite utiliser pour afficher les renommés.

Un dry-run utilise les mécanismes de renommage réels, alors qu'un git status ne le fait probablement pas.

327
tanascius

Vous devez ajouter les deux fichiers modifiés à l'index avant que git le reconnaisse comme un déplacement.

La seule différence entre mv old new et git mv old new est que git mv ajoute également les fichiers à l'index.

mv old new puis git add -A aurait également fonctionné.

Notez que vous ne pouvez pas simplement utiliser git add . car cela n'ajoute pas de suppressions à l'index.

Voir Différence entre "git add -A" et "git add."

73
nonrectangular

La meilleure chose à faire est de l'essayer soi-même.

mkdir test
cd test
git init
touch aaa.txt
git add .
git commit -a -m "New file"
mv aaa.txt bbb.txt
git add .
git status
git commit --dry-run -a

Désormais, git status et git commit --dry-run -a affichent deux résultats différents, où git status indique bbb.txt lorsqu'un nouveau fichier/aaa.txt est supprimé et les commandes --dry-run indiquent le renommage réel.

~/test$ git status

# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   new file:   bbb.txt
#
# Changes not staged for commit:
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   deleted:    aaa.txt
#


/test$ git commit --dry-run -a

# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   renamed:    aaa.txt -> bbb.txt
#

Maintenant, allez-y et faites le check-in.

git commit -a -m "Rename"

Vous pouvez maintenant voir que le fichier est en fait renommé et que ce qui est affiché dans l'état git est faux.

Morale de l'histoire: Si vous n'êtes pas sûr que votre fichier ait été renommé, lancez un "git commit --dry-run -a". Si cela montre que le fichier est renommé, vous pouvez continuer.

19
dimuthu

vous devez git add css/mobile.css le nouveau fichier et git rm css/iphone.css, afin que git le sache. alors il affichera la même sortie dans git status

vous pouvez le voir clairement dans la sortie de statut (le nouveau nom du fichier):

# Untracked files:
#   (use "git add <file>..." to include in what will be committed)

et (l'ancien nom):

# Changed but not updated:
#   (use "git add/rm <file>..." to update what will be committed)

je pense que dans les coulisses git mv n’est rien de plus qu’un script wrapper qui fait exactement cela: supprime le fichier de l’index et l’ajoute sous un autre nom.

10
knittl

Pour git 1.7.x, les commandes suivantes ont fonctionné pour moi:

git mv css/iphone.css css/mobile.css
git commit -m 'Rename folder.' 

Il n’y avait aucun besoin de git add, car le fichier original (css/mobile.css) était déjà dans les fichiers validés auparavant.

10
GrigorisG

Pensons à vos fichiers du point de vue de Git.

Gardez à l'esprit que git ne suit aucune métadonnée de vos fichiers

Votre référentiel a (entre autres)

$ cd repo
$ ls
...
iphone.css
...

et il est sous contrôle git:

$ git ls-files --error-unmatch iphone.css &>/dev/null && echo file is tracked
file is tracked

Testez ceci avec:

$ touch newfile
$ git ls-files --error-unmatch newfile &>/dev/null && echo file is tracked
(no output, it is not tracked)
$ rm newfile

Quand tu fais

$ mv iphone.css mobile.css

Du point de vue de git,

  • il n'y a pas iphone.css (il est supprimé, -git en avertit).
  • il y a un nouveau fichier mobile.css.
  • Ces fichiers sont totalement indépendants.

Ainsi, git conseille les fichiers qu’il connaît déjà (iphone.css) et les nouveaux fichiers qu’il détecte (mobile.css), mais uniquement lorsque les fichiers sont dans l’index ou HEAD git commence à vérifier leur contenu.

À ce moment, ni "suppression de iphone.css" ni mobile.css ne sont sur l'index.

Ajouter la suppression iphone.css à l'index

$ git rm iphone.css

git vous dit exactement ce qui s'est passé: (iphone.css est supprimé. Rien de plus ne s'est passé)

puis ajoutez un nouveau fichier mobile.css

$ git add mobile.css

Cette fois, la suppression et le nouveau fichier sont dans l'index. Maintenant, git détecte que le contexte est le même et l'expose comme un changement de nom. En fait, si les fichiers sont similaires à 50%, cela sera détecté en tant que renommage, ce qui vous permettra de modifier mobile.css tout en conservant l'opération en tant que renommage.

Voir ceci est reproductible sur git diff. Maintenant que vos fichiers sont sur l'index, vous devez utiliser --cached. Éditez mobile.css un peu, ajoutez-le à l'index et voyez la différence entre:

$ git diff --cached 

et

$ git diff --cached -M

-M est l'option "détecter les renommés" pour git diff. -M signifie -M50% (50% ou plus de similitudes feront en sorte que git l'exprime en tant que renom) mais vous pouvez le réduire à -M20% (20%) si vous modifiez beaucoup le fichier mobile.css. .

9
albfan

Git reconnaîtra le fichier à partir du contenu, plutôt que de le voir comme un nouveau fichier non suivi

C'est là que tu as mal tourné.

Ce n'est que après vous ajoutez le fichier, que git le reconnaîtra à partir du contenu.

7
hasen

Étape 1: renommez le fichier de oldfile en newfile

git mv #oldfile #newfile

Étape 2: git commit et ajouter des commentaires

git commit -m "rename oldfile to newfile"

Étape 3: Transmettez cette modification au serveur distant

git Push Origin #localbranch:#remotebranch
7
Haimei

Vous n'avez pas mis en scène les résultats de votre déplacement dans le Finder. Je crois que si vous aviez déplacé via le Finder, puis git add css/mobile.css ; git rm css/iphone.css, git calculait le hachage du nouveau fichier et réalisait alors seulement que les hachages des fichiers correspondaient (et qu'il s'agirait donc d'un changement de nom).

3
Mike Seplowitz

Pour les utilisateurs de Xcode: Si vous renommez votre fichier dans Xcode, l'icône du badge change pour l'ajouter. Si vous effectuez un commit en utilisant XCode, vous allez créer un nouveau fichier et perdre l'historique.

Une solution de contournement est simple mais vous devez le faire avant de valider avec Xcode:

  1. Faites un statut git sur votre dossier. Vous devriez voir que les changements mis en scène sont corrects:

renommé: Project/OldName.h -> Projet/NewName.h renommé: Project/OldName.m -> Projet/NouveauNom.m

  1. commettez -m 'changement de nom'

Revenez ensuite à XCode et vous verrez le badge changé de A à M et il est sauvegardé pour valider les changements ultérieurs en utilisant xcode maintenant.

2
doozMen

Dans les cas où vous devez vraiment renommer les fichiers manuellement, par exemple. utiliser un script pour renommer par lots un tas de fichiers, puis utiliser git add -A . a fonctionné pour moi.

2
pckben