Zeilenenden Durcheinander in Git - so verfolgen Sie änderungen von einem Zweig nach einem großen Zeilenende fix?

StackOverflow https://stackoverflow.com/questions/1011985

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!

War es hilfreich?

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 zu LF wenn aus dem Dateisystem zu lesen, und umgekehrt umwandeln, wenn auf das Dateisystem zu schreiben. Die Variable kann so eingestellt werden, um input in diesem Fall die Umwandlung geschieht nur während aus dem Dateisystem zu lesen, aber Dateien werden mit LF am Ende der Zeilen geschrieben werden. Eine Datei wird „text“ betrachtet ( d. zum autocrlf Mechanismus unterworfen werden) auf der Grundlage der crlf Attribut der Datei, oder wenn crlf 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).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top