Programing

머신 특정 구성 파일 커밋

crosscheck 2020. 10. 15. 07:33
반응형

머신 특정 구성 파일 커밋


개발할 때 일반적인 시나리오는 코드베이스에 시스템 특정 설정이 필요한 여러 구성 파일이 있다는 것입니다. 이 파일은 Git에 체크인되고 다른 개발자는 항상 실수로 다시 체크인하여 다른 사람의 구성을 손상시킵니다.

이에 대한 간단한 해결책은 Git에 체크인하지 않거나 추가로 .gitignore 항목을 추가하는 것입니다. 그러나 개발자가 필요에 맞게 수정할 수있는 파일에 합리적인 기본값을 갖는 것이 훨씬 더 우아하다는 것을 알았습니다.

이러한 파일로 Git을 멋지게 재생하는 우아한 방법이 있습니까? 컴퓨터 별 구성 파일을 수정 한 다음 해당 파일을 확인하지 않고 "git commit -a"를 실행할 수 있기를 바랍니다.


프로그램이 설정을 위해 한 쌍의 구성 파일을 읽도록하십시오. 먼저, config.defaults저장소에 포함될 파일을 읽어야 합니다. 그런 다음 다음에 config.local나열되어야 하는 파일을 읽어야합니다 ..gitignore

이 배열을 사용하면 새 설정이 기본 파일에 나타나고 업데이트되는 즉시 적용됩니다. 재정의 된 경우에만 특정 시스템에서 달라집니다.

이것에 대한 변형으로, config버전 제어에서 제공 하는 일반 파일 만 가질 수 있으며 include config.local컴퓨터 특정 값을 가져 오는 것과 같은 작업을 수행 하도록 할 수 있습니다. 이는 코드에보다 일반적인 메커니즘 (정책 대비)을 도입하고 결과적으로 더 복잡한 구성을 가능하게합니다 (응용 프로그램에 적합한 경우). 많은 대규모 오픈 소스 소프트웨어에서 볼 수있는이 확장은 to입니다 include conf.d. 이는 디렉토리의 모든 파일에서 구성을 읽습니다.

비슷한 질문에 대한 내 대답참조하십시오 .


시도 할 수 있습니다 git update-index --skip-worktree filename. 이것은 git에게 파일 이름에 대한 로컬 변경 사항이 존재하지 않는 척하라고 지시하므로 git commit -a무시합니다. 또한 저항 git reset --hard할 수 있는 추가 이점이 있으므로 실수로 로컬 변경 사항을 잃지 않을 것입니다. 또한 파일이 업스트림으로 변경되면 자동 병합이 정상적으로 실패합니다 (작업 디렉터리 복사본이 인덱스 복사본과 일치하지 않는 경우 자동으로 업데이트 됨). 단점은 관련된 모든 컴퓨터에서 명령을 실행해야한다는 점이며이를 자동으로 수행하기가 어렵습니다. git update-index --assume-unchanged이 아이디어의 미묘하게 다른 버전 도 참조하십시오 . 둘 다에 대한 자세한 내용은 git help update-index.


또 다른 접근 방식은 다른 개인 브랜치의 공통 구성 파일에 대한 로컬 변경을 유지하는 것입니다. 여러 로컬 변경이 필요한 일부 프로젝트에이 작업을 수행합니다. 이 기술이 모든 상황에 적용되는 것은 아니지만 어떤 경우에는 저에게 효과적입니다.

먼저 마스터 브랜치를 기반으로 새 브랜치를 생성합니다 (이 특정 경우에는 git-svn을 사용하므로 마스터에서 커밋해야하지만 여기서는 그다지 중요하지 않습니다).

git checkout -b work master

이제 필요에 따라 구성 파일을 수정하고 커밋합니다. 나는 보통 "NOCOMMIT"또는 "PRIVATE"와 같은 커밋 메시지에 독특한 것을 넣습니다 (나중에 유용 할 것입니다). 이 시점에서 자신의 구성 파일을 사용하여 비공개 브랜치에서 작업 할 수 있습니다.

작업을 업스트림으로 되돌리려면 work브랜치에서 마스터로 각 변경 사항을 선택하십시오 . 이 작업을 수행하는 데 도움이되는 스크립트가 있는데 다음과 같습니다.

#!/bin/sh

BRANCH=`git branch | grep ^\\* | cut -d' ' -f2`
if [ $BRANCH != "master" ]; then
  echo "$0: Current branch is not master"
  exit 1
fi

git log --pretty=oneline work...master | grep -v NOCOMMIT: | cut -d' ' -f1 | tac | xargs -l git cherry-pick

이 첫 번째는 내가 master지점 에 있는지 확인합니다 (건전성 확인). 그런 다음에 각 커밋을 나열 work하고 NOCOMMIT 키워드를 언급하는 커밋을 필터링하고 순서를 반대로 한 다음 마지막으로 각 커밋 (이제 가장 오래된 커밋부터)을 master.

마지막으로 마스터 업스트림에서 변경 사항을 work적용한 후 다시 전환하여 리베이스합니다.

git checkout work
git rebase master

Git은 work브랜치 의 각 커밋을 다시 적용 master하여 체리 피킹 통해 이미 적용된 커밋을 효과적으로 건너 뜁니다 . 남은 것은 NOCOMMIT 로컬 커밋뿐입니다.

이 기술은 푸시 프로세스에 시간이 좀 더 걸리지 만 문제가 해결되었으므로 공유 할 것이라고 생각했습니다.


한 가지 가능성은 .gitignore에 실제 파일이 있지만 다른 확장자로 기본 구성을 체크인하는 것입니다. Rails 앱의 일반적인 예는 config / database.yml 파일입니다. config / database.yml.sample을 확인하고 각 개발자는 이미 .gitignored 인 자체 config / database.yml을 만듭니다.


다른 확장자 (예 : .default)로 기본 구성을 체크인하고, symlink를 사용하여 기본값을 올바른 위치에 심볼릭 링크하고, 올바른 위치를 .gitignore에 추가하고, 구성과 관련된 다른 모든 것을 .gitignore에 추가합니다 (따라서 유일한 체크인되는 것은 config.default)입니다.

또한 응용 프로그램 전체에 대한 심볼릭 링크를 설정하는 빠른 설치 스크립트를 작성하십시오.

우리는 이전 회사에서 비슷한 접근 방식을 사용했습니다. 설치 스크립트는 실행중인 환경 (샌드 박스, 개발, QA, 프로덕션)을 자동 감지하여 올바른 작업을 자동으로 수행합니다. config.sandbox 파일이 있고 샌드 박스에서 실행중인 경우 해당 파일이 연결됩니다 (그렇지 않으면 .defaults 파일 만 연결됨). 일반적인 절차는 .defaults를 복사하고 필요에 따라 설정을 변경하는 것이 었습니다.

설치 스크립트를 작성하는 것은 상상하는 것보다 쉬우 며 많은 유연성을 제공합니다.


베스트 답변에 동의하지만 추가하고 싶습니다. ANT 스크립트를 사용하여 GIT 저장소에서 파일을 제거하고 수정하므로 프로덕션 파일을 덮어 쓰지 않습니다. ANT에는 java-property 파일을 수정하는 좋은 옵션이 있습니다. 이는 로컬 테스트 변수를 자바 스타일 속성 파일에 넣고 코드를 추가하여 처리하는 것을 의미하지만 FTP를 온라인으로 보내기 전에 사이트 구축을 자동화 할 수있는 기회를 제공합니다. 일반적으로 프로덕션 정보를 site.default.properties 파일에 넣고 ANT가 설정을 관리하도록합니다. 로컬 설정은 site.local.properties에 있습니다.

    <?php
/**
 * This class will read one or two files with JAVA style property files. For instance site.local.properties & site.default.properties
 * This will enable developers to make config files for their personal development environment, while maintaining a config file for 
 * the production site. 
 * Hint: use ANT to build the site and use the ANT <propertyfile> command to change some parameters while building.
 * @author martin
 *
 */
class javaPropertyFileReader {

    private $_properties;
    private $_validFile;

    /**
     * Constructor
     * @return javaPropertyFileReader
     */
    public function   __construct(){
        $this->_validFile = false;
        return $this;
    }//__construct

    /**
     * Reads one or both Java style property files
     * @param String $filenameDefaults
     * @param String $filenameLocal
     * @throws Exception
     * @return javaPropertyFileReader
     */
    public function readFile($filenameDefaults, $filenameLocal = ""){

        $this->handleFile($filenameDefaults);
        if ($filenameLocal != "") $this->handleFile($filenameLocal);
    }//readFile

    /**
     * This private function will do all the work of reading the file and  setting up the properties
     * @param String $filename
     * @throws Exception
     * @return javaPropertyFileReader
     */
    private function handleFile($filename){

    $file = @file_get_contents($filename);

    if ($file === false) {
         throw (New Exception("Cannot open property file: " . $filename, "01"));
    }
    else {
        # indicate a valid file was opened
        $this->_validFile = true;

        // if file is Windows style, remove the carriage returns
        $file = str_replace("\r", "", $file);

        // split file into array : one line for each record
        $lines = explode("\n", $file);

        // cycle lines from file
        foreach ($lines as $line){
            $line = trim($line);

            if (substr($line, 0,1) == "#" || $line == "") {
                #skip comment line
            }
            else{
                // create a property via an associative array
                $parts   = explode("=", $line);
                $varName = trim($parts[0]);
                $value   = trim($parts[1]);

                // assign property
                $this->_properties[$varName] = $value;
            }
        }// for each line in a file
    }
    return $this;
    }//readFile

    /**
     * This function will retrieve the value of a property from the property list.
     * @param String $propertyName
     * @throws Exception
     * @return NULL or value of requested property
     */
    function getProperty($propertyName){
        if (!$this->_validFile) throw (new Exception("No file opened", "03"));

        if (key_exists($propertyName, $this->_properties)){
            return $this->_properties[$propertyName];
        }
        else{
          return NULL;
        }
    }//getProperty

    /**
     * This function will retreive an array of properties beginning with a certain prefix.
     * @param String $propertyPrefix
     * @param Boolean $caseSensitive
     * @throws Exception
     * @return Array
     */
    function getPropertyArray($propertyPrefix, $caseSensitive = true){
        if (!$this->_validFile) throw (new Exception("No file opened", "03"));

        $res = array();

        if (! $caseSensitive) $propertyPrefix= strtolower($propertyPrefix);

        foreach ($this->_properties as $key => $prop){
            $l = strlen($propertyPrefix);

            if (! $caseSensitive) $key = strtolower($key);

            if (substr($key, 0, $l ) == $propertyPrefix) $res[$key] = $prop;
        }//for each proprty

        return $res;
    }//getPropertyArray

    function createDefineFromProperty($propertyName){
        $propValue = $this->getProperty($propertyName);
        define($propertyName, $propValue);
    }//createDefineFromProperty


    /**
     * This will create a number of 'constants' (DEFINE) from an array of properties that have a certain prefix.
     * An exception is thrown if 
     * @param  String $propertyPrefix
     * @throws Exception
     * @return Array The array of found properties is returned.
     */
    function createDefinesFromProperties($propertyPrefix){
        // find properties
        $props = $this->getPropertyArray($propertyPrefix);

        // cycle all properties 
        foreach($props as $key => $prop){

            // check for a valid define name
            if (preg_match("'[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*'", $key)) {
                define($key, $prop);
            }   
            else{
                throw (new Exception("Invalid entry in property file: cannot create define for {" . $key . "}", "04"));
            }   
        }// for each property found

        return $props;
    }//createDefineFromProperty

}//class javaPropertyFileReader

그런 다음 사용하십시오.

  $props = new javaPropertyFileReader();
  $props->readFile($_SERVER["DOCUMENT_ROOT"] . "/lib/site.default.properties",$_SERVER["DOCUMENT_ROOT"] . "/lib/site.local.properties");

  #create one DEFINE
  $props->createDefineFromProperty("picture-path");

  # create a number of DEFINEs for enabled modules
  $modules = $props->createDefinesFromProperties("mod_enabled_");

site.default.properties는 다음과 같습니다.

release-date=x
environment=PROD
picture-path=/images/

SITE_VERSION_PRODUCTION=PROD
SITE_VERSION_TEST=TEST
SITE_VERSION_DEVELOP=DEV

# Available Modules
mod_enabled_x=false
mod_enabled_y=true
mod_enabled_z=true

귀하의 site.local.properties는 다음과 같습니다 (차이 환경 및 활성화 된 모듈에 유의하십시오).

release-date=x
environment=TEST
picture-path=/images/

SITE_VERSION_PRODUCTION=PROD
SITE_VERSION_TEST=TEST
SITE_VERSION_DEVELOP=DEV

# Available Modules
mod_enabled_x=true
mod_enabled_y=true
mod_enabled_z=true

And your ANT instructions: ($d{deploy} being your deployment target directory)

<propertyfile
    file="${deploy}/lib/site.properties"
    comment="Site properties">
    <entry  key="environment" value="PROD"/>
    <entry  key="release-date" type="date" value="now" pattern="yyyyMMddHHmm"/>
</propertyfile>

The simplest solution is to edit the file to defaults, commit it, then add it to your .gitignore. This way, developers will not accidentally commit it when doing git commit -a, but they can still commit it in the (presumably rare) case where you want to change your defaults with git add --force.

However, having a .default and .local config file is ultimately the best solution, since this allows anyone with a machine-specific configuration to change the defaults, without having to break their own configuration.


I do it like it's recommended here with default and local config files. To manage my local config files wich are in the projects .gitignore, I made a git repo ~/settings. There I manage all my local settings from all projects. You create, for example a folder project1 in ~/settings and put all the local config stuff for this project into it. After that you can symlink that files/folder to your project1.

With that approach you can track your local config files, and don't put them into to the normal source code repository.


Building on @Greg Hewgill's answer, you could add a specific commit with your local changes and tag it as localchange:

git checkout -b feature master
vim config.local
git add -A && git commit -m "local commit" && git tag localchange

Then proceed to add your feature's commits. After finishing the work, you can merge this branch back to master without the localchange commit by doing this:

git rebase --onto master localchange feature
git fetch . feature:master
git cherry-pick localchange
git tag localchange -f

These commands will:

1) Rebase your feature branch to master, ignoring the localchange commit. 2) Fast forward master without leaving feature branch 3) Add localchange commit back to the top of the feature branch so you can continue working on it. You can do this to any other branch you want to continue working on. 4) Reset localchange tag to this cherry-picked commit so we can use rebase --onto again in the same way.

This isn't meant to replace the accepted answer as the best general solution, but as a way of thinking out of the box about the problem. You basically avoid accidentally merging local changes to master by only rebasing from localchange to feature and fast forwarding master.


Nowadays (2019) I use ENV vars for example in python/django, you can also add defaults to them. In the context of docker I can save the ENV vars in a docker-compose.yml file or an extra file which is ignored in version control.

# settings.py
import os
DEBUG = os.getenv('DJANGO_DEBUG') == 'True'
EMAIL_HOST = os.environ.get('DJANGO_EMAIL_HOST', 'localhost')

참고URL : https://stackoverflow.com/questions/1396617/committing-machine-specific-configuration-files

반응형