36 votes

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

Je vais transférer un dépôt Git privé d'une boîte win32 à Ubuntu. Bien que je puisse faire un dos2unix final commit, mais j'aimerais réécrire tout l'historique, afin qu'une certaine interface graphique Git affiche correctement les logs/diffs. Par exemple, gitg insérera des lignes vides pour chaque CR/LF.

30voto

givp Points 798

Vous pouvez utiliser git filter-branch pour cela, avec le --tree-filter et en spécifiant --all pour 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

I fortement recommande de faire une sauvegarde complète au préalable . Exécuter cela à partir de votre machine Linux (à moins que vous n'ayez une bonne Shell configurée dans votre environnement Windows) est probablement plus facile.

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

6voto

mgorovoy Points 61

Mat's réponse a mis le doigt sur le problème. 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 ignorent à des degrés divers l'existence des fichiers binaires, donc si votre dépôt 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 des fichiers binaires qui utilise la commande 'file' de Linux pour identifier correctement et traiter uniquement les fichiers texte comme indiqué ci-dessous. La commande ci-dessous utilise l'option --tag-name-filter pour préserver les balises existantes en les déplaçant vers le commits nouvellement modifié. Elle utilise également le drapeau --force pour s'assurer que la commande fonctionnera dans le cas où vous avez déjà exécuté tree-filter sur votre référentiel.

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

3voto

METAJIJI Points 131

Et sans aucun outil supplémentaire (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

Multiplateforme (OS X, FreeBSD, Linux) analogue utile 'fromdos', 'dos2unix' :

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

Peut-être utile "unix2dos" :

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 courant "." :

find . -type f -exec sed -i'' -e 's/'"$(printf '\015')"'$//' {} \;

0voto

CervEd Points 127

git filter-branch présente plusieurs problèmes, principalement en termes de performances, car il est déprécié au profit de l'option git filter-repo un projet séparé qui consiste en plusieurs scripts Python.

Pour convertir toutes les fins de lignes d'un référentiel, utilisez lint-history

lint-history dos2unix # CRLF => LF
lint-history unix2dos # LF => CRLF

Vous pouvez également effectuer d'autres tâches de linting, comme ajouter une nouvelle ligne à la fin du fichier.

lint-history sed -i '$a\'

Cela suppose que le lint-history script est dans votre chemin et que git filter-repo est installé correctement avec les liens symboliques et autres.

Si vous ne disposez pas d'un filter-repo installation avec lint-history mais seulement git-filter-repo vous pouvez courir :

git filter-repo --blob-callback '
  if not b"\0" in blob.data[0:8192]:
    filename = ".git/info/tmpfile"
    with open(filename, "wb") as f:
      f.write(blob.data)
    subprocess.check_call(["sed", "-i", "$a\\", filename])
    with open(filename, "rb") as f:
      blob.data = f.read()
    os.remove(filename)
  '

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