Nos développeurs utilisent un mélange de systèmes d'exploitation Windows et Unix. Par conséquent, les liens symboliques créés sur des machines Unix deviennent un problème pour les développeurs Windows. Dans Windows (msysgit), le lien symbolique est converti en un fichier texte avec un chemin d'accès au fichier vers lequel il pointe. Au lieu de cela, j'aimerais convertir le lien symbolique en un lien symbolique Windows réel.
La solution (mise à jour) dont je dispose est la suivante:
Je n'ai pas implémenté ceci, mais je pense que c'est une approche solide à ce problème.
Des questions:
Vous pouvez trouver les liens symboliques en recherchant les fichiers ayant le mode 120000
, éventuellement avec cette commande:
git ls-files -s | awk '/120000/{print $4}'
Une fois que vous avez remplacé les liens, je vous recommande de les marquer comme non modifiés avec git update-index --assume-unchanged
, plutôt que de les lister dans .git/info/exclude
.
Je posais cette même question il y a quelque temps (pas ici, mais en général) et j'ai fini par proposer une solution très similaire à la proposition de OP. Je vais d’abord répondre directement aux questions 1, 2 et 3, puis je posterai la solution que j’ai finalement utilisée.
git checkout
littérale, mais la solution ci-dessous a assez bien répondu à mes besoins qu’un script de post-paiement n’a pas été nécessaire.Nos développeurs sont à peu près dans la même situation que les OP: un mélange d’hôtes, de référentiels et de sous-modules Windows et de type Unix avec de nombreux liens symboliques git, et aucun support natif (encore) dans la version finale de MsysGit pour la gestion intelligente de ces liens symboliques sur les hôtes Windows. .
Merci à Josh Lee d'avoir signalé le fait que git envoie des liens symboliques avec le mode de fichier spécial 120000
. Avec ces informations, il est possible d'ajouter quelques alias git permettant la création et la manipulation de liens symboliques git sur des hôtes Windows.
Création de liens symboliques git sous 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
)"
Usage: git add-symlink <source_file_or_dir> <target_symlink>
, où l’argument correspondant au fichier ou au répertoire source doit se présenter sous la forme d’un chemin relatif au lien symbolique cible. Vous pouvez utiliser cet alias de la même manière vous utiliseriez normalement ln
.
Par exemple, l'arborescence du référentiel:
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/)
Peut être créé sur Windows comme suit:
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"
Remplacement des liens symboliques git par des liens durs NTFS + jonctions
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.
Usage:
git rm-symlinks [symlink] [symlink] [...]
Cet alias peut supprimer les liens symboliques git un par un ou tous les deux à la fois. Les liens symboliques seront remplacés par des liens durs NTFS (dans le cas de fichiers) ou par des jonctions NTFS (dans le cas de répertoires). L'avantage d'utiliser des liens durs + des jonctions par rapport aux "vrais" liens symboliques NTFS est que les autorisations de contrôle de compte élevées ne sont pas nécessaires pour être créées.
Pour supprimer les liens symboliques des sous-modules, utilisez simplement le support intégré de git pour les parcourir:
git submodule foreach --recursive git rm-symlinks
Mais, pour chaque action aussi drastique, un retournement est bien agréable à avoir ...
Restauration des liens symboliques git sous Windows
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'
Utilisation: git checkout-symlinks [symlink] [symlink] [...]
, qui annule git rm-symlinks
, restaure effectivement le référentiel dans son état naturel (à l'exception de vos modifications, qui devraitrester intact).
Et pour les sous-modules:
git submodule foreach --recursive git checkout-symlinks
Limitations:
Les répertoires/fichiers/liens symboliques avec des espaces dans leurs chemins devraient fonctionner. Mais des onglets ou des nouvelles lignes? YMMV… (Je veux dire par là: ne faites pas cela, car cela ne ne fonctionnera pastravail.)
Si vous-même ou les autres oubliez de git checkout-symlinks
avant de faire quelque chose de lourd en conséquences, comme git add -A
, le référentiel local pourrait se retrouver dans un état polluted.
En utilisant notre "exemple de dépôt" d'avant:
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
#
Oups ...
Pour cette raison, il est agréable d’inclure ces alias en tant qu’étapes à exécuter par les utilisateurs Windows avant et après la construction d’un projet, plutôt qu’après la fin du processus ou avant le transfert. Mais chaque situation est différente. Ces alias m'ont été suffisamment utiles pour qu'une véritable solution post-paiement ne soit pas nécessaire.
J'espère que ça t'as aidé!
Références:
http://git-scm.com/book/en/Git-Internals-Git-Objects
http://technet.Microsoft.com/en-us/library/cc753194
Dernière mise à jour: 2019-03-1
mklink
, bien sûr) - pas plus Bashisms !add-symlink
fonctionne maintenant plus comme ln (1) et peut être utilisé à partir de n’importe quel répertoire du référentiel, et pas uniquement du répertoire racine du référentiel.rm-symlink
alias (singulier) a été remplacé par le rm-symlinks
alias (pluriel), qui accepte désormais plusieurs arguments (ou aucun argument, qui trouve tous les liens symboliques dans le référentiel, comme auparavant). pour transformer sélectivement les liens symboliques git en liens durs NTFS + jonctions.checkout-symlinks
a également été mis à jour pour accepter plusieurs arguments (ou aucun, == tout) afin d'inverser de manière sélective les transformations susmentionnées.Note finale: Bien que j'ai testé le chargement et l'exécution de ces alias à l'aide de Bash 3.2 (et même de 3.1) pour ceux qui risquent de rester bloqués sur de telles versions anciennes pour un certain nombre de raisons, sachez que les versions aussi anciennes comme ceux-ci sont notoires pour leurs bogues d'analyse. Si vous rencontrez des problèmes lors de la tentative d'installation de l'un de ces alias, commencez par mettre à niveau votre shell (pour Bash, vérifiez la version avec CTRL + X, CTRL + V). Si vous essayez de les installer en les collant dans votre émulateur de terminal, vous aurez peut-être plus de chance de les coller dans un fichier et de les rechercher à la place, par exemple. comme
. ./git-win-symlinks.sh
Bonne chance!
La version la plus récente de git scm (testet 2.11.1) permet d'activer les liens symboliques. Mais vous devez à nouveau cloner le référentiel avec les liens symboliques git clone -c core.symlinks=true <URL>
. Vous devez exécuter cette commande avec des droits d'administrateur. Il est également possible de créer des liens symboliques sous Windows avec mklink. Découvrez le wiki .
Cela devrait être implémenté dans msysgit, mais il y a deux inconvénients:
J'ai fait une recherche rapide et des travaux sont en cours, voir la question 224 .
donc, comme les choses ont changé avec GIT depuis que beaucoup de réponses ont été postées, voici les instructions correctes pour que les liens symboliques fonctionnent correctement dans les fenêtres à partir de
AOUT 2018
1. Assurez-vous que git est installé avec le support des liens symboliques
2. Dites à Bash de créer des liens physiques à la place de liens symboliques
EDIT - (dossier git) /etc/bash.bashrc
AJOUTER AU BAS - MSYS=winsymlinks:nativestrict
3. Configurez git config pour utiliser des liens symboliques
git config core.symlinks true
ou
git clone -c core.symlinks=true <URL>
NOTE: J'ai essayé d'ajouter ceci à la configuration globale de git et pour le moment cela ne fonctionne pas pour moi, donc je recommande de l'ajouter à chaque rapport de suivi ...
4. tirer le repo
REMARQUE: sauf si vous avez activé le mode développeur dans la dernière version de Windows 10, vous devez exécuter bash en tant qu'administrateur pour créer des liens symboliques.
5. Réinitialiser tous les liens symboliques (facultatif) Si vous avez un référentiel existant ou utilisez des sous-modules, vous constaterez peut-être que les liens symboliques ne sont pas créés correctement. Vous pouvez donc les actualiser. commandes.
find -type l -delete
git reset --hard
NOTE: cela réinitialisera toutes les modifications depuis la dernière validation alors assurez-vous d’avoir commis la première
Je suggérerais que vous n'utilisiez pas de liens symboliques dans le repo '. Stockez le contenu réel dans le référentiel, puis placez des liens symboliques en dehors du référentiel qui pointe vers le contenu.
Supposons donc que vous utilisez un référentiel pour comparer l'hébergement de votre site sur * nix avec l'hébergement de Win. Stockez le contenu dans votre dépôt ', disons /httpRepoContent
et c:\httpRepoContent
, le dossier synchronisé via GIT, SVN, etc.
Ensuite, remplacez le dossier de contenu de votre serveur Web (/var/www
et c:\program files\web server\www
{les noms importent peu, modifiez-le si nécessaire}) par un lien symbolique vers le contenu de votre référentiel '. Les serveurs Web verront le contenu comme étant à la "bonne" place, mais vous utiliserez votre contrôle de source.
Cependant, si vous devez utiliser des liens symboliques dans le référentiel ', vous devrez vous pencher sur quelque chose comme une sorte de script avant/après validation. Je sais que vous pouvez les utiliser pour effectuer certaines tâches, telles que l'analyse de fichiers de code via un programme de formatage, afin de pouvoir convertir les liens symboliques entre les plates-formes.
si quelqu'un connaît un bon endroit pour apprendre à faire ces scripts pour les contrôles source communs, SVN GIT MG, alors veuillez ajouter un commentaire.
Réponse courte: ils sont désormais bien pris en charge, si vous pouvez activer le mode développeur.
De https://blogs.windows.com/buildingapps/2016/12/02/symlinks-windows-10/
Désormais, dans Windows 10 Creators Update, un utilisateur (avec des droits d'administrateur) peut d'abord activer le mode développeur, puis tout utilisateur de l'ordinateur peut exécuter la commande mklink sans élever la console de ligne de commande.
Qu'est-ce qui a motivé ce changement? La disponibilité et l'utilisation de liens symboliques est un gros problème pour les développeurs modernes:
De nombreux outils de développement populaires tels que git et les gestionnaires de paquets, tels que npm, reconnaissent et conservent les liens symboliques persistants lors de la création de dépôts ou de paquets, respectivement. Lorsque ces dépôts ou ces paquets sont ensuite restaurés ailleurs, les liens symboliques sont également restaurés, pour que l’espace disque (et le temps de l’utilisateur) ne soit pas perdu.
Il est facile d'ignorer toutes les autres annonces de la "mise à jour du créateur", mais si vous activez le mode Développeur, vous pouvez créer des liens symboliques sans privilèges élevés. Vous devrez peut-être réinstaller et vous assurer que le support est activé, car ce n'est pas le cas par défaut.
Pour ceux qui utilisent CygWin sur Vista, Win7 ou une version ultérieure, la commande native git
peut créer des liens symboliques "appropriés" reconnus par les applications Windows, tels que Android Studio . Vous devez simplement définir la variable d’environnement CYGWIN
pour inclure winsymlinks:native
ou winsymlinks:nativestrict
en tant que tel:
export CYGWIN="$CYGWIN winsymlinks:native"
L'inconvénient de ceci (et de son inconvénient majeur) est que le shell CygWin doit être "Exécuter en tant qu'administrateur" afin de disposer des autorisations du système d'exploitation requises pour créer ce type de lien symbolique. Cependant, une fois créés, aucune autorisation spéciale n'est requise pour les utiliser . Tant qu'ils ne sont pas modifiés dans le référentiel par un autre développeur, git
fonctionne ensuite correctement avec les autorisations utilisateur normales.
Personnellement, j’utilise ceci uniquement pour les liens symboliques qui sont parcourus par les applications Windows (c’est-à-dire non-CygWin) en raison de cette difficulté supplémentaire.
Pour plus d'informations sur cette option, consultez cette SO question: Comment créer un lien symbolique avec cygwin dans Windows 7
Voici un script de traitement par lots pour la conversion de liens symboliques dans un référentiel, pour les fichiers uniquement, basé sur la réponse de Josh Lee. Le script avec une vérification supplémentaire des droits d'administrateur est à 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
Je recherchais une solution simple pour gérer les liens symboliques Unix sous Windows. Merci beaucoup pour les pseudonymes ci-dessus de Git. Il existe une petite optimisation qui peut être apportée à rm-symlinks afin qu’il ne supprime pas les fichiers du dossier de destination au cas où l’alias serait exécuté une deuxième fois par erreur. Veuillez observer la nouvelle condition if dans la boucle pour vous assurer que le fichier n'est pas déjà un lien vers un répertoire avant que la logique ne soit exécutée.
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
J'utilise des liens sym tout le temps entre la racine de mon document et le répertoire git repo. J'aime les garder séparés. Sur Windows, j'utilise l'option mklink/j. La jonction semble laisser git se comporter normalement:
>mklink /j <location(path) of link> <source of link>
par exemple:
>mklink /j c:\gitRepos\Posts C:\Bitnami\wamp\Apache2\htdocs\Posts
Une astuce simple consiste à appeler git add --all
deux fois de suite.
Par exemple, nos appels de script de validation Windows 7:
$ git add --all
$ git add --all
Le premier ajout traite le lien en tant que texte et ajoute les dossiers à supprimer.
Le deuxième ajout traverse correctement le lien et annule la suppression en restaurant les fichiers.
C'est moins élégant que certaines des solutions proposées, mais c'est une solution simple à certains de nos environnements hérités auxquels des liens symboliques ont été ajoutés.