Supprimer des fichiers de Git commit

1613

J'utilise Git et j'ai engagé quelques fichiers en utilisant

git commit -a

Plus tard, j'ai découvert qu'un fichier avait été ajouté par erreur à la validation.

Comment supprimer un fichier du dernier commit?

Fric
la source
2
Ce lien est parfait pour votre question: stackoverflow.com/questions/307828/…
b3h3m0th
@CharlesB: oui, c'est mon dernier commit
Lolly
8
avez-vous poussé le commit sur le serveur?
Paritosh Singh
4
Je le fais simplement en utilisant:git reset filepath
felipekm

Réponses:

3090

Je pense que d'autres réponses ici sont fausses, car il s'agit de déplacer les fichiers validés par erreur dans la zone de transfert à partir de la validation précédente, sans annuler les modifications qui leur ont été apportées. Cela peut être fait comme l'a suggéré Paritosh Singh:

git reset --soft HEAD^ 

ou

git reset --soft HEAD~1

Réinitialisez ensuite les fichiers indésirables afin de les exclure du commit:

git reset HEAD path/to/unwanted_file

Maintenant, validez à nouveau, vous pouvez même réutiliser le même message de validation:

git commit -c ORIG_HEAD  
juzzlin
la source
86
Merci pour cela. Il vaut la peine d'ajouter que si vous avez déjà poussé votre commit (incorrect) antérieur et que vous essayez maintenant de git pushcorriger votre repo, il se plaindra Updates were rejected because the tip of your current branch is behind its remote counterpart.. Si vous êtes sûr de vouloir les pousser (par exemple, c'est votre fourche), vous pouvez utiliser l' -foption pour forcer la poussée, par exemple git push origin master -f. (Ne faites pas cela à un dépôt en amont que d'autres recherchent)
andy magoon
57
git reset --soft HEAD^est mon opération d'annulation la plus courante
funroll
2
@PabloFernandez, tout d'abord, la réponse acceptée aurait pu être ce que le PO recherchait (également, elle a été publiée des mois plus tôt). Deuxièmement, les réponses acceptées sont toujours en tête quel que soit le nombre de votes positifs.
MITjanitor
4
@PabloFernandez en haut de toutes les réponses sont trois onglets qui vous permettent de contrôler l'ordre des réponses: actif , le plus ancien et les votes . Je suppose que la vôtre est réglée sur la plus ancienne . Passez-le aux votes même si la réponse acceptée sera toujours en haut, cette réponse sera la deuxième.
ahsteele
15
Je savais à ce sujet, git resetmais je voulais un moyen d'affecter le commit existant "en place". Je viens d'apprendre git commit -C. Donc, pour moi, ce que je veux, c'est votre recette exacte avec une étape de plus, le "nouveau commit à nouveau" écrit comme git commit -C [hash of original HEAD commit from first step].
metamatt
323

ATTENTION ! Si vous souhaitez uniquement supprimer un fichier de votre commit précédent et le conserver sur le disque , lisez la réponse de juzzlin juste au-dessus.

S'il s'agit de votre dernier commit et que vous souhaitez supprimer complètement le fichier de votre référentiel local et distant , vous pouvez:

  1. supprimer le fichier git rm <file>
  2. valider avec modifier le drapeau: git commit --amend

Le drapeau de modification indique à git de recommencer, mais "fusionner" (pas dans le sens de fusionner deux branches) cette validation avec la dernière validation.

Comme indiqué dans les commentaires, utiliser git rmici, c'est comme utiliser la rmcommande elle-même!

CharlesB
la source
120
vous pouvez également utiliser git rm --cachedpour conserver les fichiers sur le disque
Arkadiy Kukarkin
14
Avertissement à ceux qui parcourent cette réponse: assurez-vous que vous voulez SUPPRIMER le fichier (comme disparu disparu!), Et pas seulement le supprimer de la liste de validation.
Scott Biggs
8
Pour ajouter à ce que les autres disent (et pour le rendre plus facile de se rappeler de ne pas le faire , sauf si vous voulez vraiment): La rmdans la gitcommande est en train de faire ce que rmlui - même fait!
yo '22
@CharlesB Pouvez-vous s'il vous plaît ajouter la note du commentaire d'Arkadiy Kukarkin à votre réponse pour lui donner plus de visibilité?
mopo922
2
Notez que les fichiers peuvent toujours être restaurés, au cas où vous changeriez d'avis, le commit avant git commit --amendest toujours là et peut être trouvé par exemple avec git reflog. Ce n'est donc pas aussi mauvais que les autres commentaires le suggèrent.
Steohan
165

Les réponses existantes parlent toutes de la suppression des fichiers indésirables du dernier commit.

Si vous souhaitez supprimer des fichiers indésirables d'un ancien commit (même poussé) et ne souhaitez pas créer un nouveau commit, ce qui n'est pas nécessaire, en raison de l'action:

1.

Recherchez le commit auquel vous souhaitez que le fichier soit conforme.

git checkout <commit_id> <path_to_file>

vous pouvez le faire plusieurs fois si vous souhaitez supprimer de nombreux fichiers.

2.

git commit -am "remove unwanted files"

3.

Trouvez le commit_id du commit sur lequel les fichiers ont été ajoutés par erreur , disons "35c23c2" ici

git rebase 35c23c2~1 -i  // notice: "~1" is necessary

Cette commande ouvre l'éditeur en fonction de vos paramètres. La valeur par défaut est vim.

Déplacez le dernier commit, qui devrait être "supprimer les fichiers indésirables", à la ligne suivante du commit incorrect ("35c23c2" dans notre cas), et définissez la commande comme suit fixup:

pick 35c23c2 the first commit
fixup 0d78b28 remove unwanted files

Vous devriez être bon après avoir enregistré le fichier.

Pour finir :

git push -f

Si vous rencontrez malheureusement des conflits, vous devez les résoudre manuellement.

Brian
la source
2
Faire cela avec nano est fabuleux! Ctrl + K, Ctrl + U, mettez un «f», Ctrl + X, mettez «y» et le tour est joué!
sequielo
6
Si vous souhaitez réellement supprimer les fichiers du référentiel (et non le système de fichiers), plutôt que de simplement les rétablir dans une version précédente, alors au lieu de l'étape 1, faites-le git rm --cached <file(s)>.
waldyrious
2
Attendez, vous pouvez simplement déplacer les validations dans le fichier de rebase interactif à volonté?
Dan Rosenstark
2
Vous pouvez totalement, mais vous pouvez (ou non) avoir des conflits.
Brian
6
Ce processus pourrait être rendu un peu plus facile en ajoutant --fixup=35c23c2à la git commitcommande. Cela configurera le commit automatiquement comme une correction du commit requis et vous n'aurez donc pas besoin de le spécifier dans la rebase. De plus, si vous ajoutez --autosquashà la git rebasecommande, git déplacera automatiquement votre commit au bon endroit, donc vous n'avez rien à faire dans la rebase interactive - enregistrez simplement le résultat (ce qui signifie que vous n'avez même pas besoin de -imarquer, bien que j'aime quand même l'utiliser pour m'assurer que tout ressemble à ce que j'attends).
Guss
144

Comme l'indique la réponse acceptée, vous pouvez le faire en réinitialisant l'intégralité du commit. Mais c'est une approche plutôt lourde.
Une façon plus propre de le faire serait de conserver la validation et de simplement en supprimer les fichiers modifiés.

git reset HEAD^ -- path/to/file
git commit --amend --no-edit

Le git resetprendra le fichier tel qu'il était lors de la validation précédente et le mettra en scène dans l'index. Le fichier dans le répertoire de travail est intact.
Le git commitva ensuite valider et écraser l'index dans le commit actuel.

Cela prend essentiellement la version du fichier qui était dans la validation précédente et l'ajoute à la validation actuelle. Cela n'entraîne aucune modification nette et le fichier est donc effectivement supprimé de la validation.

Patrick
la source
5
C'est une bien meilleure réponse pour supprimer un seul fichier, sans réviser l'intégralité du commit.
2017
C'est exactement la même chose que cette réponse: D stackoverflow.com/a/27340569/1623984
ThatsAMorais
@ThatsAMorais en effet :-). Je me demande si cette question a été fusionnée avec une autre, et c'est pourquoi je ne l'ai pas vue. Ou peut-être que je suis juste aveugle. Dans les deux cas, je pense que je suis enclin à le laisser car sur la base des votes, il semble être plus populaire (peut-être que les gens préfèrent la réponse courte et directe).
Patrick
Par tous les moyens, laissez-le! :) Nous avons clairement eu la bonne idée, et le but est d'aider. Je pense que la fusion est une bonne théorie.
ThatsAMorais
Comment faites-vous cela si vous avez déjà poussé vers une branche sur github? J'ai essayé de pousser après avoir fait ce correctif et j'ai reçu le message "Les mises à jour ont été rejetées car la pointe de votre branche actuelle est derrière un indice: son homologue distant."
Ollie Williams
41

Si vous n'avez pas poussé les modifications sur le serveur, vous pouvez utiliser

git reset --soft HEAD~1

Il réinitialisera toutes les modifications et reviendra à un seul commit

Si vous avez poussé vos modifications, suivez les étapes comme indiqué par @CharlesB

Paritosh Singh
la source
2
-1 git reset supprime le fichier des changements survenus dans la zone de transfert, ici le changement a été
validé
OK, mais je vais garder mon downvote car ce n'est pas ce que l'OP veut :) désolé
CharlesB
ok c'est bien pour moi, mais pourquoi l'adversaire ne veut pas ça. Quel est le problème?
Paritosh Singh
pas un gros problème, mais parce que l'OP veut supprimer le fichier indésirable de la dernière validation, et il réinitialise simplement l'état avant de valider. encore faut-il refaire le commit.
CharlesB
3
@Aris utilise <git diff --cached> pour voir les changements
Paritosh Singh
37

La suppression du fichier à l'aide de rm le supprimera!

Vous ajoutez toujours à un commit dans git plutôt que de le supprimer, donc dans ce cas, remettez le fichier dans l'état où il était avant le premier commit (cela peut être une action de suppression de 'rm' si le fichier est nouveau), puis recommencez et le fichier disparaîtra.

Pour ramener le fichier à un état antérieur:

    git checkout <commit_id> <path_to_file>

ou pour le remettre à l'état sur la TETE distante:

    git checkout origin/master <path_to_file>

puis modifiez le commit et vous devriez trouver que le fichier a disparu de la liste (et qu'il n'a pas été supprimé de votre disque!)

Bob Flannigon
la source
36
git checkout HEAD~ path/to/file
git commit --amend
Denis Shchepetov
la source
1
C'est le meilleur moyen de modifier le dernier commit, celui qui n'a pas été poussé. Cela réinitialisera les modifications dans un fichier, supprimant efficacement ce fichier du dernier commit.
Alex Bravo
Cela a également changé le fichier. Comment conserver les modifications locales dans le fichier?
theonlygusti
29

Ce qui suit mettra en scène uniquement le fichier que vous vouliez, ce que l'OP a demandé.

git reset HEAD^ /path/to/file

Vous verrez quelque chose comme ce qui suit ...

Modifications à valider: (utilisez "git reset HEAD ..." pour annuler la mise en scène)

modifié: / chemin / vers / fichier

Modifications non planifiées pour la validation: (utilisez "git add ..." pour mettre à jour ce qui sera validé) (utilisez "git checkout - ..." pour ignorer les modifications dans le répertoire de travail)

modifié: / chemin / vers / fichier

  • "Modifications à valider" est la version précédente du fichier avant la validation. Cela ressemblera à une suppression si le fichier n'a jamais existé. Si vous validez cette modification, il y aura une révision qui annulera la modification du fichier dans votre branche.
  • "Modifications non planifiées pour la validation" est la modification que vous avez validée et l'état actuel du fichier

À ce stade, vous pouvez faire tout ce que vous voulez dans le fichier, comme réinitialiser une version différente.

Lorsque vous êtes prêt à vous engager:

git commit --amend -a

ou (si vous avez d'autres changements en cours que vous ne voulez pas encore valider)

git commit add /path/to/file
git commit --amend
ThatsAMorais
la source
3
La réponse de juzzlin est excellente, mais il est excessif de supprimer toute la validation lorsque vous ne souhaitez en supprimer qu'une. Annuler la mise en scène de la validation entière peut provoquer des problèmes si vous avez actuellement des modifications non mises en scène sur les fichiers de cette validation que vous ne voulez pas perdre.
ThatsAMorais
27

Je vais vous expliquer avec exemple.
Soit A, B, C 3 commits successifs. La validation B contient un fichier qui n'aurait pas dû être validé.

git log  # take A commit_id
git rebase -i "A_commit_ID" # do an interactive rebase
change commit to 'e' in rebase vim # means commit will be edited
git rm unwanted_file
git rebase --continue
git push --force-with-lease <branchName>    
Moaz Rashad
la source
Si le fichier particulier ne se trouve pas dans le dernier ou le précédent commit, c'est la manière la plus élégante. Je dirais même que c'est la manière la plus élégante en général. J'aime le rebasage interactif.
bvgheluwe
Pour un seul commit, changez noopen edit [A_commit_ID]oue [A_commit_ID]
TamusJRoyce
23

Vous pouvez simplement essayer.

git reset --soft HEAD~1

et créez un nouveau commit.

Cependant, il existe un logiciel génial "gitkraken". ce qui facilite le travail avec git.

HamzaMushtaq
la source
1
Et juste pour noter: après cela, vous devriez git commit --amendavoir la suppression du fichier mise à jour dans votre dernier commit; et après, vous pouvez vérifier qu'il a bien été supprimé avecgit log -1 --stat
sdbbs
13
git rm --cached <file_to_remove_from_commit_<commit_id>_which_added_file>
git commit -m "removed unwanted file from git"

vous laissera toujours le fichier local. Si vous ne voulez pas non plus le fichier localement, vous pouvez ignorer l'option --cached.

Si tout le travail est sur votre branche locale, vous devez conserver le fichier dans un commit ultérieur, et comme avoir un historique propre, je pense qu'une façon plus simple de le faire pourrait être:

git rm --cached <file_to_remove_from_commit_<commit_id>_which_added_file>
git commit --squash <commit_id>
git add <file_to_remove_from_commit_<commit_id>_which_added_file>
git commit -m "brand new file!"
git rebase --interactive <commit_id>^

et vous pouvez ensuite terminer facilement le rebasage sans avoir à vous souvenir de commandes plus complexes ou à valider un message ou à taper autant.

Bryan Buckley
la source
Cela fonctionne pour moi. Je suppose que si vous souhaitez ajouter les fichiers dans le mix, utilisez simplement git add -A ou git add. et ils sont de retour.
Alexander Mills
11

L'utilisation de git GUI peut simplifier la suppression d'un fichier de la validation précédente.

En supposant que ce n'est pas une branche partagée et que cela ne vous dérange pas de réécrire l'historique , exécutez:

git gui citool --amend

Vous pouvez décocher le fichier qui a été validé par erreur, puis cliquer sur "Valider".

entrez la description de l'image ici

Le fichier est supprimé de la validation, mais sera conservé sur le disque . Donc, si vous avez décoché le fichier après l'avoir ajouté par erreur, il s'affichera dans votre liste de fichiers non suivis (et si vous avez décoché le fichier après l'avoir modifié par erreur, il s'affichera dans vos modifications non mises en scène pour la liste de validation).

JDiMatteo
la source
2
Sur Ubuntu, vous pouvez installer git gui avecsudo apt-get install git-gui
JDiMatteo
Je vous remercie! J'étais coincé avec un problème (bug?) Où un dossier contenant un dépôt .git a été ajouté, et toutes les commandes de suppression habituelles ne fonctionnaient pas. Cela a cependant aidé. Comme il s'agit de quelques validations, j'ai d'abord utilisé git rebase -i HEAD~4puis exécuté votre commande pour ouvrir l'éditeur. Autre remarque: "Unstaging" se trouve dans le menu "Commit".
Johny Skovdal
La solution la plus simple de toutes. Le plus simple à retenir. Et beaucoup moins sujet aux erreurs que d'utiliser git reset --soft HEAD^(en se souvenant de l'argument --soft), suivi de git commit -c ORIG_HEAD(plutôt que --amend, qui fout tout).
Brent Faust
9

Si vous souhaitez conserver votre commit (peut-être avez-vous déjà passé un certain temps à écrire un message de commit détaillé et que vous ne voulez pas le perdre) et que vous souhaitez uniquement supprimer le fichier du commit, mais pas du référentiel:

git checkout origin/<remote-branch> <filename>
git commit --amend
mattexx
la source
6

Effectuez une séquence des commandes suivantes:

//to remove the last commit, but preserve changes  
git reset --soft HEAD~1

//to remove unneded file from the staging area  
git reset HEAD `<your file>` 

//finally make a new commit  
git commit -m 'Your message'
Sergey Onishchenko
la source
J'ai essayé de faire ces étapes, et je vois cette erreur d'erreur: impossible de pousser certaines références vers 'git ....' Pour vous empêcher de perdre l'historique, les mises à jour non rapides ont été rejetées. 'git pull') avant de pousser à nouveau. Voir la section 'Remarque sur les avances rapides' de 'git push --help' pour plus de détails. (après git pull j'ai les mêmes changements)
Dezigo
Cela signifie que l'état de votre dépôt à distance a changé pendant que vous faisiez votre travail local. Et après 'git pull', vos modifications locales devraient être fusionnées avec des modifications distantes, c'est tout. Bien sûr, vos changements doivent rester.
Sergey Onishchenko
En d'autres termes, si vous obtenez cette erreur @Dezigo, ajoutez l'indicateur -f pour forcer la mise à jour.
jungledev
5

Je voulais juste compléter la première réponse car je devais exécuter une commande supplémentaire:

git reset --soft HEAD^
git checkout origin/master <filepath>

À votre santé!

andrepo
la source
Bienvenue. Cette réponse serait meilleure si vous expliquiez ce que font réellement les commandes.
Mark Chorley
3

Quelque chose qui a fonctionné pour moi, mais pense toujours qu'il devrait y avoir une meilleure solution:

$ git revert <commit_id>
$ git reset HEAD~1 --hard

Laissez simplement le changement que vous souhaitez supprimer dans l'autre commit, vérifiez les autres

$ git commit --amend // or stash and rebase to <commit_id> to amend changes
saiyancoder
la source
3

git reset --soft HEAD^annule votre commit, et lorsque vous tapez git status, il vous indique quoi faire:

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
cardamome
la source
2

En fait, je pense qu'un moyen plus rapide et plus simple consiste à utiliser le mode interactif git rebase.

git rebase -i head~1  

(ou dirigez-vous ~ 4, jusqu'où vous voulez aller)

puis, au lieu de «choisir», utilisez «modifier». Je ne savais pas à quel point le «montage» est puissant.

https://www.youtube.com/watch?v=2dQosJaLN18

J'espère que vous le trouverez utile.

Mat
la source
la vidéo
dure
2

Eu le même problème où j'ai des changements dans une branche locale où je voulais revenir à un seul fichier. Ce qui a fonctionné pour moi était -

( feature / target_branch ci-dessous est l'endroit où j'ai toutes mes modifications, y compris celles que je voulais annuler pour un fichier spécifique)

( origin / feature / target_branch est la branche distante où je veux pousser mes modifications)

( fonctionnalité / staging est ma branche de staging temporaire où je vais pousser de toutes mes modifications souhaitées à l'exception de la modification de ce fichier)

  1. Créer une branche locale à partir de mon origine / fonction / branche_branche - appelée fonction / mise en scène

  2. Fusionné ma branche locale travaillant fonction / target_branch à la fonction / mise en scène branche

  3. Extrait de la fonctionnalité / mise en scène puis réinitialisation de git --soft ORIG_HEAD (Maintenant, toutes les modifications de la fonction / mise en scène seront mises en place mais non validées.)

  4. Unstaged le fichier que j'ai précédemment archivé avec des modifications inutiles

  5. Changement de la branche amont pour fonction / mise en scène d' origine / fonction / target_branch

  6. Validé le reste des modifications par étapes et poussé en amont vers mon origine / fonctionnalité / branche_branchée distante

user1201303
la source
1

Si vous n'avez plus besoin de ce fichier, vous pouvez le faire

git rm file
git commit --amend
git push origin branch
tven
la source
1

Si vous utilisez GitHub et n'avez pas encore poussé la validation, GitHub Desktop résout facilement ce problème:

  1. Choisissez Référentiel -> Annuler la validation la plus récente
  2. Désélectionnez le fichier que vous avez ajouté par erreur. Votre message de validation précédent sera déjà dans la boîte de dialogue.
  3. Appuyez sur le bouton Valider!
Ron
la source
1

Si vous souhaitez supprimer des fichiers des validations précédentes, utilisez des filtres

git filter-branch --prune-empty --index-filter 'git rm --ignore-unmatch --cached "file_to_be_removed.dmg"'

Si vous voyez cette erreur:

Impossible de créer une nouvelle sauvegarde. Une sauvegarde précédente existe déjà dans refs / original / Force écrasant la sauvegarde avec -f

Supprimez simplement les sauvegardes de références sur votre référentiel local

$ rm -rf .git/refs/original/refs
wilo087
la source
1

si vous n'avez pas encore poussé vos modifications vers git

git reset --soft HEAD~1

Il réinitialisera toutes les modifications et reviendra à un seul commit

S'il s'agit du dernier commit que vous avez effectué et que vous souhaitez supprimer le fichier du référentiel local et distant, essayez ceci:

git rm <file>
 git commit --amend

ou encore mieux:

réinitialiser d'abord

git reset --soft HEAD~1

réinitialiser le fichier indésirable

git reset HEAD path/to/unwanted_file

engager à nouveau

git commit -c ORIG_HEAD  
TanvirChowdhury
la source
c'est la même chose que ci-dessus, mais a même vraiment aidé à recouper
Reshma
0

Cela a fonctionné pour moi pour supprimer le fichier du dépôt de bit bit que j'ai poussé le fichier pour créer une branche initialement.

git checkout origin/develop <path-to-file>
git add <path-to-file>
git commit -m "Message"
git push
swathi
la source
0

J'ai copié les fichiers actuels dans un dossier différent, puis je me suis débarrassé de toutes les modifications non poussées en:

git reset --hard @{u}

Recopiez ensuite les choses. Validez, poussez.

Miranda
la source
0

Vous pouvez simplement utiliser cette commande:

git restore --staged <file>
suulisine
la source
0
Here is the step to remove files from Git Commit.

>git reset --soft HEAD^1(either commitid ) -- now files moved to the staging area.
>git rm --cached filename(it will removed the file from staging area)
>git commit -m 'meaningfull message'(Now commit the required files)
Sheo Dayal Singh
la source
-1

À l'heure actuelle, aucune des réponses n'est raisonnable. Il semble que la demande soit suffisante pour qu'une véritable solution soit proposée: https://github.com/git/git/blob/master/Documentation/SubmittingPatches

git --uncommit <nom de fichier>

serait bien. J'obtiens que nous ne voulons pas modifier l'historique, mais si je suis local et que j'ai accidentellement ajouté un fichier "hack" local et que je veux le supprimer du commit, ce serait super utile.

Bob9630
la source