web-dev-qa-db-fra.com

Comment supprimer le sous-arbre git ajouté précédemment et son historique

Il y a plusieurs lunes, j'ai ajouté une sous-arborescence à mon référentiel git. Cette sous-arborescence comprenait plusieurs dossiers et fichiers. J'ai ajouté le sous-arbre au lieu de créer un sous-module (comme recommandé). Maintenant, je me rends compte que je ne veux qu'un des fichiers de la sous-arborescence et aucun des autres. Pire encore, lorsque d'autres clone mon référentiel, ce qu'ils obtiennent n'est pas ce qui est attendu — il y a un conflit avec le sous-arbre et l'autre code que j'ai créé.

Je peux me débarrasser des fichiers/dossiers avec

git rm subtree–folder1 subtree_folder2 subtree_files.*

cependant, je reste avec un long historique de validation du sous-arbre.

J'ai fait pas mal de développement depuis que j'ai initialement ajouté le sous-arbre et je ne peux pas perdre l'historique de validation que j'ai généré.

Bref voici ce que j'aimerais:

  1. Supprimez tous les fichiers/dossiers de sous-arborescence.
  2. Oubliez l'historique de tous les commits de sous-arborescence.
  3. Resté avec seulement mon code et mon historique.

Est-ce possible?

PS. Une complication possible est que j'ai déplacé le fichier d'en-tête unique que je voulais conserver du sous-arbre vers un dossier de mon code. J'espère que ce n'est pas ce qui m'empêche d'oublier l'histoire du sous-arbre.

Un essai

Après une nouvelle vérification du serveur distant, j'ai ce qui suit:

$ ls
.git             CMakeLists.txt   Read.cpp         logging.conf
.gitignore       ENDF6            TestData         src
.sparse-checkout LICENCE          doc              test
.travis.yml      README.md        include          tools

.gitignore n'a que: build/debug /

Lorsque j'essaie la commande comme suggéré, je n'obtiens pas de réponse très heureuse:

$ git filter-branch --index-filter 'git rm --cached -rf test tools src doc LICENCE README.md .travis.yml' HEAD
Rewrite 2fec85e41e40ae18efd1b130f55b14166a422c7f (1/1701)fatal: pathspec 'test' did not match any files
index filter failed: git rm --cached -rf test tools src doc LICENCE README.md .travis.yml

Je ne sais pas pourquoi il dit qu'il a un problème avec test quand il est clairement là. Je suis déconcerté.

16
jlconlin

Vous devez utiliser une branche de filtre avec l'option --Prune-empty pour supprimer toutes les validations qui n'introduisent plus de nouvelles modifications.

git filter-branch --index-filter 'git rm --cached --ignore-unmatch -rf dir1 dir2 dirN file1 file2 fileN' --Prune-empty -f HEAD

Après cela, si vous souhaitez récupérer de l'espace disque, vous devrez supprimer toutes les références d'origine que la branche de filtrage a enregistrées, expirer le reflog et le garbage collection.

20
Andrew C

Vous pouvez utiliser git filter-branch pour appliquer une opération à tous les commits que vous avez effectués dans une branche. Cela comprend la suppression des fichiers de chaque validation lorsque vous réécrivez l'historique complet. Une bonne description et des instructions sont disponibles ici: http://gitready.com/beginner/2009/03/06/ignoring-doesnt-remove-a-file.html . Vous pouvez également trouver la question suivante utile: Supprimer complètement les fichiers du dépôt Git et à distance sur GitHub (c'est là que j'ai trouvé le lien). La commande réelle que vous exécuterez avec cette solution sera quelque chose comme git filter-branch --index-filter 'git rm --cached -rf subtree–folder1 subtree_folder2' HEAD.

Une autre façon, qui est probablement exagérée pour ce que vous faites, est la cueillette des cerises. La sélection des cerises vous permet de réécrire n'importe quelle partie de votre historique que vous aimez avec n'importe quel niveau de détail que vous aimez: http://git-scm.com/docs/git-cherry-pick. Vous voudrez faire quelque chose comme git reset --hard <HASH of commit that introduced the subtree>, suivi d'une série de

git cherry-pick -n <following commit hashes>
git reset
git add -p
git commit

pour chaque validation ultérieure que vous aviez effectuée. Cela vous permettra de supprimer le sous-arbre de chaque commit que vous avez fait dans le passé. Vous pouvez vous référer à en partie choisir un commit avec git pour plus d'informations sur un choix efficace. Lorsque vous avez terminé avec cette version de la suppression, vous souhaiterez supprimer les anciens commits qui ne font plus partie de votre branche:

git reflog expire --expire-unreachable=now --all
git gc --Prune=now

Autres questions référencées: Comment déplacer une branche en arrière dans git?Liste et suppression des validations Git qui ne sont sous aucune branche (balançant?)

2
Mad Physicist