6 votes

Comment ajouter un commit parent avant tous les autres commits dans Git ?

Je suis dans une situation où j'essaie de convertir un projet open source en Git, et j'ai récemment obtenu l'accès aux données historiques du projet. J'ai déjà apporté des modifications au dépôt, donc je souhaite ajouter ces premiers changements en tant que commits git au début de l'arborescence des commits dans Git. (Oui, je suis conscient que cela changera les SHAs pour les commits ultérieurs ; cela est acceptable.) Les données sont fournies sous forme de snapshots successifs du répertoire de travail. Je veux configurer les choses de manière à ce que l'état du répertoire de travail pour les commits ultérieurs ne soit pas affecté (je ne veux pas fusionner les changements).

Par exemple, si le commit initial B ajoute les fichiers a et b au répertoire de travail, et que mon commit historique A ajoute le fichier a, je souhaite créer un nouveau commit B' parenté de A qui n'ajoute que le fichier b. Dans B et B', le répertoire de travail est identique, et tous les commits ultérieurs sur B peuvent être facilement rebasés sur B'.

Est-il possible de faire cela en Git ? Si oui, comment ?

Édit : Notez que je dois modifier le commit initial. L'utilisation standard de git commit ajoute un nouveau commit en tant qu'enfant du commit HEAD, et donc ne fonctionne pas pour le commit initial, qui n'a pas de parent.

10voto

punchagan Points 216

Quelque chose comme ça devrait fonctionner.

# Créez une nouvelle branche avec l'ancien historique
$ git checkout --orphan old-history    
$ git add 
$ git commit

# Rebaser master sur la branche avec l'ancien historique
$ git checkout master
$ git pull --rebase . old-history

3voto

Deven T. Corzine Points 141

Il y a des instructions dans la page de manuel de git-filter-branch(1) à ce sujet :

   Pour définir un commit (qui est généralement à la pointe d'une autre historique) comme parent du commit initial actuel, afin de coller l'autre historique derrière l'historique actuel :

       git filter-branch --parent-filter 'sed "s/^\$/-p /"' HEAD

   (si la chaîne parent est vide - ce qui se produit lorsque nous traitons le commit initial - ajoutez graftcommit comme parent). Notez que cela suppose une historique avec une seule racine (c'est-à-dire, aucun merge sans ancêtres communs ne s'est produit).

En suivant une suggestion de Kent, vous voudrez peut-être ajouter --tag-name-filter cat à cette commande pour réécrire les noms des étiquettes vers les nouveaux commits. Cela est également documenté dans la page de manuel, avec un avertissement de sauvegarder d'abord les anciennes étiquettes :

       Les étiquettes originales ne sont pas supprimées, mais peuvent être écrasées ; utilisez "--tag-name-filter cat" pour simplement mettre à jour les étiquettes. Dans ce cas, soyez très prudent et assurez-vous d'avoir sauvegardé les anciennes étiquettes au cas où la conversion échoue.

La page de manuel explique également pourquoi les signatures doivent être supprimées lors de la réécriture des étiquettes :

       La réécriture quasi correcte des objets étiquettes est prise en charge. Si l'étiquette a un message attaché, un nouvel objet étiquette sera créé avec le même message, auteur et horodatage. Si l'étiquette a une signature attachée, la signature sera supprimée. Il est par définition impossible de préserver les signatures. La raison pour laquelle cela est "quasi" correct, c'est parce qu'idéalement si l'étiquette n'a pas changé (pointe vers le même objet, a le même nom, etc.), elle devrait conserver toute signature. Ce n'est pas le cas, les signatures seront toujours supprimées, l'acheteur est prévenu. Il n'y a également aucun support pour changer l'auteur ou l'horodatage (ou le message de l'étiquette pour cette question). Les étiquettes qui pointent vers d'autres étiquettes seront réécrites pour pointer vers le commit sous-jacent.

Après l'exemple de la racine unique, la page de manuel continue avec des instructions pour les multiples racines :

   Si ce n'est pas le cas, utilisez :

       git filter-branch --parent-filter \
               'test $GIT_COMMIT =  && echo "-p " || cat' HEAD

   ou même plus simplement :

       git replace --graft $commit-id $graft-id
       git filter-branch $graft-id..HEAD

Utiliser git filter-branch est bien plus propre que d'utiliser git --rebase, qui fonctionne comme une combinaison de diff et patch, appliquant les changements de chaque commit sur un autre. Au lieu de cela, git filter-branch laisse les fichiers actuels de chaque commit intacts et modifie directement le pointeur du commit parent.

Évidemment, les nouveaux commits auront des SHAs différents des originaux - c'est inévitable puisque le commit parent est inclus dans le calcul du SHA.


Vous pouvez également essayer le script de Mark Lodato git-reparent, qui semble utiliser des commandes de plomberie git pour obtenir un résultat similaire.

0voto

Ari Malinen Points 97

Je ne suis pas sûr que l'on puisse simplement faire :

git add [fichiers]
git commit -m 'premier commit'

Ensuite fusionner les modifications

git add [fichiers]
git commit -m 'deuxième commit'

Ensuite

git push

Si cela ne fonctionne pas, je pense qu'il n'y a aucun moyen d'accomplir cela.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X