Consejos para poner ~ bajo control de fuente

77

Quiero poner mi directorio de inicio (~) bajo control de fuente (git, en este caso), ya que tengo muchos archivos de configuración (.gitconfig, .gitignore, .emacs, etc.) allí me gustaría transportar a través de máquinas, y tenerlos en Git sería bueno para recuperarlos.

Mi máquina principal es mi MacBook, y por la forma en que está configurado OS X, hay muchas carpetas que quiero ignorar (Documentos, Descargas, .ssh). También hay carpetas que ya están usando Git (.emacs.d).

Pensé en agregar todos estos directorios a mi archivo .gitignore, pero eso parece un poco cansado y podría dar lugar a algunas consecuencias imprevistas. Lo siguiente que pensé fue copiar periódicamente los archivos que quiero almacenar en alguna carpeta en casa, y luego confirmar esa carpeta. El problema con eso será que tengo que recordar moverlos antes de comprometerme.

¿Hay una manera limpia de hacer esto?

Dan McClain
fuente
También puede hacer un script haciendo las confirmaciones de las carpetas que desee y llamándolo a través de cronjobs.
Shadok
¡Tenga en cuenta que el sistema de archivos HFS + predeterminado en Mac OS X no distingue entre mayúsculas y minúsculas (pero conserva mayúsculas y minúsculas) y que las rutas de archivos están codificadas en UTF-8 descompuesto canónicamente en el espacio del usuario! Para obtener más información, consulte: <a href=" stackoverflow.com/questions/5581857/… y el problema de Umlaut en Mac OS X</a>

Respuestas:

60

Tengo $HOMEbajo git. La primera línea de mi archivo .gitignore es

/*

El resto son patrones para no ignorar el uso del !modificador. Esta primera línea significa que el valor predeterminado es ignorar todos los archivos en mi directorio de inicio. Esos archivos en los que quiero controlar la versión entran .gitignoreasí:

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

Un patrón más complicado que tengo es:

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

Es decir, solo quiero la versión .ssh/config, no quiero que mis claves y otros archivos en .ssh entren en git. Lo anterior es cómo lo logro.

Editar: Se agregaron barras diagonales al inicio de todas las rutas. Esto hace que los patrones de ignorar coincidan desde la parte superior del repositorio ($ HOME) en lugar de cualquier lugar. Por ejemplo, si !lib/era un patrón (no ignore todo en el directorio lib) y agrega un archivo .gitignore, anteriormente el patrón ( !.gitignore) coincidía con eso. Con la barra inclinada ( !/.gitignore), solo coincidirá .gitignoreen mi directorio de inicio y no en ningún subdirectorio.

No he visto un caso en el que esto haga una diferencia práctica con mi lista de ignorados, pero me parece más técnicamente preciso.

camh
fuente
1
Me parece que lo mismo se puede lograr de una manera mucho más fácil .
Nick Volynkin
24

Lo que hago (con los mismos objetivos) es poner mis archivos de configuración en un subdirectorio ~/liby tienen enlaces simbólicos en mi directorio, por ejemplo, .emacs -> lib/emacs/dot.emacs. Solo guardo los archivos de configuración que escribí explícitamente bajo control de versiones; mi directorio de inicio contiene gran cantidad de archivos de puntos creados automáticamente que no están bajo control de versiones. Por ~/liblo tanto, está bajo control de versiones y mi directorio de inicio no.

Tengo un script que crea los enlaces simbólicos de los archivos debajo ~/lib. Cuando creo una cuenta en una nueva máquina, la relleno revisando ~/liby ejecutando ese script.

Mi experiencia es con CVS, no con git, por lo que no es 100% transferible. Una de las razones por las que no puse mi directorio de inicio directamente bajo CVS es que ~/.cvsignorese aplicaría a todos mis pagos de CVS y no solo a mi directorio de inicio; git no tiene este problema. La desventaja de ese enfoque en comparación con tener el directorio de inicio bajo control de versiones es que no puede usar git statuspara distinguir entre un archivo que ha decidido explícitamente ignorar (que se enumeraría en el archivo de ignorar, por lo que no se muestra) y un archivo sobre el que no tiene opinión (que se mostrará con a ?).

Algunos archivos deben ser diferentes en diferentes máquinas. Los pongo en un directorio llamado ~/Local/SITENAME/liby también creo enlaces simbólicos para ellos o (para los formatos de archivo que lo admiten) tengo una directiva de inclusión en el archivo debajo ~/lib. También tengo un enlace simbólico ~/Here -> ~/Local/SITENAME. Dado que git, a diferencia de CVS, está diseñado para admitir repositorios en su mayoría similares pero no idénticos, puede haber una mejor manera de administrar archivos específicos de la máquina. De hecho, algunos de mis archivos de puntos no son enlaces simbólicos, sino que se generan automáticamente a partir del contenido debajo ~/liby ~/Here.

Gilles
fuente
Quizás tenga core.excludesfile = ~/.gitignore. Sin dicha configuración, el archivo no se aplica a ningún repositorio excepto uno almacenado ~/.git(incluso entonces no se aplicaría a los repositorios secundarios). Uso core.excludesfile = ~/.git-user-excludespara evitar el conflicto entre las exclusiones que quiero aplicar a todos mis repositorios Git (independientemente de la ubicación) y las exclusiones que deseo aplicar al repositorio que contiene (partes de) mi directorio de inicio.
Chris Johnsen
@ Chris: Sé muy poco sobre git. Es posible que haya entendido mal esta oración en la gitignorepágina de manual: "Los patrones leídos de un archivo .gitignore en el mismo directorio que la ruta, o en cualquier directorio padre (...)" De hecho, se detiene en la raíz del pago (es decir, donde el .gitdirectorio es)?
Gilles
1
Sí, la búsqueda ascendente de .gitignorearchivos está limitada por la raíz del árbol de trabajo. La oración que citó continúa: "(hasta el nivel superior del árbol de trabajo)".
Chris Johnsen
@ Chris: mi versión de la página de manual no tiene estas palabras, parece que la redacción ha sido aclarada. He corregido mi respuesta. ¡Gracias!
Gilles
Esto fue discutido recientemente en el chat
strugee 01 de
11

Podemos usar la capacidad de Git para continuar rastreando archivos incluso si están listados .gitignore. Entonces, esto es suficiente para .gitignore:

$ cat .gitignore
/*

Para cada archivo que desee rastrear, ejecute add -f(el -fparámetro anula ignorando tanto en .gitignorecomo .git/info/exclude):

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

Una vez que haya indexado un archivo, Git rastreará todos los cambios a pesar del hecho de que el archivo se ignora. Lo mismo funciona para un directorio, pero solo para los archivos que están realmente presentes:

git add -f somedirname

Si desea realizar un seguimiento de un directorio completo con todos los archivos nuevos que aparecen en él, puede excluirse de .gitignorealguna manera, descrita en la respuesta de camh :

!/somedirname

Si alguna vez quieres dejar de rastrear un archivo, este comando elimina un archivo del índice de Git pero lo deja intacto en el disco duro:

git rm --cached .ssh/config
Nick Volynkin
fuente
1
Te daría mis puntos si pudiera. Debe tenerse en cuenta que este método solo puede usarse para rastrear archivos, no directorios. Si desea que git rastree todos los archivos en un directorio, deberá ignorar ese directorio en .gitignore. De lo contrario, los archivos nuevos en ese directorio no aparecerán como archivos nuevos.
camh
5

Yo uso lo viejo rcspara eso.

Echar un vistazo a las páginas de manual para ci, coy rcs. Esos sitios también deberían ser útiles:

Lo uso para la versión que controla mis archivos de puntos, por ejemplo:

ci -u .*vimrc

Y si quiero editarlos:

co -l .*vimrc

Recomiendo hacer un directorio nombrado RCSen su ~, luego puede hacer una copia de seguridad de ese directorio en algún lugar.

polemon
fuente
2
rcs está bastante anticuado ahora, y git hace todo lo que rcs hace y mucho más además. Solía ​​usar rcs para cualquier cosa local donde no quería la sobrecarga de configurar un repositorio en un servidor, pero ahora me he cambiado completamente a git para ese tipo de uso. Incluso escribí un script que envuelve cvs2git para convertir una jerarquía de directorios existente con archivos rcs en git.
Neil Mayhew
1
Sí, sé que está anticuado. La pregunta era un consejo sobre cómo hacer eso. Le acabo de decir a este tipo cómo lo he estado haciendo durante muchos, muchos años ("fechado", pista, pista). No tenía la intención de ser la única forma razonable de hacerlo.
polemon
5

Compruebo mis archivos de configuración $HOME/.conf/desde un repositorio de BitBucket Mercurial. Un repositorio de GitHub funcionaría igual de bien.

El ~/.confpago contiene archivos de configuración y un script de shell para completar enlaces simbólicos en $HOMEcada archivo ~/.conf. Para los formatos de configuración que apoyan la inclusión ( .bashrc, .inputrc, .vimrc, etc.) incluyo el ~/.confarchivo en lugar de enlace a la misma, por lo que yo puedo hacer cambios locales.

Para algunos archivos de configuración, hago un enlace simbólico a un archivo en mi carpeta de Dropbox y lo comparto a través de Dropbox.

Durante algunos meses intenté mantener el $HOMEcontrol de versiones, pero me cansé de administrar las listas masivas de ignorados, me cansé de verificar los cambios de configuración realizados al ejecutar aplicaciones, y el resultado ni siquiera era algo que quisiera ver en otra computadora. ¿Puede usted imaginar la fijación de los conflictos más ~/.gconfo ~/.config/monitors.xml, o catering vaivén diferentes versiones de las aplicaciones de escritorio?

Me resulta más fácil crear un enlace simbólico o incluir una lista limitada de archivos de configuración que he personalizado personalmente y que quiero compartir entre máquinas como valores predeterminados globales.

Graham
fuente
1

Creo que su segundo presentimiento de tener una carpeta no relacionada bajo control de fuente es buena.

Simplemente agregue 2 scripts de shell allí. Uno para copiar archivos bajo su control ~y el otro para recopilar archivos ~y copiarlos de nuevo en la carpeta controlada por la fuente y confirmar.

Alexander Pogrebnyak
fuente
0

Aquí hay un pequeño script de ruby ​​que uso para configurar una nueva máquina

#!/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
fuente