Posso memorizzare la cartella .git al di fuori dei file che voglio monitorare?


147

Ho un'idea insolita di usare git come sistema di backup. Quindi diciamo che ho una directory ./backup/myfiles e voglio eseguirne il backup 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. Guardando i documenti git, ho provato a fare questo:

$ 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

Puoi vedere il messaggio di errore che ottengo lì. Che cosa sto facendo di sbagliato?


9
Oltre all'idea di backup, questa può essere utilizzata anche per mantenere i "dotfile" (.bashrc, .vimrc, ecc.) Nella home directory mantenendo la cartella .git altrove.
Filippo

6
Risposta più diretta: stackoverflow.com/a/19548676/170352 (sepolto a causa di vecchi voti)
Brandon Bertelsen,

1
Nel caso in cui non si abbia accesso in scrittura o non si desideri apportare modifiche alla directory di lavoro (come aggiungere .git / ecc.), Questa risposta di Leo (seppellita anche da vecchi voti) è la migliore.
KobeJohn,

1
@Philip, a meno che il repository dotfiles non contenga anche sottomoduli Git. Git non supporta i sottomoduli in combinazione con un albero di lavoro esterno.
maxschlepzig,

Risposte:


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

Questo farà quello che vuoi ma ovviamente farà schifo quando dovrai specificarlo con ogni comando git che tu abbia mai usato.

Puoi esportare GIT_WORK_TREE=.e GIT_DIR=../backupGit li prenderà su ogni comando. Tuttavia, ciò ti consentirà di lavorare comodamente in un unico repository per shell.

Preferirei suggerire il collegamento simbolico della directory .git da qualche altra parte o la creazione di un collegamento simbolico alla directory .git dalla directory di backup principale.


1
Puoi archiviare lo stesso senza specificare git-dir e l'albero di lavoro in ogni comando e senza alcun collegamento simbolico. Vedi la mia risposta
niks

Il rovescio della medaglia di un collegamento 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

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

@Jeff: per un compromesso. (Nel suo caso di backup, spazzare via il suo albero di lavoro non è probabilmente una preoccupazione maggiore per lui che spazzare via qualsiasi altra directory (come il repository stesso).)
Sz.

1
Sto usando questo insieme a direnv per i miei appunti. Il mio albero di lavoro si trova in una cartella in Dropbox e la mia cartella git da qualche parte all'esterno. In questo modo posso avere facilmente le mie modifiche su tutti i computer, ma posso comunque controllare cosa è cambiato e impegnarmi solo quando qualcosa di significativo è cambiato. Grazie
Paulo Phagula il

170

Devi solo assicurarti che il repository sappia dove si trova l'albero di lavoro e viceversa.

Per far sapere al repository dove si trova l'albero di lavoro, impostare il valore di configurazione core.worktree. Per far sapere all'albero di lavoro dove si trova la directory git, aggiungi un file chiamato .git (non una cartella!) E aggiungi una riga come

gitdir: /path/to/repo.git

Da git 1.7.5 il comando init ha appreso un'opzione aggiuntiva per questo.

È possibile inizializzare un nuovo repository separato con

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

Questo inizializzerà il repository git nella directory separata e aggiungerà il file .git nella directory corrente, che è la directory di lavoro del nuovo repository.

Precedentemente alla 1.7.5 dovevi usare parametri leggermente diversi e aggiungere tu stesso il file .git.

Per inizializzare un repository separato il seguente comando collega l'albero di lavoro al repository:

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

La tua directory attuale sarà l'albero di lavoro e git utilizzerà il repository su /path/to/repo.git. Il comando init imposterà automaticamente il core.worktreevalore come specificato con il --git-dirparametro.

Puoi anche aggiungere un alias per questo:

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

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

Con le conoscenze di cui sopra, è anche possibile impostare il controllo versione git per una directory di lavoro senza disporre delle autorizzazioni di scrittura. Se si utilizza --git-dirsu ogni comando git o si esegue ogni comando all'interno del repository (anziché nella directory di lavoro), è possibile escludere il file .git e quindi non è necessario creare alcun file all'interno della directory di lavoro. Vedi anche la risposta del Leo


7
Puoi farlo anche in un repository esistente: sposta la cartella .git dove preferisci, aggiungi il file .git per puntare su di esso, quindi puoi continuare a utilizzare il repository come faresti normalmente
joachim,

Si noti che è possibile emettere comandi git solo dalla radice del repository. Andare in sottocartelle lo confonde! (Ciò accade indipendentemente dal fatto che il valore dato per gitdir sia relativo o assoluto.)
joachim,

2
La soluzione per questo è specificare 'core.worktree' nel file di configurazione di git, cioè quello nella cartella in cui punti in .git.
Joachim,

2
Sì, è quello che ho descritto nella mia seconda frase della mia risposta. Il valore di configurazione core.worktreeè ovviamente memorizzato nel file di configurazione della cartella .git, dove punta il file .git.
niks

1
Trovo che quando ho usato queste istruzioni il repository creato è diventato un repository nudo e dà l'errore fatal: core.worktree and core.bare do not make sense. Sembra solo cambiare la configurazione, quindi non è semplice risolverlo.
Steven Lu,

62

L' --separate-git-diropzione per git init(e git clone) può essere usata per realizzare ciò sulla mia versione di git ( 1.7.11.3). L'opzione separa il repository git dall'albero di lavoro e crea un collegamento simbolico git agnostico del filesystem (sotto forma di un file denominato .git) nella radice dell'albero di lavoro. Penso che il risultato sia identico alla risposta di Niks .

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

2
+1 L'uso di un'opzione della riga di comando per initse stesso appare più chiaro e più pulito
goncalopp

in Windows, repo.gitviene creato con il set di attributi hiden. Quindi lo cambio manualmente. Ti capita di sapere se questo è sicuro?
PA.

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

25

Trovo più semplice invertire le directory --work-treee --git-dirusate nella risposta di Niks:

$ 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:

  • Elimina la necessità di disporre di opzioni o .gitfile della riga di comando . Basta operare normalmente dalla radice del repository.
  • Ti consente di eseguire la versione di un file system anche se non lo possiedi. Git scriverà solo nella posizione del repository.

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

È quindi possibile utilizzare il repository read_only_repos/foocome telecomando nei propri repository anche se i file originali non sono sotto controllo della versione.


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 poiché non hai accesso in scrittura ad esso. Tuttavia, l'utilizzo del controllo versione per una directory senza accesso in scrittura ad essa è un buon caso d'uso. :-)
nipoti il

3
Avete capito bene. La chiave sta creando il repository esterno alla directory di lavoro.
Leo,

4
Mi piace: mi permette di usare git nelle directory che sto condividendo con Dropbox, senza che gli altri partecipanti sappiano che git è in uso.
Quentin Stafford-Fraser,

19

È 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 avessi fornito l' --work-treeopzione al momento dell'iniziale, questo avrebbe impostato automaticamente la core.worktreevariabile di configurazione, il che significa che git saprà dove trovare l'albero di lavoro una volta specificata la directory git.

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

Ma puoi impostare questa variabile anche dopo il fatto.

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

Una volta fatto questo, il comando aggiungi dovrebbe funzionare come previsto.

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

Ho scoperto che se prima esegui il cd su ../git_repos/myfiles.git, invece di trovarti nell'albero di lavoro reale, 'git add foo' funzionerà e non devi specificare --git-dir all il tempo.
Steve Folly,

1
È vero, ma penso che molte persone tendano a lavorare nel loro albero di lavoro piuttosto che nei loro archivi. Ovviamente, se stai usando un albero di lavoro distaccato, probabilmente stai facendo qualcosa di "speciale" e potresti usare alcune macro per aiutarti.
CB Bailey,

6

Utilizzare gitall'interno del repository:

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

D'ora in poi, è possibile utilizzare gitall'interno della ./backup/git_repos/myfilesdirectory, senza impostare variabili di ambiente o parametri aggiuntivi.


Questa sembra la risposta migliore, ma ricevo il messaggio warning: core.bare and core.worktree do not make sensesignifica che non ha funzionato?
hazrpg,

1
Continuo a pensare che funzioni, ma si lamenta di essere nudi quando si imposta il campo di lavoro. Ecco perché sto impostando core.barea falsedopo.
To1ne

Ah! Adesso ha più senso. Grazie per quello
hazrpg,

1

È possibile creare uno script "nodgit" (No Dot GIT) con qualcosa del genere

#!/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 "$@"
        fi
      fi
      x=`testdir "$x/.."`
    done

Puoi chiamare nodgit al posto di git e imposterà le variabili necessarie cercando un repository git. Ad esempio, supponiamo di avere un repository (nudo) 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 i set corretti impostati in modo da poter usare semplici comandi git.


0

Supponendo che le tue myfilesdirectory esistano già e abbiano dei contenuti, potresti vivere con questo:

cd ~/backup
git init
git add myfiles

La .gitdirectory sarà in backup, non in myfiles.


Sebbene ciò risolverà in qualche modo quello che voglio, preferirei semplicemente archiviare la cartella myfiles sotto git e nient'altro.
Rory,

Puoi mantenere una selezione dei file che vuoi gitmonitorare usando il .gitignorefile. Se lo aggiungi *e !myfilesad esso, verrà tracciata solo quella directory. Ma se desideri un repository separato per un'altra directory, avresti un problema ...
To1ne,

0

Creo 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 "$@"

exit $?

È ridondante usare --git_dir = $ GIT_DIR, ma mi ricorda che posso anche impostare variabili d'ambiente al di fuori dello script.

L'esempio sopra è per tenere traccia delle modifiche locali ai file di sistema di Cygwin.

Posso creare uno di questi script per qualsiasi progetto importante che ne abbia bisogno, ma il mio uso principale è / senza /.git.

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

Se lo faccio abbastanza spesso, ripristinerei l'area di lavoro per la mappatura del repository di

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

la cui controparte moderna più vicina sono i mapping o le viste di Perforce , che supportano i checkout parziali e la non colocation dell'area di lavoro e dei repository.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.