2009-02-02 5 views
118

Ho un'idea insolita di utilizzare git come sistema di backup. Diciamo che ho una directory ./backup/myfiles e voglio confermarlo usando git. Per mantenere le cose pulite non voglio avere una directory .git nella cartella myfiles, quindi ho pensato di poter creare ./backup/git_repos/myfiles. Da un'occhiata ai documenti git, ho provato a fare questo:Posso memorizzare la cartella .git al di fuori dei file che voglio monitorare?

$ cd backup/myfiles 
$ mkdir ../git_repos/myfiles 
$ git --git-dir=../git_repos/myfiles init 
Initialized empty Git repository in backup/git_repos/myfiles/ 
$ git --git-dir="../git_repos/myfiles/" add foo 
fatal: pathspec 'foo' did not match any files 

È possibile visualizzare il messaggio di errore che arrivo. Che cosa sto facendo di sbagliato?

+7

Così come la tua idea di backup, questo può anche essere usato per mantenere i tuoi "dotfile" (.bashrc, .vimrc, ecc.) Nella directory home mantenendo la cartella .git altrove. – Philip

+6

La risposta più semplice: http://stackoverflow.com/a/19548676/170352 (sepolto a causa di vecchi upvotes) –

+1

Nel caso in cui non si abbia accesso in scrittura o non si voglia apportare alcuna modifica alla directory di lavoro (come l'aggiunta .git/ecc.), [questo] (http://stackoverflow.com/a/26746068/377366) la risposta in basso di Leo (anche se sepolta da vecchi upvotes) è la migliore. – KobeJohn

risposta

83
git --git-dir=../repo --work-tree=. add foo 

Questo farà quello che vuoi, ma ovviamente succhiare quando si deve specificare con tutti i comandi git mai utilizzate.

È possibile esportare GIT_WORK_TREE=. e GIT_DIR=../backup e Git li preleva a ogni comando. Tuttavia, questo ti permetterà di lavorare in un solo repository per shell.

Preferisco suggerire il collegamento simbolico della directory .git a un'altra parte oppure la creazione di un collegamento simbolico alla directory .git dalla directory di backup principale.

+0

È possibile archiviare lo stesso senza specificare git-dir e l'albero di lavoro in ogni comando e senza collegamenti simbolici. Vedi la mia risposta. – niks

+0

Lo svantaggio di un link simbolico è che esiste all'interno dell'albero di lavoro e se qualche altro processo cancella l'albero di lavoro, allora hai perso il collegamento simbolico – Jeff

+0

Inoltre, se l'OP non voleva una sottodirectory .git nel suo albero di lavoro perché dovrebbe voler un link simbolico? – Jeff

1

Assumendo che il myfiles directory già esiste e ha alcuni contenuti, si potrebbe vivere con questo:

cd ~/backup 
git init 
git add myfiles 

La directory .git sarà in backup, non in myfiles.

+0

Anche se questo potrebbe risolvere quello che voglio, preferisco semplicemente archiviare la cartella myfiles sotto git e nient'altro. – Rory

+0

Puoi mantenere una selezione dei file che vuoi 'git' tracciare usando il file' .gitignore'. Se dovessi aggiungere '*' e '! Myfiles' ad esso, solo quella directory verrà tracciata. Ma se si desidera un repository separato per un'altra directory, si avrebbe un problema ... – To1ne

18

È convenzionale nominare una directory che è un repository git che ha il suo albero di lavoro in un posto insolito con un'estensione ".git", proprio come un repository nudo.

mkdir ../git_repos/myfiles.git 

Se si aveva fornito l'opzione --work-tree al momento init allora questo sarebbe impostare automaticamente la variabile core.worktree configurazione che significa che git saprà dove trovare l'albero di lavoro una volta che si specifica la directory git.

git --git-dir=../git_repos/myfiles.git --work-tree=. init 

Ma è possibile impostare questa variabile anche dopo il fatto.

git --git-dir=../git_repos/myfiles.git config core.worktree "$(pwd)" 

Una volta fatto, il comando add dovrebbe funzionare come previsto.

git --git-dir=../git_repos/myfiles.git add foo 
+0

Ho trovato se si cd per ../git_repos/myfiles.git per prima cosa, invece di essere nel vero albero di lavoro, 'git add foo' funzionerà e non è necessario specificare --git-dir tutto il tempo. –

+1

È vero, ma penso che molte persone tendano a lavorare nella loro struttura di lavoro piuttosto che nei loro repository. Ovviamente, se si sta utilizzando un albero di lavoro distaccato, probabilmente si sta facendo qualcosa di "speciale" e potrebbe essere utile utilizzare alcune macro. –

1

Si potrebbe creare un "nodgit" Script (No Dot GIT) con Somet come

#!/bin/sh 
gits=/usr/local/gits 
    x=`pwd` 
    testdir() {(cd $1; pwd;)} 
    while [ "$x" != "/" ]; do 
     y=`echo $x|sed -e "s/\//__/g"` 
     if ([ -d "$gits/$y" ]); then 
     export GIT_DIR="$gits/$y" 
     export GIT_WORK_TREE="$x" 
     if ([ "$1" = "nodinit" ]); then 
      mkdir -p "$GIT_DIR" 
      git init --bare; exit $? 
     elif ([ "$1" = "shell" ]); then 
      bash; exit $? 
     else 
      exec git "[email protected]" 
     fi 
     fi 
     x=`testdir "$x/.."` 
    done 

È possibile chiamare nodgit al posto di git e sarà impostare le variabili in base alla necessità, cercando per un git pronti contro termine. Ad esempio, si supponga di avere un repository (bare) in/usr/local/gits/__ home__foo_wibbles e ci si trova in/home/foo/wibbles/one, quindi troverà la directory di lavoro corretta (/ home/foo/wibbles) e repo .

Oh puoi anche usare "nodgit shell" per ottenere una shell con il set vars corretto in modo da poter usare semplici comandi git vecchi.

4

Usa git all'interno del pronti contro termine:

cd ./backup/git_repos/myfiles 
git init --bare 
git config core.worktree ../myfiles 
git config core.bare false 

Da ora in poi, è possibile utilizzare git all'interno della directory ./backup/git_repos/myfiles, senza impostare le variabili di ambiente o parametri aggiuntivi.

152

È sufficiente assicurarsi che il repository sappia dove si trova l'albero di lavoro e viceversa.

Per consentire al repository di sapere dove si trova l'albero di lavoro, impostare il valore di configurazione core.worktree. Per consentire l'albero di lavoro sa dove è directory git è, aggiungere un file chiamato .git (non una cartella!) E aggiungere una linea come

gitdir: /path/to/repo.git 

Dal git 1.7.5 il comando init imparato un'opzione in più per Questo.

È possibile inizializzare un nuovo repository separato con

git init --separate-git-dir /path/to/repo.git 

Questa sarà inizializzare il repository git nella directory separata e aggiungere il file .git nella directory corrente, che è la directory di lavoro del nuovo repository .

Precedentemente a 1.7.5 si dovevano utilizzare parametri leggermente diversi e aggiungere il file .git da soli.

per inizializzare un repository separata i seguenti collegamenti di comando il lavoro-albero con il repository:

git --git-dir=/path/to/repo.git --work-tree=. init && echo "gitdir: /path/to/repo.git" > .git 

La directory corrente sarà l'albero di lavoro e git utilizzerà il repository a /path/to/repo.git. Il comando init imposterà automaticamente il valore core.worktree come specificato con il parametro --git-dir.

Si potrebbe anche aggiungere un alias per questo:

[alias] 
    initexternal = !"f() { git --work-tree=. --git-dir=\"$1\" init && echo \"gitdir: $1\" >> .git; }; f" 

Usa controllo di versione git su una directory di sola lettura di lavoro

Con le conoscenze di cui sopra, è possibile anche impostare il controllo della versione Git per una directory di lavoro senza autorizzazioni di scrittura. Se si utilizza --git-dir su ogni comando git o si esegue ogni comando dall'interno del repository (anziché la directory di lavoro), è possibile escludere il file .git e quindi non è necessario creare alcun file all'interno della directory di lavoro. Vedere anche Leos answer

+6

Puoi farlo anche con un repository esistente: sposta la cartella .git dove vuoi, aggiungi il file .git per puntarlo, e poi puoi continuare a utilizzare il repository come faresti normalmente con – joachim

+0

può emettere solo comandi git dalla radice del repository. Entrare nelle sottocartelle lo confonde! (Questo accade indipendentemente dal fatto che il valore dato per gitdir sia relativo o assoluto.) – joachim

+2

La correzione per questo è specificare 'core.worktree' nel file di configurazione git attuale, cioè quello nella cartella in cui si punta in .git. – joachim

55

L'opzione --separate-git-dir per git init (e git clone) può essere utilizzato per raggiungere questo obiettivo sulla mia versione di git (1.7.11.3). L'opzione separa il repository git dall'albero di lavoro e crea un link simbolico agitativo git del filesystem (nella forma di un file denominato .git) nella radice dell'albero di lavoro. Penso che il risultato sia identico a niks' answer.

git init --separate-git-dir path/to/repo.git path/to/worktree 
+2

+1 L'uso di un'opzione da riga di comando per' init' sembra più chiara e pulita – goncalopp

+0

in windows, 'repo.git' viene creato con il suo set di attributi hiden. Quindi lo cambio manualmente. Ti capita di sapere se questo è sicuro? –

+0

+1 Sì git ha appoggiato questa opzione della riga di comando nella versione 1.7.5, che non era disponibile al momento (se ricordo bene). Ho aggiornato la mia risposta per suggerire di utilizzare questo parametro. – niks

20

Trovo più semplice per invertire i --work-tree e --git-dir directory utilizzate in niks' answer:

$ cd read_only_repos 
$ git --work-tree=/some/readonly/location/foo/ --git-dir=foo init 
$ cd foo 
$ git status 
On branch master 

Initial commit 

Untracked files: 
    (use "git add <file>..." to include in what will be committed) 

     .file_foo 
     bar 
     ... 

Questo approccio ha due vantaggi:

  • Si elimina la necessità di avere alcuna riga di comando opzioni o file .git. Si opera normalmente dalla radice del repository.
  • Consente di eseguire la versione di un file system anche se non la si possiede. Git scriverà solo nella posizione del repository.

L'unica avvertenza che ho riscontrato è che invece di utilizzare un file .gitignore, si modifica info/exclude.

È quindi possibile utilizzare il repository read_only_repos/foo come remoto nei propri repository anche se i file originali non sono sotto controllo di versione.

+0

Bene, questo è esattamente lo stesso comando. L'unica differenza che vedo è che hai scambiato l'ordine degli argomenti --work-tree e --git-dir. E ovviamente non crei il file .git nella directory di lavoro perché non hai accesso in scrittura. Tuttavia, l'utilizzo del controllo di versione per una directory senza accesso in scrittura è un caso utile. :-) – niks

+2

Hai capito. La chiave sta creando il repository al di fuori della directory di lavoro. – Leo

+2

Mi piace - mi permette di usare git sulle directory che sto condividendo con Dropbox, senza che gli altri partecipanti sappiano che git è in uso. –

0

ho creare script che sembrano

~/bin/git-slash:

#!/usr/bin/sh 

export GIT_DIR=/home/Version-Control/cygwin-root.git/ 
export GIT_WORK_TREE=/ 

git --git-dir=$GIT_DIR --work-tree=$GIT_WORK_TREE "[email protected]" 

exit $? 

E 'superfluo utilizzare --git_dir = $ GIT_DIR, ma mi ricorda che io posso anche impostare le variabili d'ambiente al di fuori della sceneggiatura.

L'esempio precedente è per il monitoraggio delle modifiche locali ai file di sistema cygwin.

È possibile creare uno script simile per qualsiasi progetto principale che necessita di questo - ma/senza /.git è il mio uso principale.

Quanto sopra è abbastanza piccolo da rendere un alias o una funzione di shell, se si elimina la ridondanza.

Se faccio questo abbastanza spesso, mi farebbe rivivere l'area di lavoro al repository mappatura delle

"Boxes, Links, and Parallel Trees: Elements of a Configuration Management System", 
in Workshop Proceedings of the Software Management Conference. 1989. 

cui controparte moderna più vicina è Perforce mappings or views, sostenendo le estrazioni parziali così come non colocation di spazio di lavoro e pronti contro termine.