Wskazówki dotyczące poddawania ~ kontroli źródła

77

Chcę umieścić mój katalog domowy (~) pod kontrolą źródła (w tym przypadku git), ponieważ mam tam wiele plików ustawień (.gitconfig, .gitignore, .emacs itp.), Które chciałbym przenosić między komputerami, a posiadanie ich w Git ułatwiłoby ich odzyskanie.

Moim głównym komputerem jest mój MacBook, a sposób, w jaki skonfigurowany jest system OS X, istnieje wiele folderów, które chcę zignorować (Dokumenty, Pobrane, .ssh). Istnieją również foldery, które już korzystają z Git (.emacs.d).

Myślałem, aby po prostu dodać wszystkie te katalogi do mojego pliku .gitignore, ale wydaje się to dość męczące i może potencjalnie prowadzić do nieprzewidzianych konsekwencji. Moją kolejną myślą było okresowe kopiowanie plików, które chcę przechowywać do jakiegoś folderu w domu, a następnie zatwierdzanie tego folderu. Problem w tym, że muszę pamiętać o ich przeniesieniu przed popełnieniem.

Czy jest na to czysty sposób?

Dan McClain
źródło
Możesz także utworzyć skrypt wykonujący zatwierdzenia wybranych folderów i wywołujący go za pomocą cronjobs.
Shadok
Pamiętaj, że domyślny system plików HFS + w systemie Mac OS X nie rozróżnia wielkości liter (ale zachowuje wielkość liter), a ścieżki plików są zakodowane w kanonicznie rozłożonym UTF-8 w przestrzeni użytkownika! Aby uzyskać więcej informacji, zobacz: <a href=" stackoverflow.com/questions/5581857/... i problem Umlaut w systemie Mac OS X</a>

Odpowiedzi:

60

Mam $HOMEniedopałek. Pierwszy wiersz mojego pliku .gitignore to

/*

Reszta to wzorce, których nie należy ignorować za pomocą !modyfikatora. Ten pierwszy wiersz oznacza, że ​​domyślnie ignorowane są wszystkie pliki w moim katalogu domowym. Pliki, które chcę kontrolować wersję, .gitignorewyglądają następująco:

!/.gitignore
!/.profile
[...]

Mam trudniejszy wzór:

!/.ssh
/.ssh/*
!/.ssh/config

To znaczy, chcę tylko wersji .ssh/config- nie chcę, aby moje klucze i inne pliki w .ssh przechodziły do ​​git. Powyżej jest, jak to osiągnąć.

Edycja: Dodano ukośniki na początku wszystkich ścieżek. To sprawia, że ​​wzorce ignorowania są dopasowane z góry repozytorium ($ HOME) zamiast z dowolnego miejsca. Na przykład, jeśli !lib/był wzorcem (nie ignoruj ​​wszystkiego w katalogu lib) i dodajesz plik .gitignore, wcześniej wzorzec ( !.gitignore) pasował do tego. Z wiodącym ukośnikiem ( !/.gitignore) będzie pasować tylko .gitignorew moim katalogu domowym, a nie w żadnym podkatalogu.

Nie widziałem przypadku, w którym ma to praktyczny wpływ na moją listę ignorowanych, ale wydaje mi się, że jest dokładniejsza technicznie.

camh
źródło
1
Wydaje mi się, że to samo można osiągnąć w znacznie łatwiejszy sposób .
Nick Volynkin,
24

To, co robię (z tymi samymi celami), to umieścić moje pliki konfiguracyjne w podkatalogu ~/libi mieć dowiązania symboliczne w moim katalogu domowym, np .emacs -> lib/emacs/dot.emacs. Trzymam tylko pliki konfiguracyjne, które napisałem jawnie, pod kontrolą wersji; mój katalog domowy zawiera wiele automatycznie tworzonych plików kropek, które nie są pod kontrolą wersji. Zatem ~/libjest pod kontrolą wersji, a mój katalog domowy nie.

Mam skrypt, który tworzy dowiązania symboliczne z plików poniżej ~/lib. Kiedy tworzę konto na nowym komputerze, zapełniam je, sprawdzając ~/libi uruchamiając ten skrypt.

Moje doświadczenie dotyczy CVS, a nie git, więc nie można go w 100% przenieść. Jednym z powodów, dla których nie umieściłem mojego katalogu domowego bezpośrednio w CVS, jest to, ~/.cvsignoreże dotyczyłoby wszystkich moich kas CVS, a nie tylko mojego katalogu domowego; git nie ma tego problemu. Minusem tego podejścia w porównaniu z kontrolowaniem wersji katalogu głównego jest to, że nie można użyć git statusdo rozróżnienia pliku, który jawnie postanowiono zignorować (który byłby wymieniony w pliku ignorowania, więc nie jest wyświetlany) i plik, o którym nie masz zdania (który byłby wyświetlany za pomocą a ?).

Niektóre pliki muszą się różnić na różnych komputerach. Umieszczam je w katalogu o nazwie ~/Local/SITENAME/libi albo tworzę dla nich dowiązania symboliczne, albo (dla formatów plików, które go obsługują) zawierają dyrektywę dołączania w pliku poniżej ~/lib. Mam również dowiązanie symboliczne ~/Here -> ~/Local/SITENAME. Ponieważ git, w przeciwieństwie do CVS, jest zaprojektowany do obsługi głównie podobnych, ale nie identycznych repozytoriów, może istnieć lepszy sposób zarządzania plikami specyficznymi dla komputera. Niektóre z moich plików kropek nie są w rzeczywistości symbolicznymi linkami, ale są automatycznie generowane z treści pod ~/libi ~/Here.

Gilles
źródło
Może masz core.excludesfile = ~/.gitignore. Bez takiej konfiguracji plik nie zostanie zastosowany do żadnego repozytorium oprócz jednego w nim przechowywanego ~/.git(nawet wtedy nie będzie miał zastosowania do repozytoriów). Używam core.excludesfile =, ~/.git-user-excludesaby uniknąć konfliktu między wykluczeniami, które chcę zastosować do wszystkich moich repozytoriów Git (niezależnie od lokalizacji), a wykluczeniami, które chcę zastosować do repozytorium, które zawiera (części) mojego katalogu domowego.
Chris Johnsen,
@Chris: Wiem bardzo mało o git. Być może źle zrozumiałem to zdanie na gitignorestronie podręcznika : „Wzorce odczytane z pliku .gitignore w tym samym katalogu co ścieżka lub w dowolnym katalogu nadrzędnym (…)” Czy w rzeczywistości zatrzymuje się w katalogu głównym kasy (tzn. Gdzie .gitkatalog jest)?
Gilles
1
Tak, wyszukiwanie .gitignoreplików w górę jest ograniczone przez katalog główny działającego drzewa. Cytowane zdanie trwa: „(do najwyższego poziomu drzewa roboczego)”.
Chris Johnsen,
@Chris: moja wersja strony man nie zawiera tych słów - wygląda na to, że zostało to wyjaśnione. Poprawiłem swoją odpowiedź. Dzięki!
Gilles
zostało to omówione ostatnio na czacie
strugee
11

Możemy użyć zdolności Gita do kontynuowania śledzenia plików, nawet jeśli są one wymienione na liście .gitignore. To wystarczy, aby .gitignore:

$ cat .gitignore
/*

Dla każdego pliku, który chcesz śledzić, uruchom add -f( -fparametr zastępuje ignorowanie zarówno w, jak .gitignorei .git/info/exclude):

git add -f .gitignore
git add -f .profile
git add -f .zshrc
git add -f .ssh/config

Po zaindeksowaniu pliku Git będzie śledził wszystkie zmiany, mimo że plik jest ignorowany. To samo działa dla katalogu, ale tylko dla plików, które są faktycznie obecne:

git add -f somedirname

Jeśli chcesz śledzić cały katalog ze wszystkimi nowymi plikami, które się w nim pojawiają, możesz go wyłączyć .gitignorew sposób opisany w odpowiedzi przez camh :

!/somedirname

Jeśli kiedykolwiek chcesz przestać śledzić plik, te polecenia usuwają plik z indeksu Gita, ale pozostawiają go nietkniętym na dysku twardym:

git rm --cached .ssh/config
Nick Volynkin
źródło
1
Dałbym ci moje punkty, gdybym mógł. Należy zauważyć, że ta metoda może być używana tylko do śledzenia plików, a nie katalogów. Jeśli chcesz, aby git śledził wszystkie pliki w katalogu, nadal musisz zignorować ten katalog w .gitignore. W przeciwnym razie nowe pliki w tym katalogu nie pojawią się jako nowe pliki.
camh
5

Używam do tego starego rcs.

Zapraszamy do obejrzenia strony podręcznika dla ci, coi rcs. Te strony również powinny być pomocne:

Używam tego do wersji kontrolującej moje pliki dot, na przykład:

ci -u .*vimrc

A jeśli chcę je edytować:

co -l .*vimrc

Polecam dokonanie katalog o nazwie RCSIn Your ~można następnie łatwo kopii zapasowej katalogu gdzieś.

polemon
źródło
2
rcs jest już dość przestarzałe, a git robi wszystko, co robi rcs i wiele więcej. Kiedyś używałem rcs do wszystkiego lokalnego, gdzie nie chciałem narzutu związanego z konfigurowaniem repozytorium na serwerze, ale teraz całkowicie przełączyłem się na git dla tego rodzaju użycia. Napisałem nawet skrypt, który otacza cvs2git, aby przekonwertować istniejącą hierarchię katalogów z plikami rcs na git.
Neil Mayhew,
1
Tak, wiem, że jest przestarzały. Pytanie dotyczyło porady, jak to zrobić. Właśnie powiedziałem temu facetowi, jak to robię przez wiele, wiele lat („randka”, podpowiedź, podpowiedź). Nie miało to oznaczać, że jest to jedyny rozsądny sposób na zrobienie tego.
polemon
5

Sprawdzam moje pliki konfiguracyjne $HOME/.conf/z repozytorium BitBucket Mercurial. Repozytorium GitHub równie dobrze działałoby.

~/.confZamówienie zawiera pliki konfiguracyjne i skrypt do wypełnienia w dowiązania $HOMEdo każdego pliku ~/.conf. Dla formatów konfiguracyjnych, które wspierają integrację ( .bashrc, .inputrc, .vimrc, itd.) I obejmują ~/.confpliku zamiast link do niego tak, że mogę zrobić przesłonięcia lokalne.

W przypadku niektórych plików konfiguracyjnych symbolizuję dowiązanie do pliku w folderze Dropbox i udostępniam przez Dropbox.

Przez kilka miesięcy próbowałem zachować $HOMEkontrolę nad wersjami, ale zmęczyło mnie zarządzanie ogromnymi listami ignorowania, zmęczenie sprawdzaniem zmian konfiguracji dokonanych przez uruchamianie aplikacji, a wynik nie był nawet czymś, co chciałbym sprawdzić na innym komputerze. Czy potrafisz sobie wyobrazić rozwiązywanie konfliktów ~/.gconflub obsługę ~/.config/monitors.xmlróżnych wersji aplikacji komputerowych?

Łatwiej jest mi utworzyć dowiązanie symboliczne lub dołączyć ograniczoną listę plików konfiguracyjnych, które osobiście dostosowałem i które chcę udostępniać na różnych komputerach jako globalne ustawienia domyślne.

Graham
źródło
3

Właśnie zacząłem używać następującego skryptu Python Dotfiles, który jest przydatnym narzędziem, które automatycznie łączy pliki za ciebie: https://pypi.python.org/pypi/dotfiles

Trojjer
źródło
1

Myślę, że twoje drugie przeczucie, że folder niepowiązany jest pod kontrolą źródła jest dobre.

Po prostu dodaj tam 2 skrypty powłoki. Jeden do kopiowania plików pod twoją kontrolą, ~a drugi do zbierania plików ~i kopiowania go z powrotem do folderu kontrolowanego przez źródło i zatwierdzania.

Alexander Pogrebnyak
źródło
0

Oto mały skrypt ruby, którego używam do konfiguracji nowej maszyny

#!/usr/bin/env ruby
# setup.rb

#list of dirs which you don't want to symlink
ignored = %w(.gitignore .gitmodules misc setup.rb readme)

current_dir = File.expand_path(Dir.pwd)
home_dir = File.expand_path("~")

links = `git ls-tree --name-only HEAD`.lines.map(&:strip).select {|x| !ignored.include?(x)  }

links.each do |link|
  link = File.join(current_dir, link)
  symlink = File.join(home_dir, File.basename(link))
  `ln -ns #{link} #{symlink}`
end
Khaja Minhajuddin
źródło