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?
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
). pourtantgit 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
etgit 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.
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.
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.
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.
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.
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,
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. .
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.
É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
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).
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:
renommé: Project/OldName.h -> Projet/NewName.h renommé: Project/OldName.m -> Projet/NouveauNom.m
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.
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.