نهايات الأسطر معطوبة في Git - كيفية تتبع التغييرات من فرع آخر بعد إصلاح نهاية السطر الضخم؟

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

سؤال

نحن نعمل مع محرك PHP تابع لجهة خارجية ويحصل على تحديثات منتظمة.يتم الاحتفاظ بالإصدارات في فرع منفصل في git، والشوكة الخاصة بنا هي الفرع الرئيسي.

بهذه الطريقة سنكون قادرين على تطبيق تصحيحات على شوكتنا من الإصدارات الجديدة للمحرك.

مشكلتي هي أنه بعد العديد من الالتزامات لفرعنا، أدركت أن الاستيراد الأولي للمحرك تم مع نهايات سطر CRLF.

لقد قمت بتحويل كل ملف إلى LF، لكن هذا أدى إلى التزام كبير، حيث تمت إزالة 100 ألف سطر وإضافة 100 ألف سطر، وهو ما يخالف بوضوح ما كنا ننوي القيام به:يمكنك بسهولة دمج التصحيحات من إصدارات المصنع لمحرك الطرف الثالث.

ماذا علي أن أعرف؟كيف يمكنني اصلاح هذا؟لدي بالفعل مئات الالتزامات على مفترقنا.

ما سيكون جيدًا هو القيام بطريقة ما بإصلاح نهايات الأسطر بعد الاستيراد الأولي وقبل تفرع شوكتنا الخاصة، وإزالة التزام نهاية السطر الضخم هذا لاحقًا في التاريخ.

لكن ليس لدي أي فكرة عن كيفية القيام بذلك في Git.

شكرًا!

هل كانت مفيدة؟

المحلول

تمكنت أخيرا من حلها.

الجواب هو:

git filter-branch --tree-filter '~/Scripts/fix-line-endings.sh' -- --all

يحتوي Fix-line-endings.sh على:

#!/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

بعد أن تم إصلاح جميع نهايات الأسطر في جميع الأشجار وفي جميع الالتزامات، قمت بإجراء إعادة صياغة تفاعلية وأزلت جميع الالتزامات التي كانت تعمل على إصلاح نهايات الأسطر.

الآن أصبح الريبو الخاص بي نظيفًا وجديدًا وجاهزًا للدفع :)

ملاحظة للزوار:لا تفعل هذا إذا تم دفع / استنساخ الريبو الخاص بك لأنه سيؤدي إلى إفساد الأمور بشكل سيء!

نصائح أخرى

وبالتطلع إلى الأمام، وتجنب هذه المشكلة مع إعداد core.autocrlf، وثقت في git config --help :

<اقتباس فقرة>   

core.autocrlf

     

وإذا كان هذا صحيحا، يجعل بوابة تحويل CRLF في نهاية الأسطر في ملفات نصية إلى LF عند قراءة من نظام الملفات، وتحويل في الاتجاه المعاكس عند الكتابة إلى نظام الملفات. المتغير يمكن تعيين لinput، وفي هذه الحالة تحويل يحدث فقط أثناء القراءة من الملفات ولكن يتم كتابة الملفات خارج مع LF في نهاية الخطوط. ويعتبر ملف "النص" (<م> أي بمعنى. التعرض للآلية autocrlf) على أساس السمة crlf الملف، أو إذا crlf هو غير محدد، استنادا إلى محتويات الملف. انظر gitattributes .

هل نظرت إلى git rebase?

سوف تحتاج إلى إعادة تأسيس تاريخ المستودع الخاص بك، على النحو التالي:

  • ارتكاب إصلاحات فاصل الخط
  • بدء إعادة الأساس
  • اترك التزام استيراد الطرف الثالث أولاً
  • تطبيق إصلاحات فاصل الخط
  • تطبيق بقعك الأخرى

ما تحتاج إلى فهمه هو أن هذه الإرادة استراحة جميع المستودعات النهائية - تلك التي تم استنساخها من الريبو الأصلي الخاص بك.من الناحية المثالية سوف تبدأ من الصفر مع هؤلاء.


تحديث:استخدام العينة:

target=`git rev-list --max-count=3 HEAD | tail -n1`
get rebase -i $target

ستبدأ جلسة إعادة الأساس لآخر 3 التزامات.

ونحن تجنب هذه المشكلة في المستقبل مع:

1) كل شخص يستخدم محرر يجرد زائدة الفراغات، ونحن حفظ جميع الملفات مع LF.

2) إذا فشل 1) (ما في وسعها - شخص غير قصد حفظها في CRLF لأي سبب كان) لدينا إلزام قبل النصي الذي يتحقق من حرف CRLF:

#!/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 --

وهذا البرنامج النصي يستخدم GNU البقرى، ويعمل على نظام التشغيل Mac OS X، إلا أنه ينبغي اختبار قبل استخدامها على منصات أخرى (كان لدينا مشاكل مع سيغوين وBSD البقرى)

و3) في حالة نجد أية أخطاء المسافات البيضاء، ونحن نستخدم البرنامج النصي التالي على الملفات الخاطئة:

#!/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;
    }
?>

وحل واحد (وليس بالضرورة أفضل واحد) سيكون لاستخدام بوابة-مرشحات فرع لإعادة كتابة التاريخ دائما الى استخدام خط النهايات الصحيحة. هذا ينبغي أن يكون الحل الأفضل أن rebase التفاعلي، على الأقل بالنسبة لعدد أكبر من يرتكب. كما أنه قد يكون من الأسهل للتعامل مع دمج باستخدام بوابة تصفية الفروع.

وهذا هو بالطبع على افتراض أن التاريخ كان <م> لم تنشر (لم المستنسخة مستودع).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top