web-dev-qa-db-fra.com

Comment faire en sorte que git marque un fichier supprimé et un nouveau fichier comme un fichier déplacé

J'ai déplacé un fichier manuellement, puis je l'ai modifié. Selon Git, il s'agit d'un nouveau fichier et d'un fichier supprimé. Existe-t-il un moyen de forcer Git à le traiter comme un transfert de fichier?

377
pupeno

Git détectera automatiquement le déplacement/renommer si votre modification n'est pas trop sévère. Juste git add le nouveau fichier, et git rm l'ancien fichier. git status indiquera ensuite s'il a détecté le changement de nom. 

en outre, pour les déplacements dans les répertoires, vous devrez peut-être:

  1. cd au sommet de cette structure de répertoire.
  2. Exécuter git add -A .
  3. Exécutez git status pour vérifier que le "nouveau fichier" est maintenant un fichier "renommé"

Si le statut de git indique toujours "nouveau fichier" et non "renommé", vous devez suivre Hank Gay’s conseil et effectuer le déplacement et la modification dans deux commits distincts.

337
Bombe

Effectuez le déplacement et la modification dans des commits séparés.

83
Hank Gay

Tout est une chose perceptuelle. Git est généralement assez bon pour reconnaître les mouvements, parce que GIT est un traqueur de contenu

Tout ce qui dépend vraiment, c'est comment votre "stat" l'affiche. La seule différence ici est le drapeau -M. 

git log --stat -M

commit 9c034a76d394352134ee2f4ede8a209ebec96288
Author: Kent Fredric
Date:   Fri Jan 9 22:13:51 2009 +1300


        Category Restructure

     lib/Gentoo/Repository.pm                |   10 +++++-----
     lib/Gentoo/{ => Repository}/Base.pm     |    2 +-
     lib/Gentoo/{ => Repository}/Category.pm |   12 ++++++------
     lib/Gentoo/{ => Repository}/Package.pm  |   10 +++++-----
     lib/Gentoo/{ => Repository}/Types.pm    |   10 +++++-----
     5 files changed, 22 insertions(+), 22 deletions(-)

git log --stat

commit 9c034a76d394352134ee2f4ede8a209ebec96288
Author: Kent Fredric
Date:   Fri Jan 9 22:13:51 2009 +1300

    Category Restructure

 lib/Gentoo/Base.pm                |   36 ------------------------
 lib/Gentoo/Category.pm            |   51 ----------------------------------
 lib/Gentoo/Package.pm             |   41 ---------------------------
 lib/Gentoo/Repository.pm          |   10 +++---
 lib/Gentoo/Repository/Base.pm     |   36 ++++++++++++++++++++++++
 lib/Gentoo/Repository/Category.pm |   51 ++++++++++++++++++++++++++++++++++
 lib/Gentoo/Repository/Package.pm  |   41 +++++++++++++++++++++++++++
 lib/Gentoo/Repository/Types.pm    |   55 +++++++++++++++++++++++++++++++++++++
 lib/Gentoo/Types.pm               |   55 -------------------------------------
 9 files changed, 188 insertions(+), 188 deletions(-)

journal d'aide git 

   -M
       Detect renames.

   -C
       Detect copies as well as renames. See also --find-copies-harder.
42
Kent Fredric

git diff -M ou git log -M devrait automatiquement détecter ces modifications comme étant un renommer avec des modifications mineures tant qu'elles sont en réalité . Si vos modifications mineures ne sont pas mineures, vous pouvez réduire la similarité, par exemple.

$ git log -M20 -p --stat

pour le réduire de la valeur par défaut de 50% à 20%.

28
gitster

Voici une solution rapide et simplifiée pour un ou plusieurs fichiers renommés et modifiés non validés.

Supposons que le fichier s'appelle foo et qu'il s'appelle maintenant bar:

  1. Renommez bar en un nom temporaire:

    mv bar side
    
  2. Commander foo:

    git checkout HEAD foo
    
  3. Renommez foo en bar avec Git:

    git mv foo bar
    
  4. Maintenant, renommez votre fichier temporaire en bar.

    mv side bar
    

C'est cette dernière étape qui récupère le contenu modifié dans le fichier.

Bien que cela puisse fonctionner, si le fichier déplacé est trop différent du contenu du git original, il sera plus efficace de décider qu'il s'agit d'un nouvel objet. Permettez-moi de démontrer:

$ git status
On branch workit
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   .gitignore
    renamed:    README -> README.md

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   README.md
    modified:   work.js

$ git add README.md work.js # why are the changes unstaged, let's add them.
$ git status
On branch workit
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   .gitignore
    deleted:    README
    new file:   README.md
    modified:   work.js

$ git stash # what? let's go back a bit
Saved working directory and index state WIP on dir: f7a8685 update
HEAD is now at f7a8685 update
$ git status
On branch workit
Untracked files:
  (use "git add <file>..." to include in what will be committed)

    .idea/

nothing added to commit but untracked files present (use "git add" to track)
$ git stash pop
Removing README
On branch workit
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   .gitignore
    new file:   README.md

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:    README
    modified:   work.js

Dropped refs/stash@{0} (1ebca3b02e454a400b9fb834ed473c912a00cd2f)
$ git add work.js
$ git status
On branch workit
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   .gitignore
    new file:   README.md
    modified:   work.js

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:    README

$ git add README # hang on, I want it removed
$ git status
On branch workit
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   .gitignore
    deleted:    README
    new file:   README.md
    modified:   work.js

$ mv README.md Rmd # Still? Try the answer I found.
$ git checkout README
error: pathspec 'README' did not match any file(s) known to git.
$ git checkout HEAD README # Ok the answer needed fixing.
$ git status
On branch workit
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   .gitignore
    new file:   README.md
    modified:   work.js

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:    README.md
    modified:   work.js

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

    Rmd

$ git mv README README.md
$ git status
On branch workit
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   .gitignore
    renamed:    README -> README.md
    modified:   work.js

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   work.js

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

    Rmd

$ mv Rmd README.md
$ git status
On branch workit
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   .gitignore
    renamed:    README -> README.md
    modified:   work.js

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   README.md
    modified:   work.js

$ # actually that's half of what I wanted; \
  # and the js being modified twice? Git prefers it in this case.
27
user186821

Si vous parlez de git status n'indiquant pas les renames, essayez plutôt git commit --dry-run -a

16
BoD

Si vous utilisez TortoiseGit, il est important de noter que la détection de renommage automatique de Git a lieu lors de la validation, mais le fait que cela va se produire n'est pas toujours affiché par le logiciel à l'avance. J'avais déplacé deux fichiers dans un répertoire différent et effectué de légères modifications. J'utilise TortoiseGit comme outil de validation et la liste Modifications apportées indique les fichiers en cours de suppression et d’ajout, pas déplacés. L'exécution du statut git à partir de la ligne de commande a montré une situation similaire. Cependant, après avoir validé les fichiers, ils ont été renommés dans le journal. La réponse à votre question est donc, tant que vous n'avez rien fait de trop drastique, Git devrait automatiquement reprendre le changement de nom. 

Éditer: Apparemment, si vous ajoutez les nouveaux fichiers puis effectuez un statut git à partir de la ligne de commande, le renom doit apparaître avant la validation.

Edit 2: De plus, dans TortoiseGit, ajoutez les nouveaux fichiers dans la boîte de dialogue de validation, mais ne les validez pas. Ensuite, si vous allez dans la commande Afficher le journal et consultez le répertoire de travail, vous verrez si Git a détecté le changement de nom avant la validation.

La même question a été soulevée ici: https://tortoisegit.org/issue/1389 et a été enregistrée en tant que bogue à corriger ici: https://tortoisegit.org/issue/1440 Il s’agit d’un problème d’affichage avec la boîte de dialogue de validation de TortoiseGit et existe en quelque sorte dans le statut git si vous n'avez pas ajouté les nouveaux fichiers.

10
Giles Roberts

Utilisez la commande git mv pour déplacer les fichiers au lieu des commandes de déplacement du système d'exploitation: https://git-scm.com/docs/git-mv

Notez que la commande git mv n'existe que dans les versions 1.8.5 et supérieures de Git. Vous devrez donc peut-être mettre à jour votre Git pour utiliser cette commande.

3

Ou vous pouvez essayer la réponse à cette question ici avec Ambre ! Pour le citer encore:

Tout d’abord, annulez votre ajout par étapes pour le fichier déplacé manuellement:

$ git reset path/to/newfile
$ mv path/to/newfile path/to/oldfile

Ensuite, utilisez Git pour déplacer le fichier:

$ git mv path/to/oldfile path/to/newfile

Bien sûr, si vous avez déjà validé le déplacement manuel, vous souhaiterez peut-être réinitialiser la révision avant le déplacement, puis simplement git mv à partir de là.

2
Zingam

J'ai eu ce problème récemment, lors du déplacement (sans modification) de certains fichiers.

Le problème est que Git a modifié certaines fins de ligne lorsque j'ai déplacé les fichiers et qu'il n'a pas été en mesure de dire que les fichiers étaient les mêmes.

Utiliser git mv a réglé le problème, mais cela ne fonctionne que sur des fichiers/répertoires uniques, et j'avais beaucoup de fichiers à faire à la racine du référentiel.

Une façon de résoudre ce problème serait d'utiliser une magie bash/batch.

Une autre façon est la suivante

  • Déplacez les fichiers et git commit. Ceci met à jour les fins de ligne.
  • Déplacez les fichiers à leur emplacement d'origine, maintenant qu'ils ont les nouvelles fins de ligne, et git commit --amend
  • Déplacez les fichiers à nouveau et git commit --amend. Il n'y a pas de changement aux fins de ligne cette fois, donc Git est heureux
2
cedd

Pour moi, cela a fonctionné pour sauvegarder toutes les modifications avant le commit et les ressortir. Cela a permis à Git de ré-analyser les fichiers ajoutés/supprimés et de les marquer correctement comme déplacés.

1
Alex Ilie

Il existe probablement une meilleure méthode de «ligne de commande» pour le faire, et je sais que c’est un hack, mais je n’ai jamais réussi à trouver une bonne solution.

Utilisation de TortoiseGIT: Si vous avez une validation GIT dans laquelle certaines opérations de déplacement de fichier apparaissent sous la forme de charges d’ajouts/suppressions plutôt que de renommements, même si les fichiers ne contiennent que de petites modifications, procédez comme suit:

  1. Enregistrez ce que vous avez fait localement
  2. Enregistrement dans un mini changement d'une ligne dans un 2e commit
  3. Aller à la connexion GIT dans tortoise git
  4. Sélectionnez les deux commits, cliquez avec le bouton droit de la souris et sélectionnez «fusionner en un seul».

Le nouveau commit affichera maintenant correctement les renominations de fichiers… ce qui aidera à conserver un historique correct des fichiers.

0
Jon Rea

Je comprends cette question comme "Comment faire en sorte que git reconnaisse la suppression d’un ancien fichier et la création d’un nouveau fichier en tant que déplacement de fichier".

Oui dans le répertoire de travail une fois que vous avez supprimé un ancien fichier et inséré un ancien fichier, git status dira "deleted: old_file" et "Untracked files: ... new_file"

Mais dans l'index/le niveau intermédiaire, une fois que vous avez ajouté et supprimé un fichier à l'aide de git, il sera reconnu comme un déplacement de fichier. Pour ce faire, en supposant que vous ayez effectué la suppression et la création à l'aide de votre système d'exploitation, exécutez les commandes suivantes:

git add new_file
git rm old_file

Si le contenu du fichier est identique à 50% ou plus, exécuter la commande git status devrait vous donner:

renamed: old_file -> new_file
0
harshainfo

Lorsque je modifie, renomme et déplace un fichier en même temps, aucune de ces solutions ne fonctionne. La solution consiste à le faire en deux commits (éditer et renommer/déplacer séparément) puis à fixup le deuxième commit via git rebase -i pour l'avoir dans un commit.

0
Hativ