Réécrire l'historique git pour remplacer tous les CRLF en LF?

32

Je vais transférer un référentiel Git privé de la boîte win32 vers Ubuntu. Bien que je puisse faire un commit dos2unix final, mais je voudrais réécrire tout l'historique, donc certaines interfaces graphiques Git afficheront correctement log / diff. Par exemple, gitg insérera des lignes vides pour chaque CR / LF.

Xiè Jìléi
la source

Réponses:

25

Vous pouvez utiliser git filter-branchpour cela, avec l' --tree-filteroption, et en spécifiant --allpour la branche.

Voici un exemple (démarré dans un répertoire vide avec un fichier texte de type Unix:

Préparation:

$ hexdump -C testfile 
00000000  61 0d 0a 62 0d 0a 63 0d  0a                       |a..b..c..|
00000009

$ git init
Initialized empty Git repository in /home/seigneur/tmp/a/.git/

$ git add testfile && git commit -m "dos file checked in"
[master (root-commit) df4970f] dos file checked in
 1 files changed, 3 insertions(+), 0 deletions(-)
 create mode 100644 testfile

La commande:

$ git filter-branch --tree-filter 'git ls-files -z | xargs -0 dos2unix' -- --all

Sortie:

Rewrite df4970f63e3196216d5986463f239e51eebb4014 (1/1)dos2unix: converting file testfile to Unix format ...

Ref 'refs/heads/master' was rewritten

$ hexdump -C testfile 
00000000  61 0a 62 0a 63 0a                                 |a.b.c.|
00000006

Je recommande fortement de faire une sauvegarde complète au préalable . L'exécuter à partir de votre machine Linux (à moins que vous n'ayez un bon shell configuré dans votre environnement Windows) est probablement plus facile.

Edit: avait la conversion inversée la première fois.

Tapis
la source
1
Merci, ce message m'a beaucoup aidé. J'ai eu quelques fichiers avec des espaces en leur nom, un peu de changement à la commande originale réparée: git filter-branch --tree-filter 'git ls-files -z | xargs -0 dos2unix' -- --all. Drapeaux -zet -0dire git ls-fileset xargsimprimer et interpréter nullcomme fin de ligne.
Ivan
Une autre alternative à la commande dos2unix est de s'appuyer sur le git lui-même:git filter-branch --prune-empty --tree-filter 'git add --renormalize .' -- --all
Vilmantas Baranauskas
6

La réponse de Mat a cloué le problème directement sur la tête. Malheureusement sur Ubuntu Linux, à partir de la version 10.04 (Lucid Lynx), les commandes dos2unix / unix2dos ne sont plus disponibles et ont été remplacées par fromdos / todos. De plus, les deux ensembles de commandes de conversion ont différents degrés d'ignorance de l'existence de fichiers binaires, donc si votre référentiel contient des images, des polices, etc., ils seront corrompus par ce processus.

J'ai pu trouver une solution de contournement pour le problème de corruption de fichiers binaires qui utilise la commande Linux 'file' pour identifier et traiter correctement uniquement les fichiers texte comme indiqué ci-dessous. La commande ci-dessous utilise l'option --tag-name-filter pour conserver les balises existantes en les déplaçant vers les commits nouvellement modifiés. Il utilise également l'option --force pour garantir que la commande fonctionnera au cas où vous auriez exécuté un filtre d'arborescence sur votre référentiel auparavant.

git filter-branch --force --tree-filter 'git ls-files | xargs file | sed -n -e "/.*: .*text.*/s/\(.*\): .*/\1/p" | xargs fromdos' --tag-name-filter cat -- --all
mgorovoy
la source
3

Et sans outils supplémentaires (comme «fromdos», «dos2unix», etc.):

git filter-branch --force --tree-filter 'git ls-files | xargs file | sed -n -e "/.*: .*text.*/s/\(.*\): .*/\1/p" | xargs -0 sed -i"" -e "s/"$(printf "\015")"$//"' --tag-name-filter cat -- --all

Crossplatform (OS X, FreeBSD, Linux) analogique utile 'fromdos', 'dos2unix':

sed -i'' -e 's/'"$(printf '\015')"'$//'

Peut-être unix2dos utile:

sed -i '' -e 's|$|'"`printf '\015'`"'|' file.name

Si vous êtes absolument sûr de ce que vous faites, vous pouvez utiliser cette simple commande en ligne pour supprimer "/ r" de tous les fichiers du répertoire en cours ".":

find . -type f -exec sed -i'' -e 's/'"$(printf '\015')"'$//' {} \;
METAJIJI
la source
1
Remplacez plutôt \ r \ n par \ n au lieu de supprimer uniquement \ r
xdevs23
Je pense que l' sedinvocation correspondante peut être remplacée par une plus courte:sed -n -e "s/\(.*\): .*text.*/\1/p"
dma_k