IT story

Windows의 Git Symlinks

hot-time 2020. 4. 18. 09:36
반응형

Windows의 Git Symlinks


우리 개발자들은 Windows와 Unix 기반 OS를 혼합하여 사용합니다. 따라서 Unix 시스템에서 작성된 심볼릭 링크는 Windows 개발자에게 문제가됩니다. Windows (msysgit)에서 symlink는 가리키는 파일의 경로가있는 텍스트 파일로 변환됩니다. 대신 symlink를 실제 Windows symlink로 변환하고 싶습니다.

내가해야 할 ( 업데이트 된 ) 솔루션은 다음과 같습니다.

  • "symlink"텍스트 파일을 재귀 적으로 찾는 체크 아웃 후 스크립트를 작성하십시오.
  • 더미 "symlink"와 동일한 이름 및 확장자를 가진 Windows symlink (mklink 사용)로 바꾸십시오.
  • .git / info / exclude에 항목을 추가하여이 Windows symlink를 무시하십시오.

나는 이것을 구현하지 않았지만 이것이이 문제에 대한 견고한 접근법이라고 생각합니다.

질문 :

  1. 이 접근법의 단점은 무엇입니까?
  2. 이 사후 체크 아웃 스크립트도 구현할 수 있습니까? 즉, git이 생성 한 더미 "symlink"파일을 재귀 적으로 찾을 수 있습니까?
  3. 이미 그런 스크립트를 작업 한 사람이 있습니까?

120000이 명령을 사용 하여 모드를 가진 파일을 찾아서 심볼릭 링크를 찾을 수 있습니다 .

git ls-files -s | awk '/120000/{print $4}'

당신이 링크를 교체하면, 내가 가진 변화로 마킹 추천 할 것입니다 git update-index --assume-unchanged보다는에 나열 .git/info/exclude.


나는이 똑같은 질문을 잠시 동안 (여기서는 일반적인 것이 아니라) 묻고 OP의 제안과 매우 비슷한 해결책을 찾았습니다. 먼저 질문 1 2 & 3에 대한 답변을 제공 한 다음 사용했던 솔루션을 게시하겠습니다.

  1. 실제로 저장소 오염 가능성이 증가하거나 "Windows symlink"상태 인 동안 실수로 중복 파일을 추가하는 것과 관련하여 제안 된 솔루션에는 몇 가지 단점이 있습니다. (아래 "제한 사항"에 대한 자세한 내용)
  2. 예, 체크 아웃 후 스크립트를 구현할 수 있습니다! 문자 그대로 사후 git checkout단계가 아닐 수도 있지만 아래 솔루션은 문자 그대로 사후 점검 스크립트가 필요하지 않을 정도로 필자의 요구를 충분히 충족 시켰습니다.
  3. 예!

해결책:

개발자는 OP와 거의 같은 상황에 있습니다 .Windows 및 Unix와 유사한 호스트, git symlink가 많은 리포지토리 및 하위 모듈이 혼합되어 있으며 Windows 호스트에서 이러한 symlink를 지능적으로 처리하기 위해 MsysGit 릴리스 버전에서 기본 지원 (아직)이 지원되지 않음 .

git이 특수 파일 모드로 심볼릭 링크를 커밋한다는 사실을 지적한 Josh Lee에게 감사드립니다 120000. 이 정보를 사용하면 Windows 호스트에서 git symlink를 작성하고 조작 할 수있는 몇 가지 git 별명을 추가 할 수 있습니다.

  1. Windows에서 자식 심볼릭 링크 만들기

    git config --global alias.add-symlink '!'"$(cat <<'ETX'
    __git_add_symlink() {
      if [ $# -ne 2 ] || [ "$1" = "-h" ]; then
        printf '%b\n' \
            'usage: git add-symlink <source_file_or_dir> <target_symlink>\n' \
            'Create a symlink in a git repository on a Windows host.\n' \
            'Note: source MUST be a path relative to the location of target'
        [ "$1" = "-h" ] && return 0 || return 2
      fi
    
      source_file_or_dir=${1#./}
      source_file_or_dir=${source_file_or_dir%/}
    
      target_symlink=${2#./}
      target_symlink=${target_symlink%/}
      target_symlink="${GIT_PREFIX}${target_symlink}"
      target_symlink=${target_symlink%/.}
      : "${target_symlink:=.}"
    
      if [ -d "$target_symlink" ]; then
        target_symlink="${target_symlink%/}/${source_file_or_dir##*/}"
      fi
    
      case "$target_symlink" in
        (*/*) target_dir=${target_symlink%/*} ;;
        (*) target_dir=$GIT_PREFIX ;;
      esac
    
      target_dir=$(cd "$target_dir" && pwd)
    
      if [ ! -e "${target_dir}/${source_file_or_dir}" ]; then
        printf 'error: git-add-symlink: %s: No such file or directory\n' \
            "${target_dir}/${source_file_or_dir}" >&2
        printf '(Source MUST be a path relative to the location of target!)\n' >&2
        return 2
      fi
    
      git update-index --add --cacheinfo 120000 \
          "$(printf '%s' "$source_file_or_dir" | git hash-object -w --stdin)" \
          "${target_symlink}" \
        && git checkout -- "$target_symlink" \
        && printf '%s -> %s\n' "${target_symlink#$GIT_PREFIX}" "$source_file_or_dir" \
        || return $?
    }
    __git_add_symlink
    ETX
    )"
    

    사용법 : git add-symlink <source_file_or_dir> <target_symlink>, 여기서 소스 파일 또는 디렉토리에 해당하는 인수 는 대상 심볼릭 링크에 상대적인 경로 형식을 가져야합니다 . 이 별칭은 일반적으로 사용하는 것과 같은 방식으로 사용할 수 있습니다 ln.

    예를 들어, 저장소 트리 :

    dir/
    dir/foo/
    dir/foo/bar/
    dir/foo/bar/baz      (file containing "I am baz")
    dir/foo/bar/lnk_file (symlink to ../../../file)
    file                 (file containing "I am file")
    lnk_bar              (symlink to dir/foo/bar/)
    

    다음과 같이 Windows에서 작성할 수 있습니다.

    git init
    mkdir -p dir/foo/bar/
    echo "I am baz" > dir/foo/bar/baz
    echo "I am file" > file
    git add -A
    git commit -m "Add files"
    git add-symlink ../../../file dir/foo/bar/lnk_file
    git add-symlink dir/foo/bar/ lnk_bar
    git commit -m "Add symlinks"
    
  2. git symlink를 NTFS 하드 링크 + 접합으로 대체

    git config --global alias.rm-symlinks '!'"$(cat <<'ETX'
    __git_rm_symlinks() {
      case "$1" in (-h)
        printf 'usage: git rm-symlinks [symlink] [symlink] [...]\n'
        return 0
      esac
      ppid=$$
      case $# in
        (0) git ls-files -s | grep -E '^120000' | cut -f2 ;;
        (*) printf '%s\n' "$@" ;;
      esac | while IFS= read -r symlink; do
        case "$symlink" in
          (*/*) symdir=${symlink%/*} ;;
          (*) symdir=. ;;
        esac
    
        git checkout -- "$symlink"
        src="${symdir}/$(cat "$symlink")"
    
        posix_to_dos_sed='s_^/\([A-Za-z]\)_\1:_;s_/_\\\\_g'
        doslnk=$(printf '%s\n' "$symlink" | sed "$posix_to_dos_sed")
        dossrc=$(printf '%s\n' "$src" | sed "$posix_to_dos_sed")
    
        if [ -f "$src" ]; then
          rm -f "$symlink"
          cmd //C mklink //H "$doslnk" "$dossrc"
        elif [ -d "$src" ]; then
          rm -f "$symlink"
          cmd //C mklink //J "$doslnk" "$dossrc"
        else
          printf 'error: git-rm-symlink: Not a valid source\n' >&2
          printf '%s =/=> %s  (%s =/=> %s)...\n' \
              "$symlink" "$src" "$doslnk" "$dossrc" >&2
          false
        fi || printf 'ESC[%d]: %d\n' "$ppid" "$?"
    
        git update-index --assume-unchanged "$symlink"
      done | awk '
        BEGIN { status_code = 0 }
        /^ESC\['"$ppid"'\]: / { status_code = $2 ; next }
        { print }
        END { exit status_code }
      '
    }
    __git_rm_symlinks
    ETX
    )"
    
    git config --global alias.rm-symlink '!git rm-symlinks'  # for back-compat.
    

    용법:

    git rm-symlinks [symlink] [symlink] [...]
    

    이 별칭은 git symlink를 하나씩 또는 한 번에 모두 제거 할 수 있습니다. 심볼릭 링크는 NTFS 하드 링크 (파일의 경우) 또는 NTFS 정션 (디렉토리의 경우)으로 대체됩니다. "true"NTFS 심볼릭 링크에 비해 하드 링크 + 접합을 사용하면 UAC 권한높일 필요가 없다는 이점이 있습니다.

    서브 모듈에서 심볼릭 링크를 제거하려면 git의 내장 지원을 사용하여 서브 모듈을 반복하십시오.

    git submodule foreach --recursive git rm-symlinks
    

    그러나 이와 같은 모든 과감한 행동에 대해 반전은 좋은 일입니다 ...

  3. Windows에서 git symlinks 복원

    git config --global alias.checkout-symlinks '!'"$(cat <<'ETX'
    __git_checkout_symlinks() {
      case "$1" in (-h)
        printf 'usage: git checkout-symlinks [symlink] [symlink] [...]\n'
        return 0
      esac
      case $# in
        (0) git ls-files -s | grep -E '^120000' | cut -f2 ;;
        (*) printf '%s\n' "$@" ;;
      esac | while IFS= read -r symlink; do
        git update-index --no-assume-unchanged "$symlink"
        rmdir "$symlink" >/dev/null 2>&1
        git checkout -- "$symlink"
        printf 'Restored git symlink: %s -> %s\n' "$symlink" "$(cat "$symlink")"
      done
    }
    __git_checkout_symlinks
    ETX
    )"
    
    git config --global alias.co-symlinks '!git checkout-symlinks'
    

    사용법 : git checkout-symlinks [symlink] [symlink] [...], 실행 취소 git rm-symlinks효과적으로 (변경 사항을 제외하고 자연 상태로 저장소를 복원 해야 그대로 유지).

    하위 모듈의 경우 :

    git submodule foreach --recursive git checkout-symlinks
    
  4. 한계 :

    • 경로에 공백이있는 디렉토리 / 파일 / 심볼 링크가 작동해야합니다. 그러나 탭이나 줄 바꿈? YMMV는 (이에 의해 말 : 그렇게하지 않습니다 있기 때문에 하지 않습니다 작동합니다.)

    • 자신이나 다른 사람이 git checkout-symlinks와 같이 잠재적으로 광범위한 결과를 초래하는 작업을 잊어 버린 경우 git add -A로컬 저장소는 오염 된 상태가 될 수 있습니다.

      이전의 "example repo"사용 :

      echo "I am nuthafile" > dir/foo/bar/nuthafile
      echo "Updating file" >> file
      git add -A
      git status
      # On branch master
      # Changes to be committed:
      #   (use "git reset HEAD <file>..." to unstage)
      #
      #       new file:   dir/foo/bar/nuthafile
      #       modified:   file
      #       deleted:    lnk_bar           # POLLUTION
      #       new file:   lnk_bar/baz       # POLLUTION
      #       new file:   lnk_bar/lnk_file  # POLLUTION
      #       new file:   lnk_bar/nuthafile # POLLUTION
      #
      

      으악 ...

      따라서 체크 아웃 후 또는 푸시하기 전에 프로젝트를 빌드하기 전후에 Windows 사용자가 수행 할 단계로 이러한 별명을 포함시키는 것이 좋습니다. 그러나 각 상황은 다릅니다. 이 별명은 진정한 사후 점검 솔루션이 필요하지 않을 정도로 유용했습니다.

희망이 도움이됩니다!

참고 문헌 :

http://git-scm.com/book/en/Git-Internals-Git-Objects

http://technet.microsoft.com/en-us/library/cc753194

최종 업데이트 : 2019-03-13

  • POSIX 준수 (물론 이러한 mklink호출을 제외하고 ) – 더 이상 Bashisms !
  • 공백이있는 디렉토리 및 파일이 지원됩니다.
  • 제로 및 제로가 아닌 종료 상태 코드 (각각 요청 된 명령의 성공 / 실패를 통신하기위한)가 올바르게 보존 / 복귀됩니다.
  • add-symlink별명은 이제 더처럼 작동 LN (1) 및 저장소의 디렉토리뿐 아니라 저장소의 루트 디렉토리에서 사용할 수 있습니다.
  • rm-symlink(단수) 별칭으로 대체 된 rm-symlinks선택적 NTFS에 하드 링크 + 접합에 자식 심볼릭 링크를 변환하는 (이전과 마찬가지로, 저장소 걸쳐 심볼릭 링크 모두를 찾거나 전혀 인수) 이제 다중 인수를 받아 별명 (복수) .
  • 또한 checkout-symlinks별칭은 위에서 언급 한 변환을 선택적으로 취소하기 위해 여러 인수를 받도록 (또는 전혀 == 모두 없음) 업데이트되었습니다.

마지막 참고 사항 : 여러 가지 이유로 여전히 고대 버전에 붙어있는 사람들을 위해 Bash 3.2 (및 심지어 3.1)를 사용하여 이러한 별칭을로드하고 실행하는 것을 테스트했지만 파서에 악명 높은 이전 버전은 버그. 이러한 별칭을 설치하는 동안 문제가 발생하면 가장 먼저 쉘을 업그레이드해야합니다 (Bash의 경우 CTRL + X, CTRL + V로 버전 확인). 또는 터미널 에뮬레이터에 붙여 넣어 설치하려고하는 경우 파일에 붙여 넣고 대신 소싱하는 것이 더 운이 좋을 수 있습니다.

. ./git-win-symlinks.sh

행운을 빕니다!


최신 버전의 git scm (testet 2.11.1)을 사용하면 기호 링크를 사용할 수 있습니다. 그러나 심볼릭 링크를 사용하여 저장소를 다시 복제해야합니다 git clone -c core.symlinks=true <URL>. 관리자 권한으로이 명령을 실행해야합니다. mklink를 사용하여 Windows에서 심볼릭 링크를 만들 수도 있습니다. 위키를 확인하십시오 .

여기에 이미지 설명을 입력하십시오


msysgit에서 구현되어야하지만 두 가지 단점이 있습니다.

  • 이전 버전은 디렉토리 접합 만 지원하므로 기호 링크는 Windows Vista 이상에서만 사용할 수 있습니다 (2011 년에는 문제가되지는 않지만 아직은 ...).
  • Microsoft는 기호 링크를 보안 위험으로 간주하므로 기본적으로 관리자 만 링크를 만들 수 있습니다. git 프로세스의 권한을 높이거나 fstool을 사용하여 작업하는 모든 시스템에서이 동작을 변경해야합니다.

빠른 검색을 수행했으며 이에 대한 작업이 활발히 진행되고 있습니다 (문제 224 참조) .


이 답변이 많이 게시 된 후 GIT로 변경되었으므로 Windows에서 심볼릭 링크가 올바르게 작동하도록하는 올바른 지침이 있습니다.

2018 년 8 월


1. git이 symlink를 지원하도록 설치되어 있는지 확인하십시오

Windows에서 git을 설치하는 동안

2. Bash에게 심볼릭 링크 대신 하드 링크를 만들도록 지시하십시오.

편집-(git 폴더) /etc/bash.bashrc

바닥에 추가- MSYS=winsymlinks:nativestrict

심볼릭 링크를 사용하도록 git config 설정

git config core.symlinks true

또는

git clone -c core.symlinks=true <URL>

참고 : 이것을 전역 git 구성에 추가하려고 시도했지만 현재 작동하지 않으므로 각 저장소에 추가하는 것이 좋습니다.

4. 레포를 당겨

참고 : 최신 버전의 Windows 10에서 개발자 모드를 활성화하지 않은 경우 관리자로 bash를 실행하여 심볼릭 링크를 만들어야합니다.

5. 모든 심볼릭 링크 재설정 (선택 사항) 기존 저장소가 있거나 하위 모듈을 사용중인 경우 심볼릭 링크가 올바르게 작성되지 않았으므로 저장소의 모든 심볼릭 링크를 새로 고치면 이러한 명령을 실행할 수 있습니다.

find -type l -delete
git reset --hard

참고 : 마지막 커밋 이후 변경 사항이 재설정되므로 먼저 커밋했는지 확인하십시오.


짧은 답변 : 개발자 모드를 활성화 할 수 있다면 이제 잘 지원됩니다.

에서 https://blogs.windows.com/buildingapps/2016/12/02/symlinks-windows-10/

이제 Windows 10 Creators Update에서 관리자 권한이있는 사용자는 먼저 개발자 모드를 활성화 한 다음 컴퓨터의 모든 사용자가 명령 줄 콘솔을 올리지 않고도 mklink 명령을 실행할 수 있습니다.

무엇이이 변화를 이끌었습니까? 심볼릭 링크의 가용성과 사용은 현대 개발자에게 큰 문제입니다.

git과 같은 많이 사용되는 개발 도구와 npm과 같은 패키지 관리자는 각각 저장소 또는 패키지를 만들 때 심볼릭 링크를 인식하고 유지합니다. 이러한 리포지토리 또는 패키지가 다른 곳에서 복원되면 심볼릭 링크도 복원되므로 디스크 공간 (및 사용자 시간)이 낭비되지 않습니다.

"Creator 's update"의 다른 모든 발표 내용을 간과하기 쉽지만 개발자 모드를 사용하면 높은 권한없이 심볼릭 링크를 만들 수 있습니다. 기본적으로 활성화되어 있지 않으므로 다시 설치하고 지원이 활성화되어 있는지 확인하십시오.

심볼릭 링크는 기본적으로 활성화되어 있지 않습니다


리포지토리에서 심볼릭 링크를 사용하지 않는 것이 좋습니다. 실제 컨텐츠를 저장소에 저장 한 다음 컨텐츠를 가리키는 저장소 외부에 심볼릭 링크를 배치하십시오.

따라서 renix를 사용하여 * nix에서 사이트를 호스팅하는 것과 win에서 호스팅하는 것을 비교한다고 가정 해 봅시다. 당신의 repo '의 콘텐츠를 저장, 말할 수 /httpRepoContentc:\httpRepoContent이 등 GIT, SVN을 통해 동기화 폴더 인 상태

그런 다음 웹 서버의 콘텐츠 폴더 ( /var/wwwc:\program files\web server\www{이름은 중요하지 않은 경우 편집해야 함})를 리포지토리의 콘텐츠에 대한 심볼릭 링크로 바꿉니다. 웹 서버는 내용을 실제로 '올바른'위치에 표시하지만 소스 제어를 사용해야합니다.

그러나 저장소에서 심볼릭 링크를 사용해야하는 경우 일종의 사전 / 사후 커밋 스크립트와 같은 것을 살펴 봐야합니다. 예를 들어 포매터를 통한 코드 파일 구문 분석과 같은 작업을 수행하는 데 사용할 수 있으므로 플랫폼 간 심볼릭 링크를 변환 할 수 있어야합니다.

SVN GIT MG에서 공통 소스 제어를 위해 이러한 스크립트를 수행하는 방법을 익히는 사람이 있다면 의견을 추가하십시오.


Vista, Win7 이상에서 CygWin사용하는 사용자의 경우 기본 git명령은 Android Studio 와 같은 Windows 앱에서 인식하는 "적절한"심볼릭 링크를 작성할 수 있습니다 . CYGWIN환경 변수를 포함 winsymlinks:native하거나 다음 winsymlinks:nativestrict같이 설정하면 됩니다 .

export CYGWIN="$CYGWIN winsymlinks:native"

이에 대한 단점은 CygWin 셸이 이러한 종류의 심볼릭 링크를 만드는 데 필요한 OS 권한을 갖기 위해서는 "관리자 권한으로 실행"이어야한다는 것입니다. 은 생성하고 나면,하지만 특별한 권한이 필요하지 않습니다 사용 을. 다른 개발자가 저장소에서 변경하지 않는 git한 정상적인 사용자 권한으로 정상적으로 실행됩니다.

개인적으로, 나는 이 추가 어려움으로 인해 Windows 앱 (예 : CygWin이 아닌)으로 탐색하는 심볼릭 링크 에만 사용합니다 .

이 옵션에 대한 자세한 내용은 다음 SO 질문 : Windows 7에서 cygwin과 심볼릭 링크를 만드는 방법을 참조하십시오.


다음은 Josh Lee의 답변을 기반으로 파일의 저장소에서만 심볼릭 링크를 변환하는 배치 스크립트입니다. 관리자 권한을 추가로 확인하는 스크립트는 https://gist.github.com/Quazistax/8daf09080bf54b4c7641에 있습니다.

@echo off
pushd "%~dp0"
setlocal EnableDelayedExpansion

for /f "tokens=3,*" %%e in ('git ls-files -s ^| findstr /R /C:"^120000"') do (
     call :processFirstLine %%f
)
REM pause
goto :eof

:processFirstLine
@echo.
@echo FILE:    %1

dir "%~f1" | find "<SYMLINK>" >NUL && (
  @echo FILE already is a symlink
  goto :eof
)

for /f "usebackq tokens=*" %%l in ("%~f1") do (
  @echo LINK TO: %%l

  del "%~f1"
  if not !ERRORLEVEL! == 0 (
    @echo FAILED: del
    goto :eof
  )

  setlocal
  call :expandRelative linkto "%1" "%%l"
  mklink "%~f1" "!linkto!"
  endlocal
  if not !ERRORLEVEL! == 0 (
    @echo FAILED: mklink
    @echo reverting deletion...
    git checkout -- "%~f1"
    goto :eof
  )

  git update-index --assume-unchanged "%1"
  if not !ERRORLEVEL! == 0 (
    @echo FAILED: git update-index --assume-unchanged
    goto :eof
  )
  @echo SUCCESS
  goto :eof
)
goto :eof

:: param1 = result variable
:: param2 = reference path from which relative will be resolved
:: param3 = relative path
:expandRelative
  pushd .
  cd "%~dp2"
  set %1=%~f3
  popd
goto :eof

내 문서 루트와 git repo 디렉토리 사이에 항상 sym 링크를 사용합니다. 나는 그것들을 별개로 유지하고 싶습니다. Windows에서는 mklink / j 옵션을 사용합니다. 접합은 git이 정상적으로 작동하게하는 것처럼 보입니다.

>mklink /j <location(path) of link> <source of link>

예를 들면 다음과 같습니다.

>mklink /j c:\gitRepos\Posts C:\Bitnami\wamp\apache2\htdocs\Posts


Windows의 유닉스 심볼릭 링크를 다루는 쉬운 솔루션을 찾고있었습니다. 위의 Git 별칭에 대단히 감사합니다. 별칭이 실수로 두 번째로 실행되는 경우 대상 폴더의 파일을 삭제하지 않도록 rm-symlinks에 대해 수행 할 수있는 최적화 방법이 거의 없습니다. 논리가 실행되기 전에 파일이 디렉토리에 대한 링크가 아닌지 확인하기 위해 루프에서 새 if 조건을 관찰하십시오.

git config --global alias.rm-symlinks '!__git_rm_symlinks(){
for symlink in $(git ls-files -s | egrep "^120000" | cut -f2); do
    *if [ -d "$symlink" ]; then
      continue
    fi*
    git rm-symlink "$symlink"
    git update-index --assume-unchanged "$symlink"
done
}; __git_rm_symlinksenter 

우리가 사용하는 간단한 트릭 git add --all은 연속으로 두 번 전화 하는 것입니다.

예를 들어, Windows 7 커밋 스크립트 호출은 다음과 같습니다.

$ git add --all
$ git add --all

첫 번째 추가는 링크를 텍스트로 취급하고 삭제할 폴더를 추가합니다.

두 번째 추가는 링크를 올바르게 통과하고 파일을 복원하여 삭제를 취소합니다.

다른 제안 된 솔루션보다 우아하지는 않지만 심볼릭 링크가 추가 된 일부 기존 환경에 대한 간단한 수정입니다.

참고 URL : https://stackoverflow.com/questions/5917249/git-symlinks-in-windows

반응형