Jak mogę zmusić Gita do śledzenia dowiązań symbolicznych?

217

Czy najlepiej będzie, gdy będę używać skryptu powłoki, który zastępuje dowiązania symboliczne kopiami, czy też jest inny sposób, aby powiedzieć Gitowi, by podążał za dowiązaniami symbolicznymi?

PS: Wiem, że nie jest to zbyt bezpieczne, ale chcę to zrobić tylko w kilku konkretnych przypadkach.

Matt
źródło
5
czy jest wada używania twardych linków do czegoś takiego?
Ehtesh Choudhury
12
W systemie Windows 7 „mklink / d” (dowiązanie symboliczne katalogu) nie działa z git, ale „mklink / j” (juction) działa dobrze.
yoyo
1
Jeśli plik jest generowany automatycznie przez aplikację, która regeneruje go w taki sposób, że usuwa plik i tworzy nowy, to tak, jest to problem, że łącza do plików nie zostaną rozwiązane.
Martin Pecka,
1
@EhteshChoudhury nie możesz tworzyć twardych linków do katalogów
Gaurav Kansal

Odpowiedzi:

46

UWAGA: Ta rada jest obecnie nieaktualna zgodnie z komentarzem od wersji Git 1.6.1. Git zachowywał się w ten sposób i już tego nie robi.


Git domyślnie próbuje przechowywać dowiązania symboliczne zamiast je śledzić (dla zwięzłości i to jest to, czego ludzie chcą).

Jednak przypadkowo udało mi się go dodać, aby dodać pliki poza dowiązaniem symbolicznym, gdy dowiązanie symboliczne jest katalogiem.

To znaczy:

  /foo/
  /foo/baz
  /bar/foo --> /foo
  /bar/foo/baz

wykonując

 git add /bar/foo/baz

wydawało się, że działa, kiedy próbowałem. Zachowanie to było jednak przeze mnie niepożądane, więc nie mogę przekazać ci informacji poza tym.

Kent Fredric
źródło
72
Zatwierdzenia 725b06050a083474e240a2436121e0a80bb9f175 i 806d13b1ccdbdde4bbdfb96902791c4b7ed125f6 wprowadziły zmiany, które uniemożliwiły dodawanie plików poza katalogami dowiązanymi, więc to nie będzie działać w wersjach git od 1.6.1
Mark Longair
1
$ git add src / main / path / ConvertSymlinkToDir fatal: 'src / main / path / ConvertSymlinkToDir' wykracza poza dowiązanie symboliczne
użytkownik1767316
2
@ user1767316 przeczytaj całość i komentarze. Kiedyś działało, już nie działa. Zmiany oprogramowania, ale odpowiedzi zaakceptowane przez przepełnienie stosu nie. Wyjaśniłem, że to już nie działa. Spójrz na inną odpowiedź.
Kent Fredric
tak @KentFrederic, ale przekazanie dokładnego komunikatu o błędzie zwróciło pomoc użytkownika w stosowaniu rozwiązania problemu. próbowałem anulować głosowanie negatywne, ale zablokowano przepraszam. Z jednej strony twoja odpowiedź jest słuszna z uwagi na ostrzeżenie, z drugiej strony należy dać pierwszeństwo odpowiedzi, która działa teraz, a nie w przeszłości
użytkownik1767316
144

Co zrobiłem, aby dodać pliki z dowiązania symbolicznego do Git (nie użyłem dowiązania symbolicznego, ale):

sudo mount --bind SOURCEDIRECTORY TARGETDIRECTORY

Wykonaj to polecenie w katalogu zarządzanym przez Git. TARGETDIRECTORYmusi zostać utworzony przed SOURCEDIRECTORYzamontowaniem w nim.

Działa dobrze w systemie Linux, ale nie w systemie OS X! Ta sztuczka pomogła mi również w Subversion. Używam go do dołączania plików z konta Dropbox, na którym projektant robi swoje rzeczy.

użytkownik252400
źródło
8
Byłoby to bardzo miłe podejście, gdyby sudo nie było wymagane.
MestreLion
13
Aby cofnąć to powiązanie, użyj umount [mydir]. (+1 za Twoją świetną wskazówkę, @ user252400)
JellicleCat
10
Działa to tylko podczas sesji. Jaki jest najlepszy sposób, aby uczynić go „wiecznym”?
Adobe
17
@Adobe: umieść go w / etc / fstab, tak jak: / sourcedir / targetdir none bind
Alexander Garden
8
sshfs może tutaj osiągnąć taką sztuczkę, nie wymagając sudo.
PypeBros,
75

Dlaczego nie utworzyć dowiązań symbolicznych na odwrót? Oznacza to, że zamiast łączyć z repozytorium Git do katalogu aplikacji, wystarczy połączyć na odwrót.

Załóżmy na przykład, że konfiguruję zainstalowaną aplikację, ~/applicationktóra potrzebuje pliku konfiguracyjnego config.conf:

  • Dodaję config.confdo mojego repozytorium Git, na przykład o ~/repos/application/config.conf.
  • Następnie tworzę dowiązanie symboliczne ~/application, uruchamiając ln -s ~/repos/application/config.conf.

To podejście może nie zawsze działać, ale jak dotąd działało dobrze.

spier
źródło
5
Wydaje się, że to jedyny sposób i nie jest tak źle ... myślę, że twoje podejście jest dość eleganckie. git śledzi zawartość, a nie pliki. Więc utrzymywanie całej zawartości razem i linkowanie stamtąd do innych miejsc ma sens
MestreLion
12
W moim przypadku chciałem łącza z jednego repozytorium git do drugiego, aby móc edytować pliki w dowolnej lokalizacji i przypisywać je z powrotem do odpowiednich pilotów. W systemie Windows 7 połączenie („mklink / j”) załatwiło sprawę.
yoyo
3
oczywiście. czasami odpowiedź jest taka prosta.
BBW przed Windows
co jeśli chcesz uzyskać źródło i miejsce docelowe? (ponieważ oba należą do różnych kodów, które chcesz mieć w różnych repozytoriach)
DrGC
1
Nie odpowiada na pytanie :( Chciałem zsynchronizować część mojego repozytorium z moją iCloud. Niestety, iCloud nie podąża za dowiązaniami symbolicznymi, więc pomyślałem, że mogę zmusić git do podążania za dowiązaniami symbolicznymi i przechowywać oryginalne pliki w iCloud. Okazuje się, że nikt nie podąża dowiązania symboliczne: \
Jerry Green
49

Zamiast tego użyj twardych linków. Różni się to od miękkiego (symbolicznego) łącza. Wszystkie programy, w tym również gitbędą traktować plik jako zwykły plik. Należy pamiętać, że zawartość może być modyfikowana poprzez zmianę albo źródła lub przeznaczenia.

Na macOS (wcześniej niż 10.13 High Sierra)

Jeśli masz już zainstalowane git i Xcode, zainstaluj hardlink . To mikroskopijne narzędzie do tworzenia twardych łączy .

Aby utworzyć twardy link, po prostu:

hln source destination

Aktualizacja systemu macOS High Sierra

Czy system plików Apple obsługuje twarde łącza do katalogu?

Twarde łącza do katalogów nie są obsługiwane przez system plików Apple. Wszystkie twarde łącza do katalogu są konwertowane na dowiązania symboliczne lub aliasy podczas konwersji z formatów woluminów HFS + na APFS w systemie macOS.

Z APFS FAQ na developer.apple.com

Śledź https://github.com/selkhateeb/hardlink/issues/31, aby znaleźć przyszłe alternatywy.

W systemie Linux i innych wersjach Uniksa

lnPolecenie może zrobić dowiązania twarde:

ln source destination

W systemie Windows (Vista, 7, 8,…)

Ktoś zasugerował, aby użyć mklink utworzyć połączenie w systemie Windows, ale nie próbowałem:

mklink /j "source" "destination"
fregante
źródło
7
Tylko uwaga: tego właśnie szukałem, ale potem dowiedziałem się, że w Linuksie hardlink niestety nie może przekroczyć granic systemu plików (co jest moim przypadkiem użycia).
sdaau,
26
Nie możesz na stałe linkować do katalogów, prawda?
Nanne
1
ln source destinationdziała również w OS X. Testowane na El Capitan.
Mahdi Dibaiee,
7
@Nanne nie, ale można to zrobić: cp -al source destination. `-l 'oznacza twarde łącza zamiast kopiowania.
Paolo
6
Niestety nie można na stałe połączyć katalogów ani przekroczyć granic systemu plików. To sprawia, że ​​to rozwiązanie jest dla mnie podwójnie niewykonalne.
Konrad Rudolph
25

Jest to haczyk poprzedzający zatwierdzenie, który zastępuje obiekty BLOB symboliczne w indeksie zawartością tych dowiązań symbolicznych.

Włóż to .git/hooks/pre-commiti zrób to:

#!/bin/sh
# (replace "find ." with "find ./<path>" below, to work with only specific paths)

# (these lines are really all one line, on multiple lines for clarity)
# ...find symlinks which do not dereference to directories...
find . -type l -exec test '!' -d {} ';' -print -exec sh -c \
# ...remove the symlink blob, and add the content diff, to the index/cache
    'git rm --cached "$1"; diff -au /dev/null "$1" | git apply --cached -p1 -' \
# ...and call out to "sh".
    "process_links_to_nondir" {} ';'

# the end

Notatki

Używamy w jak największym stopniu funkcjonalności zgodnej z POSIX; jednak diff -anie jest zgodny z POSIX, być może między innymi.

W tym kodzie mogą występować błędy / błędy, mimo że został on nieco przetestowany.

Abbafei
źródło
4
Wspaniale jest zobaczyć próbę odpowiedzi na pytanie dotyczące plików, a nie katalogów. Zauważ jednak, że powyższe nadal będzie się wyświetlać typechangew git statusprzypadku plików, które w rzeczywistości są dowiązaniami symbolicznymi, chociaż teraz nie są nimi.
David Fraser
1
Dzięki za to; chciałem tylko wiedzieć, co to jest process_links_to_nondir?
sdaau
@ sdaau Jest to nazwa /, argv[0]która jest używana jako nazwa polecenia dla shprocesu. (Trochę mnie to rozgryzło, bo też nie pamiętam, co to było ☺😃)
Abbafei,
3
@Abbafei Czy możesz zmodyfikować skrypt, aby działał na Ubuntu (14.04)? To pokazuje find: missing argument to -exec'. Może być konieczne wykonanie polecenia krok po kroku zamiast pipowania i łączenia wszystkiego w jedną linię.
Khurshid Alam
1
@ KhurshidAlam Dla mnie zadziałało usunięcie skomentowanych linii między wierszami poleceń. Jednak hak nie działa zgodnie z oczekiwaniami (otrzymuję typechangepodobny @DavidFraser, ale połączony plik wydaje się już nie być wystawiany)
Scz
14

Włącz MacOS(mam Mojave / 10.14, gitwersja 2.7.1), użyj bindfs.

brew install bindfs

cd /path/to/git_controlled_dir

mkdir local_copy_dir

bindfs </full/path/to/source_dir> </full/path/to/local_copy_dir>

Wskazały na to inne komentarze, ale nie zostały jasno podane w innych odpowiedziach. Mam nadzieję, że zaoszczędzi to komuś trochę czasu.

ijoseph
źródło
wydaje się świetny dla zespołów, które działają na Mac OS, myślę, że twarde linki opisane poniżej powinny działać w systemie Windows i Linux.
Devin G Rhode,
Było to pomocne i myślę, że najlepsze rozwiązanie dla przydatnej, ale brakującej funkcji w MacOS. Należy jednak pamiętać, że byłem coraz Failed to resolve... No such file or directorybłędów chyba użyłem pełnych nazw ścieżek z bindfspoleceniem.
elektromaggot
Dzięki @electromaggot. Dodano wyjaśnienie, że konieczne są pełne ścieżki
ijoseph
1
Działa świetnie na macos Catalina!
Jerry Green,
13

Od dłuższego czasu dodawałem pliki poza dowiązaniami symbolicznymi. Kiedyś działało dobrze, bez żadnych specjalnych ustaleń. Ponieważ zaktualizowałem do wersji Git 1.6.1, to już nie działa.

Możesz być w stanie przełączyć się na Git 1.6.0, aby to zadziałało. Mam nadzieję, że przyszła wersja Gita będzie miała flagę git-addpozwalającą mu ponownie podążać za dowiązaniami symbolicznymi.

Erik Schnetter
źródło
12

Zmęczyło mnie każde rozwiązanie, które jest przestarzałe lub wymaga rootowania, więc stworzyłem rozwiązanie oparte na LD_PRELOAD (tylko Linux).

Wchodzi w wewnętrzne elementy Gita, zastępując „czy to dowiązanie symboliczne?” funkcja, umożliwiająca traktowanie dowiązań symbolicznych jako ich zawartości. Domyślnie wszystkie linki do zewnętrznych repozytoriów są wstawiane; zobacz link, aby uzyskać szczegółowe informacje.

Alcaro
źródło
Bardzo kreatywne rozwiązanie LD_PRELOADzastępujące funkcje biblioteczne!
iBug
Tak, ale należy to tutaj rozwinąć. Możesz to zrobić?
Peter Mortensen
Nie jestem pewien, ile pomogłoby opracowanie; chyba że skopiuję cały kod źródłowy, ta odpowiedź zawsze będzie polegać na tym linku, w którym można również znaleźć plik readme. Ale tak, myślę, że mógłbym odtworzyć ważne części readme.
Alcaro
Nie kompiluje się w systemie OS X (Mojave 10.14.2). Otrzymaj cztery błędy narzekające na „strchrnul” (miałeś na myśli „strchr”?), A jeden na „__xstat64” (czy miałeś na myśli „__lxstat64”?). Wreszcie otrzymuję błąd „dostęp członka do niekompletnego typu„ dirent64 ””. Zdarza się niezależnie od tego, czy użyję „make”, „make OPT = 1” czy „sh install.sh”.
Erik Veland,
@ErikVeland Próbowałem trochę, ale wygląda na to, że OSX nie obsługuje LD_PRELOAD ani niczego podobnego. Różne dokumenty sugerują różne rzeczy, ale wszystkie mają kilka lat, a Apple uwielbia przestarzałe rzeczy; Nie mogłem zmusić żadnego z nich do pracy. Przepraszam.
Alcaro,
6

W przypadku Git 2.3.2+ (I kwartał 2015 r.) Istnieje jeszcze jeden przypadek, w którym Git nie będzie już podążał za dowiązaniem symbolicznym: patrz commit e0d201b przez Junio ​​C Hamano ( gitster) (główny opiekun Git)

apply: nie dotykaj pliku poza dowiązaniem symbolicznym

Ponieważ Git śledzi dowiązania symboliczne jako dowiązania symboliczne, ścieżka, która ma dowiązanie symboliczne w swojej wiodącej części (np. path/to/dir/fileGdzie path/to/dirjest dowiązanie symboliczne do innego miejsca, czy to wewnątrz czy na zewnątrz działającego drzewa), nigdy nie może pojawić się w poprawnej poprawce , chyba że ta sama poprawka najpierw usunie dowiązanie symboliczne, aby umożliwić utworzenie tam katalogu.

Wykryj i odrzuć taką łatkę.

Podobnie, gdy dane wejściowe tworzą dowiązanie symboliczne, path/to/dira następnie plik path/to/dir/file, musimy oflagować je jako błąd bez faktycznego tworzenia path/to/dirdowiązania symbolicznego w systemie plików.

Zamiast tego w przypadku każdej poprawki na wejściu, która pozostawia ścieżkę (tj. Brak usunięcia) w wyniku, sprawdzamy wszystkie wiodące ścieżki względem wynikowego drzewa, które utworzy łatka, sprawdzając wszystkie łaty na wejściu, a następnie cel poprawki aplikacja (indeks lub drzewo robocze).

W ten sposób:

  • złapać błąd lub pomyłkę, aby jednocześnie dodać symboliczny link path/to/diri plik path/to/dir/file,
  • jednocześnie zezwalając na prawidłową poprawkę, która usuwa symbolikę, link path/to/dira następnie dodaje plik path/to/dir/file.

Oznacza to, że w takim przypadku komunikat o błędzie nie będzie ogólny "%s: patch does not apply", ale bardziej szczegółowy:

affected file '%s' is beyond a symbolic link
VonC
źródło
4

Hmmm, mount --bindnie działa na Darwina.

Czy ktoś ma taką sztuczkę?

[edytowany]

OK, znalazłem odpowiedź na Mac OS X, aby utworzyć hardlink. Tyle że ten interfejs API nie jest lnudostępniany przez , więc musisz użyć własnego małego programu, aby to zrobić. Oto link do tego programu:

Tworzenie twardych linków do katalogów w Mac OS X.

Cieszyć się!

J Chris A.
źródło
1
Jeśli katalog docelowy tego linku twardego jest podkatalogiem innego repozytorium git, byłby to chaos. Wykonanie operacji git w hardlink miałoby zastosowanie do tego drugiego repozytorium git. Po prostu dwukrotnie sprawdź, co robisz.
yegle
4
Można to zrobić za pośrednictwem code.google.com/p/bindfs, który można zainstalować za pomocą portu.
Kit Sunde,
0

Korzystam z Git 1.5.4.3 i podąża za przekazanym dowiązaniem symbolicznym, jeśli ma ukośnik końcowy. Na przykład

# Adds the symlink itself
$ git add symlink

# Follows symlink and adds the denoted directory's contents
$ git add symlink/
Peter Mortensen
źródło
5
przynajmniej w OSX powoduje tofatal: 'src/' is beyond a symbolic link
Dan Rosenstark
2
Jak wyjaśnił @Mark Longair, działało to tylko do gita 1.6.1
MestreLion
to był mój problem, dzięki!
Mike Q
0

Konwersja z dowiązań symbolicznych może być przydatna. Łącze w folderze Git zamiast dowiązania symbolicznego za pomocą skryptu .

Yurij73
źródło
chcesz dodać więcej szczegółów do swojej odpowiedzi?
Devin G Rhode,