開発者は、WindowsベースとUnixベースのOSを組み合わせて使用します。したがって、Unixマシンで作成されたシンボリックリンクは、Windows開発者にとって問題になります。 Windows(msysgit)では、シンボリックリンクは、それが指すファイルへのパスを持つテキストファイルに変換されます。代わりに、シンボリックリンクを実際のWindowsシンボリックリンクに変換したいと思います。
(更新済み)解決策は次のとおりです。
私はこれを実装していませんが、これはこの問題に対する堅実なアプローチだと思います。
質問:
おそらく次のコマンドを使用して、120000
のモードを持つファイルを検索することにより、シンボリックリンクを見つけることができます。
git ls-files -s | awk '/120000/{print $4}'
リンクを置き換えたら、それらをgit update-index --assume-unchanged
にリストするのではなく、.git/info/exclude
で未変更としてマークすることをお勧めします。
私はこのまったく同じ質問をしばらく前に尋ねていました(ここではありませんが、一般的なことです)が、OPの命題と非常によく似た解決策を思い付きました。最初に質問1 2および3に直接回答し、次に使用したソリューションを投稿します。
git checkout
ステップとしてではないかもしれませんが、以下のソリューションは、リテラルのポストチェックアウトスクリプトが必要ないほど十分に私のニーズを満たしました。開発者はOPとほぼ同じ状況にあります:WindowsとUnixのようなホスト、リポジトリとサブモジュールの混合物、多くのgitシンボリックリンク、およびWindowsホストでこれらのシンボリックリンクをインテリジェントに処理するためのMsysGitのリリースバージョンにはネイティブサポートはありません。
Gitが特別なファイルモード120000
でシンボリックリンクをコミットするという事実を指摘してくれたJosh Leeに感謝します。この情報を使用して、Windowsホストでgitシンボリックリンクの作成と操作を可能にするいくつかのgitエイリアスを追加できます。
Windowsでのgitシンボリックリンクの作成
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"
gitシンボリックリンクを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シンボリックリンクを1つずつ削除することも、一度に全部を削除することもできます。シンボリックリンクは、NTFSハードリンク(ファイルの場合)またはNTFSジャンクション(ディレクトリの場合)に置き換えられます。 「真の」NTFSシンボリックリンクよりもハードリンク+ジャンクションを使用する利点は、それらを作成するために昇格したUACアクセス許可が必要ないことです。
サブモジュールからシンボリックリンクを削除するには、それらの繰り返しに対するgitの組み込みサポートを使用します。
git submodule foreach --recursive git rm-symlinks
しかし、このような抜本的なアクションの場合、逆転は素晴らしいことです...
Windowsでのgitシンボリックリンクの復元
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
を元に戻し、リポジトリを自然な状態に効果的に復元します(変更を除き、shouldはそのままです)。
そして、サブモジュールの場合:
git submodule foreach --recursive git checkout-symlinks
制限:
パスにスペースが含まれるディレクトリ/ファイル/シンボリックリンクが機能するはずです。しかし、タブまたは改行? 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
mklink
呼び出しを除く)—もうありません Bashisms !add-symlink
エイリアスは ln(1) のように動作するようになり、リポジトリのルートディレクトリだけでなく、リポジトリ内の任意のディレクトリから使用できます。rm-symlink
エイリアス(単数形)は、rm-symlinks
エイリアス(複数形)に置き換わりました。これは、gitシンボリックリンクをNTFSハードリンクに選択的に変換するために、複数の引数を受け入れるようになりました。 +ジャンクション。checkout-symlinks
エイリアスも更新され、前述の変換を選択的に反転するために、複数の引数(またはまったく引数なし==すべて)を受け入れるようになりました。最後の注意:このような古代バージョンにまだ固執しているかもしれない人のために、Bash 3.2(さらには3.1)を使用してこれらのエイリアスのロードと実行をテストしましたがさまざまな理由で、これらと同じくらい古いバージョンはパーサーのバグで悪名高いことに注意してください。これらのエイリアスをインストールしようとして問題が発生した場合、最初に検討する必要があるのは、シェルのアップグレードです(Bashの場合、CTRL + X、CTRL + Vでバージョンを確認します)。または、ターミナルエミュレータに貼り付けてインストールしようとしている場合は、ファイルに貼り付けて、代わりにソースを作成することもできます。として
. ./git-win-symlinks.sh
がんばろう!
Msysgitで実装する必要がありますが、2つの欠点があります。
私はクイック検索を行いましたが、これに関して積極的に行われている作業があります。問題 224 を参照してください。
これらの回答の多くがここに投稿されてからGITで物事が変わったので、現在のウィンドウでシンボリックリンクを正しく動作させるための正しい手順です
2018年8月
1。 gitがシンボリックリンクサポートと共にインストールされていることを確認してください
2。シンボリックリンクの代わりにハードリンクを作成するようにBashに指示します
編集-(gitフォルダー)/etc/bash.bashrc
下部に追加-MSYS=winsymlinks:nativestrict
3。シンボリックリンクを使用するように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
注:これにより、最後のコミット以降の変更がリセットされるため、最初にコミットしたことを確認してください
リポジトリ内でシンボリックリンクを使用しないことをお勧めします。リポジトリ内に実際のコンテンツを保存し、コンテンツを指すシンボリックリンクをリポジトリの外側に配置します。
たとえば、レポを使用して、* nixでのサイトのホスティングとwinでのホスティングを比較しているとします。コンテンツをレポジトリに保存します。/httpRepoContent
とc:\httpRepoContent
を言うことができます。これはGIT、SVNなどを介して同期されるフォルダーです。
次に、Webサーバーのコンテンツフォルダー(/var/www
とc:\program files\web server\www
{名前は重要ではありませんが、必要に応じて編集します})をリポジトリ内のコンテンツへのシンボリックリンクに置き換えます。 Webサーバーはコンテンツを実際には「正しい」場所にあると見なしますが、ソース管理を使用できます。
ただし、リポジトリでシンボリックリンクを使用する必要がある場合は、何らかの種類の事前/事後コミットスクリプトのようなものを調べる必要があります。これらを使用して、たとえばフォーマッタを介してコードファイルを解析するなどのことを実行できることを知っているので、プラットフォーム間でシンボリックリンクを変換できるはずです。
共通のソース管理、SVN GIT MGに対してこれらのスクリプトを実行する方法を学ぶのに適した場所を知っている人がいれば、コメントを追加してください。
簡単な答え:開発者モードを有効にできる場合、それらはうまくサポートされています。
から https://blogs.windows.com/buildingapps/2016/12/02/symlinks-windows-10/
Windows 10 Creators Updateでは、ユーザー(管理者権限を持つ)が最初に開発者モードを有効にでき、その後、コンピューターのユーザーはコマンドラインコンソールを昇格させることなくmklinkコマンドを実行できます。
何がこの変化を引き起こしたのですか?シンボリックリンクの可用性と使用は、現代の開発者にとって大きな問題です。
Gitのような多くの一般的な開発ツールとnpmのようなパッケージマネージャーは、それぞれリポジトリまたはパッケージを作成するときにシンボリックリンクを認識して保持します。これらのリポジトリまたはパッケージが他の場所に復元されると、シンボリックリンクも復元され、ディスクスペース(およびユーザーの時間)が無駄にならないようにします。
「Creator's update」の他のすべてのアナウンスを見逃すのは簡単ですが、開発者モードを有効にすると、昇格した権限なしでシンボリックリンクを作成できます。デフォルトではサポートされていないため、サポートを再インストールし、有効にする必要があります。
Vista、Win7、またはそれ以上で CygWin を使用している場合、ネイティブgit
コマンドは Android Studio などのWindowsアプリで認識される「適切な」シンボリックリンクを作成できます。 CYGWIN
環境変数を設定して、winsymlinks:native
またはwinsymlinks:nativestrict
を含めるだけです。
export CYGWIN="$CYGWIN winsymlinks:native"
これのマイナス面(そして重要な点)は、CygWinシェルがこれらの種類のシンボリックリンクを作成するために必要なOS権限を持つために「管理者として実行」する必要があることです。ただし、一度作成すると、useに特別な権限は必要ありません。別の開発者によってリポジトリで変更されない限り、その後git
は通常のユーザー権限で正常に実行されます。
個人的には、このonlyを使用するのは、この追加の難しさのために、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
私は、Windows上のUNIXシンボリックリンクに対処する簡単なソリューションを探していました。上記のGitエイリアスに感謝します。 rm-symlinksには、エイリアスが誤って2回実行された場合に宛先フォルダーのファイルが削除されないようにするための最適化が1つあります。ループ内の新しい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リポジトリディレクトリの間で常に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
使用する1つの簡単なトリックは、git add --all
を続けて2回呼び出すことです。
たとえば、Windows 7のコミットスクリプト呼び出し:
$ git add --all
$ git add --all
最初の追加では、リンクをテキストとして扱い、削除するフォルダーを追加します。
2番目の追加は、リンクを正しくトラバースし、ファイルを復元して削除を取り消します。
他の提案されたソリューションのいくつかよりもエレガントではありませんが、シンボリックリンクが追加された従来の環境の一部に対する単純な修正です。