24

定期的に更新されるサードパーティの PHP エンジンを使用しています。リリースは git の別のブランチに保持され、フォークはマスター ブランチです。

このようにして、エンジンの新しいリリースからフォークにパッチを適用できます。

私の問題は、私たちのブランチに何度もコミットした後、エンジンの最初のインポートが CRLF 行末で行われたことに気付きました。

すべてのファイルを LF に変換しましたが、これは 10 万行が削除され、10 万行が追加されたという大規模なコミットを行いました。これは、サードパーティ エンジンのファクトリー リリースからパッチを簡単にマージするという、私たちが意図したことを明らかに破っています。

私は何を知っていますか?どうすればこれを修正できますか? フォークにはすでに何百ものコミットがあります。

良いことは、最初のインポートの後、独自のフォークを分岐する前に行末修正コミットを何らかの方法で実行し、履歴の後半でその巨大な行末コミットを削除することです。

ただし、Git でこれを行う方法がわかりません。

ありがとう!

4

5 に答える 5

3

見ましたgit rebaseか?

次のように、リポジトリの履歴を再ベースする必要があります。

  • 行末記号の修正をコミットする
  • リベースを開始する
  • サードパーティのインポートコミットを最初に残す
  • 行末記号の修正を適用する
  • 他のパッチを適用する

ただし、理解する必要があるのは、これによりすべてのダウンストリーム リポジトリ (親リポジトリから複製されたもの) が壊れることです。理想的には、それらをゼロから開始します。


更新:使用例:

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

最後の 3 つのコミットのリベース セッションを開始します。

于 2009-06-18T10:41:36.553 に答える
3

今後はcore.autocrlf、 に記載されている設定でこの問題を回避してgit config --helpください。

core.autocrlf

true の場合、gitCRLFはテキスト ファイルの行末をLFファイル システムから読み取るときに に変換し、ファイル システムに書き込むときに逆に変換します。この変数は に設定できます。inputこの場合、変換はファイルシステムからの読み取り中にのみ行われますが、ファイルはLF行末に で書き出されます。ファイルは、ファイルの属性に基づいて、または指定されていない場合はファイルの内容に基づいて、「テキスト」(つまりautocrlf、メカニズムの対象となる) と見なされます。gitattributesを参照してください。crlfcrlf

于 2010-01-08T18:25:43.843 に答える
2

将来的には、次の方法でこの問題を回避しています。

1)誰もが末尾の空白を削除するエディターを使用し、すべてのファイルをLFで保存します。

2)1)失敗した場合(可能性があります-何らかの理由で誰かが誤ってCRLFに保存した場合)、CRLF文字をチェックするpre-commitスクリプトがあります。

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

このスクリプトはGNUgrepを使用し、Mac OS Xで動作しますが、他のプラットフォームで使用する前にテストする必要があります(CygwinとBSD grepで問題が発生しました)

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;
    }
?>
于 2010-01-09T11:25:40.610 に答える
2

1 つの解決策 (必ずしも最良の解決策とは限りません) は、git-filter-branchを使用して履歴を書き換え、常に正しい行末を使用することです。これは、少なくともコミット数が多い場合は、インタラクティブなリベースよりも優れたソリューションになるはずです。また、git-filter-branch を使用してマージを処理する方が簡単かもしれません。

もちろん、これは履歴が公開されていない(リポジトリが複製されていない)ことを前提としています。

于 2009-06-18T12:01:57.247 に答える