Zeilenenden Durcheinander in Git - so verfolgen Sie änderungen von einem Zweig nach einem großen Zeilenende fix?
Frage
Wir arbeiten mit 3rd-party-PHP-engine, bekommt regelmäßige updates.Die releases sind immer in einem separaten Zweig in git, und unsere Gabel ist der master-branch.
Auf diese Weise werden wir in der Lage, um das anwenden von patches zu unserem Gabel von den neuen Versionen des Motors.
Mein problem ist, nachdem viele commits zu unsere Zweig, ich merkte, dass die anfänglichen import der Motor wurde mit CRLF-Zeilenenden.
Ich konvertierte jede Datei auf LF, aber machte das einen großen zu Begehen, mit 100k Zeilen entfernt und 100k Zeilen Hinzugefügt, die offensichtlich bricht, was wir tun sollen:leicht merge-in-patches aus der Fabrik-releases, dass 3rd-party-engine.
Was sollte ich wissen?Wie kann ich dieses Problem beheben?Ich habe bereits Hunderte von commits auf unserer Gabel.
Was gut wäre, irgendwie zu tun Zeilenenden fix Begehen, nachdem die erste import-und vor Verzweigung unsere eigenen Gabel, und das entfernen dieser riesigen Linie endend Begehen, später in der Geschichte.
Ich habe jedoch keine Ahnung, wie dies in Git.
Vielen Dank!
Lösung
ich es endlich geschafft, es zu lösen.
Die Antwort lautet:
git filter-branch --tree-filter '~/Scripts/fix-line-endings.sh' -- --all
fix-line-endings.sh enthält:
#!/bin/sh
find . -type f -a \( -name '*.tpl' -o -name '*.php' -o -name '*.js' -o -name '*.css' -o -name '*.sh' -o -name '*.txt' -iname '*.html' \) | xargs fromdos
Nachdem alle Zeilenende in allen Bäumen in allen Commits fixiert waren, habe ich ein interaktives Fütterungsmaterial und entfernt alle Commits, die Zeilenende wurden fixiert wird.
Nun meine Repo ist sauber und frisch, bereit gedrückt werden:)
Hinweis für Besucher: dies nicht tun, wenn Ihr Repo gedrückt wird / geklonte, weil es durcheinander zu bringen schlecht
Andere Tipps
Auch in Zukunft vermeiden dieses Problem mit der core.autocrlf
Einstellung, dokumentiert in git config --help
:
core.autocrlf
Wenn das stimmt, macht git convert
CRLF
am Ende der Zeilen in Textdateien zuLF
wenn aus dem Dateisystem zu lesen, und umgekehrt umwandeln, wenn auf das Dateisystem zu schreiben. Die Variable kann so eingestellt werden, uminput
in diesem Fall die Umwandlung geschieht nur während aus dem Dateisystem zu lesen, aber Dateien werden mitLF
am Ende der Zeilen geschrieben werden. Eine Datei wird „text“ betrachtet ( d. zumautocrlf
Mechanismus unterworfen werden) auf der Grundlage dercrlf
Attribut der Datei, oder wenncrlf
ist nicht spezifiziert, basierend auf den Inhalt der Datei. Siehe gitattributes .
Haben schauen Sie auf git rebase
?
Sie müssen erneut Basis, um die Geschichte Ihres Repositorys wie folgt:
- verpflichten sich die Leitungsabschluss fixes
- Starten Sie das Fütterungsmaterial
- verlassen die Dritt Import begehen erste
- gilt der Leitungsabschluss fixe
- übernehmen Sie die anderen Patches
Was Sie tun müssen, obwohl zu verstehen ist, dass dies brechen alle Downstream-Repositories - diejenigen, die von einem Elternteil Repo geklont werden. Im Idealfall werden Sie von Grund auf neu mit denen beginnen.
Update : Probe Nutzung:
target=`git rev-list --max-count=3 HEAD | tail -n1`
get rebase -i $target
Wird eine Fütterungsmaterial Sitzung für die letzten 3 Commits starten.
wir sind zu vermeiden dieses problem in der Zukunft mit:
1) jeder nutzt einen editor, der Streifen nachgestellte Leerzeichen, und speichern wir alle Dateien mit der LF.
2) wenn 1) nicht (kann es jemand versehentlich speichert es in CRLF-aus welchem Grund auch immer) wir haben ein pre-commit-Skript, das überprüft, für die CRLF-Zeichen:
#!/bin/sh
#
# An example hook script to verify what is about to be committed.
# Called by git-commit with no arguments. The hook should
# exit with non-zero status after issuing an appropriate message if
# it wants to stop the commit.
#
# To enable this hook, rename this file to "pre-commit" and set executable bit
# original by Junio C Hamano
# modified by Barnabas Debreceni to disallow CR characters in commits
if git rev-parse --verify HEAD 2>/dev/null
then
against=HEAD
else
# Initial commit: diff against an empty tree object
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
crlf=0
IFS="
"
for FILE in `git diff-index --cached $against`
do
fhash=`echo $FILE | cut -d' ' -f4`
fname=`echo $FILE | cut -f2`
if git show $fhash | grep -EUIlq $'\r$'
then
echo $fname contains CRLF characters
crlf=1
fi
done
if [ $crlf -eq 1 ]
then
echo Some files have CRLF line endings. Please fix it to be LF and try committing again.
exit 1
fi
exec git diff-index --check --cached $against --
Dieses Skript verwendet GNU grep, und funktioniert auf Mac OS X, aber es sollte überprüft werden, bevor die Verwendung auf anderen Plattformen (wir hatten Probleme mit Cygwin und BSD grep)
3) In Fall finden wir alle whitespace-Fehler, benutzen wir das folgende Skript auf fehlerhafte Dateien:
#!/usr/bin/env php
<?php
// Remove various whitespace errors and convert to LF from CRLF line endings
// written by Barnabas Debreceni
// licensed under the terms of WFTPL (http://en.wikipedia.org/wiki/WTFPL)
// handle no args
if( $argc <2 ) die( "nothing to do" );
// blacklist
$bl = array( 'smarty' . DIRECTORY_SEPARATOR . 'templates_c' . DIRECTORY_SEPARATOR . '.*' );
// whitelist
$wl = array( '\.tpl', '\.php', '\.inc', '\.js', '\.css', '\.sh', '\.html', '\.txt', '\.htc', '\.afm',
'\.cfm', '\.cfc', '\.asp', '\.aspx', '\.ascx' ,'\.lasso', '\.py', '\.afp', '\.xml',
'\.htm', '\.sql', '\.as', '\.mxml', '\.ini', '\.yaml', '\.yml' );
// remove $argv[0]
array_shift( $argv );
// make file list
$files = getFileList( $argv );
// sort files
sort( $files );
// filter them for blacklist and whitelist entries
$filtered = preg_grep( '#(' . implode( '|', $wl ) . ')$#', $files );
$filtered = preg_grep( '#(' . implode( '|', $bl ) . ')$#', $filtered, PREG_GREP_INVERT );
// fix whitespace errors
fix_whitespace_errors( $filtered );
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
// whitespace error fixer
function fix_whitespace_errors( $files ) {
foreach( $files as $file ) {
// read in file
$rawlines = file_get_contents( $file );
// remove \r
$lines = preg_replace( "/(\r\n)|(\n\r)/m", "\n", $rawlines );
$lines = preg_replace( "/\r/m", "\n", $lines );
// remove spaces from before tabs
$lines = preg_replace( "/\040+\t/m", "\t", $lines );
// remove spaces from line endings
$lines = preg_replace( "/[\040\t]+$/m", "", $lines );
// remove tabs from line endings
$lines = preg_replace( "/\t+$/m", "", $lines );
// remove EOF newlines
$lines = preg_replace( "/\n+$/", "", $lines );
// write file if changed and set old permissions
if( strlen( $lines ) != strlen( $rawlines )){
$perms = fileperms( $file );
// Uncomment to save original files
//rename( $file, $file.".old" );
file_put_contents( $file, $lines);
chmod( $file, $perms );
echo "${file}: FIXED\n";
} else {
echo "${file}: unchanged\n";
}
}
}
// get file list from argument array
function getFileList( $argv ) {
$files = array();
foreach( $argv as $arg ) {
// is a direcrtory
if( is_dir( $arg ) ) {
$files = array_merge( $files, getDirectoryTree( $arg ) );
}
// is a file
if( is_file( $arg ) ) {
$files[] = $arg;
}
}
return $files;
}
// recursively scan directory
function getDirectoryTree( $outerDir ){
$outerDir = preg_replace( ':' . DIRECTORY_SEPARATOR . '$:', '', $outerDir );
$dirs = array_diff( scandir( $outerDir ), array( ".", ".." ) );
$dir_array = array();
foreach( $dirs as $d ){
if( is_dir( $outerDir . DIRECTORY_SEPARATOR . $d ) ) {
$otherdir = getDirectoryTree( $outerDir . DIRECTORY_SEPARATOR . $d );
$dir_array = array_merge( $dir_array, $otherdir );
}
else $dir_array[] = $outerDir . DIRECTORY_SEPARATOR . $d;
}
return $dir_array;
}
?>
Eine Lösung (nicht unbedingt die besten) wäre zu verwenden git-filter- Zweig Geschichte neu zu schreiben, um immer korrekte Zeilenende zu verwenden. Dies sollte eine bessere Lösung sein, die interaktive Unterfütterungsmaterial, zumindest für eine größere Anzahl von Commits; es könnte auch mit verschmilzt mit git-filter-Zweig leichter zu behandeln.
Das ist natürlich, dass die Geschichte angenommen wurde nicht veröffentlicht (Repository wurde nicht geklont).