Kann ich den .git-Ordner außerhalb der Dateien speichern, die ich verfolgen möchte?

147

Ich habe eine ungewöhnliche Idee, Git als Backup-System zu verwenden. Nehmen wir also an, ich habe ein Verzeichnis ./backup/myfiles und möchte dieses mit git sichern. Um die Dinge sauber zu halten, möchte ich kein .git-Verzeichnis im Ordner myfiles haben, also dachte ich, ich könnte ./backup/git_repos/myfiles erstellen. Beim Betrachten der Git-Dokumente habe ich Folgendes versucht:

$ 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

Sie können die Fehlermeldung sehen, die ich dort erhalte. Was mache ich falsch?

Rory
quelle
9
Neben Ihrer Sicherungsidee können Sie damit auch Ihre "Punktedateien" (.bashrc, .vimrc usw.) im Ausgangsverzeichnis aufbewahren, während Sie den Ordner .git an anderer Stelle aufbewahren.
Philip
6
Die direkteste Antwort: stackoverflow.com/a/19548676/170352 (begraben wegen alter Gegenstimmen)
Brandon Bertelsen
1
Für den Fall, dass Sie keinen Schreibzugriff haben oder keine Änderungen am Arbeitsverzeichnis vornehmen möchten (wie das Hinzufügen von .git / usw.), ist diese Antwort von Leo (auch durch alte Upvotes begraben) die beste.
KobeJohn
1
@Philip, es sei denn, Ihr Dotfiles-Repository enthält auch Git-Submodule. Git unterstützt keine Submodule in Kombination mit einem externen Arbeitsbaum.
Maxschlepzig

Antworten:

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

Dies wird tun, was Sie wollen, wird aber offensichtlich scheiße sein, wenn Sie es mit jedem Git-Befehl angeben müssen, den Sie jemals verwenden.

Sie können exportieren GIT_WORK_TREE=.und GIT_DIR=../backupGit holt sie bei jedem Befehl ab. Dadurch können Sie jedoch nur bequem in einem einzigen Repository pro Shell arbeiten.

Ich würde eher vorschlagen, das .git-Verzeichnis mit einem anderen Ort zu verknüpfen oder einen Symlink mit dem .git-Verzeichnis aus Ihrem Hauptsicherungsverzeichnis zu erstellen.

Bombe
quelle
1
Sie können dasselbe archivieren, ohne das Git-Verzeichnis und den Arbeitsbaum in jedem Befehl anzugeben und ohne symbolische Verknüpfungen. Siehe meine Antwort.
Niks
Der Nachteil eines Symlinks ist, dass er im Arbeitsbaum vorhanden ist. Wenn ein anderer Prozess den Arbeitsbaum löscht, haben Sie den Symlink verloren
Jeff
Wenn das OP kein .git-Unterverzeichnis in seinem Arbeitsbaum haben wollte, warum sollte er dann einen Symlink wollen?
Jeff
@ Jeff: für einen Kompromiss. (In seinem Backup-Fall ist das Löschen seines Arbeitsbaums für ihn wahrscheinlich kein größeres Problem als das Löschen eines anderen Verzeichnisses (wie das Repo selbst).)
Sz.
1
Ich benutze dies zusammen mit direnv für meine Notizen. Mein Arbeitsbaum befindet sich in einem Ordner in Dropbox und mein Git-Ordner irgendwo außerhalb. Auf diese Weise kann ich meine Änderungen problemlos auf allen Computern vornehmen, aber trotzdem überprüfen, was sich geändert hat, und nur dann festschreiben, wenn sich etwas Wesentliches geändert hat. Danke
Paulo Phagula
170

Sie müssen nur sicherstellen, dass das Repository weiß, wo sich der Arbeitsbaum befindet und umgekehrt.

Legen Sie den Konfigurationswert fest, damit das Repository weiß, wo sich der Arbeitsbaum befindet core.worktree. Fügen Sie eine Datei mit dem Namen .git (kein Ordner!) Und eine Zeile wie hinzu, um dem Arbeitsbaum mitzuteilen, wo sich das Git-Verzeichnis befindet

gitdir: /path/to/repo.git

Seit git 1.7.5 hat der Befehl init eine zusätzliche Option dafür gelernt.

Sie können ein neues separates Repository mit initialisieren

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

Dadurch wird das Git-Repository im separaten Verzeichnis initialisiert und die Git-Datei im aktuellen Verzeichnis hinzugefügt, das das Arbeitsverzeichnis des neuen Repositorys ist.

Vor 1.7.5 mussten Sie leicht unterschiedliche Parameter verwenden und die .git-Datei selbst hinzufügen.

Um ein separates Repository zu initialisieren, verknüpft der folgende Befehl den Arbeitsbaum mit dem Repository:

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

Ihr aktuelles Verzeichnis ist der Arbeitsbaum und Git verwendet das Repository unter /path/to/repo.git. Der Befehl init setzt automatisch den core.worktreemit dem --git-dirParameter angegebenen Wert .

Sie können sogar einen Alias ​​hinzufügen:

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

Verwenden Sie die Git-Versionskontrolle für ein schreibgeschütztes Arbeitsverzeichnis

Mit den oben genannten Kenntnissen können Sie sogar die Git-Versionskontrolle für ein Arbeitsverzeichnis einrichten, ohne über Schreibberechtigungen zu verfügen. Wenn Sie entweder --git-dirfür jeden git-Befehl verwenden oder jeden Befehl aus dem Repository (anstelle des Arbeitsverzeichnisses) ausführen, können Sie die .git-Datei weglassen und müssen daher keine Dateien im Arbeitsverzeichnis erstellen. Siehe auch Leos Antwort

Niks
quelle
7
Sie können dies auch für ein vorhandenes Repo tun: Verschieben Sie den .git-Ordner an einen beliebigen Ort, fügen Sie die .git-Datei hinzu, um darauf zu verweisen, und verwenden Sie das Repo dann wie
gewohnt weiter
Beachten Sie, dass Sie Git-Befehle nur über das Stammverzeichnis Ihres Repos ausgeben können. In Unterordner zu gehen verwirrt es! (Dies geschieht unabhängig davon, ob der angegebene Wert für gitdir relativ oder absolut ist.)
Joachim
2
Die Lösung hierfür besteht darin, 'core.worktree' in der eigentlichen Git-Konfigurationsdatei anzugeben, dh in dem Ordner, auf den Sie in .git verweisen.
Joachim
2
Ja, das habe ich in meinem zweiten Satz meiner Antwort beschrieben. Der Konfigurationswert core.worktreewird natürlich in der Konfigurationsdatei des .git-Ordners gespeichert, auf die die .git-Datei verweist.
Niks
1
Ich finde, als ich diese Anweisungen verwendet habe, wurde das Repo, das erstellt wurde, zu einem nackten Repository und es gibt den Fehler fatal: core.worktree and core.bare do not make sense. Scheint, als würde man nur die Konfiguration ändern, damit es nicht einfach ist, das zu beheben.
Steven Lu
62

Die --separate-git-dirOption für git init(und git clone) kann verwendet werden, um dies in meiner Version von git ( 1.7.11.3) zu erreichen. Die Option trennt das Git-Repository vom Arbeitsbaum und erstellt .gitim Stammverzeichnis des Arbeitsbaums einen dateisystemunabhängigen symbolischen Git-Link (in Form einer Datei mit dem Namen ). Ich denke, das Ergebnis ist identisch mit der Antwort von Niks .

git init --separate-git-dir path/to/repo.git path/to/worktree
Friteuse
quelle
2
+1 Die Verwendung einer Befehlszeilenoption für sich initselbst sieht klarer und sauberer aus
Goncalopp
wird in Windows repo.gitmit dem Attribut hiden erstellt. Ich ändere es dann manuell. Wissen Sie zufällig, ob dies sicher ist?
PA.
+1 Ja, Git hat diese Befehlszeilenoption in Version 1.7.5 übernommen, die damals nicht verfügbar war (wenn ich mich recht erinnere). Ich habe meine Antwort aktualisiert, um die Verwendung dieses Parameters vorzuschlagen.
Niks
25

Ich finde es einfacher, die in der Antwort von niks verwendeten Verzeichnisse --work-treeund umzukehren :--git-dir

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

Dieser Ansatz hat zwei Vorteile:

  • Es werden keine Befehlszeilenoptionen oder .git-dateien mehr benötigt. Sie arbeiten einfach normal im Stammverzeichnis des Repositorys.
  • Sie können ein Dateisystem auch dann versionieren, wenn Sie es nicht besitzen. Git schreibt nur in den Repository-Speicherort.

Die einzige Einschränkung, auf die ich gestoßen bin, ist, dass Sie anstelle der Verwendung einer .gitignoreDatei bearbeiten info/exclude.

Sie können das Repository dann read_only_repos/fooals Remote in Ihren eigenen Repositorys verwenden, auch wenn die Originaldateien nicht der Versionskontrolle unterliegen.

Löwe
quelle
Nun, das ist genau der gleiche Befehl. Der einzige Unterschied, den ich sehe, ist, dass Sie die Reihenfolge der Argumente --work-tree und --git-dir vertauscht haben. Und natürlich erstellen Sie die .git-Datei nicht im Arbeitsverzeichnis, da Sie keinen Schreibzugriff darauf haben. Trotzdem ist die Verwendung der Versionskontrolle für ein Verzeichnis ohne Schreibzugriff ein guter Anwendungsfall. :-)
Niks
3
Du hast es. Der Schlüssel ist das Erstellen des Repos außerhalb des Arbeitsverzeichnisses.
Leo
4
Ich mag das - es ermöglicht mir, Git in Verzeichnissen zu verwenden, die ich mit Dropbox teile, ohne dass die anderen Teilnehmer überhaupt wissen, dass Git verwendet wird.
Quentin Stafford-Fraser
19

Es ist üblich, ein Verzeichnis zu benennen, bei dem es sich um ein Git-Repository handelt, dessen Arbeitsbaum sich an einem ungewöhnlichen Ort mit der Erweiterung '.git' befindet, ähnlich wie bei einem nackten Repository.

mkdir ../git_repos/myfiles.git

Wenn Sie die --work-treeOption zur Init-Zeit angegeben hätten, hätte dies automatisch die core.worktreeKonfigurationsvariable eingerichtet, was bedeutet, dass git weiß, wo sich der Arbeitsbaum befindet, sobald Sie das git-Verzeichnis angegeben haben.

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

Sie können diese Variable aber auch nachträglich festlegen.

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

Sobald Sie dies getan haben, sollte der Befehl add wie erwartet funktionieren.

git --git-dir=../git_repos/myfiles.git add foo
CB Bailey
quelle
Ich habe festgestellt, dass 'git add foo' nur funktioniert, wenn Sie zuerst auf ../git_repos/myfiles.git cd, anstatt sich im eigentlichen Arbeitsbaum zu befinden, und Sie müssen nicht --git-dir all angeben die Zeit.
Steve Folly
1
Es ist wahr, aber ich denke, dass die meisten Leute eher in ihrem Arbeitsbaum als in ihren Repositories arbeiten. Wenn Sie einen abgetrennten Arbeitsbaum verwenden, tun Sie wahrscheinlich etwas Besonderes und verwenden möglicherweise einige Makros, um zu helfen.
CB Bailey
6

Verwendung gitim Repo:

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

Von nun an können Sie gitinnerhalb des ./backup/git_repos/myfilesVerzeichnisses verwenden, ohne Umgebungsvariablen oder zusätzliche Parameter festzulegen.

To1ne
quelle
Dies scheint die beste Antwort zu sein, aber ich warning: core.bare and core.worktree do not make senseverstehe die Nachricht. Bedeutet das, dass es nicht funktioniert hat?
Hazrpg
1
Ich denke immer noch, dass es funktioniert, aber es beschwert sich darüber, dass es beim Einstellen des Arbeitsbaums nackt ist. Deshalb bin ich Einstellung core.barezu falsespäter.
To1ne
Ah! Das macht jetzt mehr Sinn. Dank dafür.
Hazrpg
1

Sie könnten ein "Nodgit" -Skript (No Dot GIT) mit so etwas wie erstellen

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

Sie können nodgit anstelle von git aufrufen und es werden nach Bedarf Variablen festgelegt, indem nach einem git-Repo gesucht wird. Angenommen, Sie haben ein (nacktes) Repo in / usr / local / gits / __ home__foo_wibbles und Sie befinden sich in / home / foo / wibbles / one. Dann wird das richtige Arbeitsverzeichnis (/ home / foo / wibbles) und Repo gefunden .

Oh, Sie können auch "nodgit shell" verwenden, um eine Shell mit den richtigen vars zu erhalten, so dass Sie einfache alte git-Befehle verwenden können.

Paul Hedderly
quelle
0

Angenommen, Ihre myfilesVerzeichnisse sind bereits vorhanden und enthalten Inhalte. Könnten Sie damit leben:

cd ~/backup
git init
git add myfiles

Das .gitVerzeichnis befindet sich in backup, nicht in myfiles.

Abie
quelle
Obwohl das irgendwie reparieren würde, was ich will, würde ich lieber einfach den Ordner myfiles unter git speichern und sonst nichts.
Rory
gitMit der .gitignoreDatei können Sie eine Auswahl der Dateien behalten, die Sie verfolgen möchten . Wenn Sie hinzufügen *und hinzufügen !myfiles, wird nur dieses Verzeichnis verfolgt. Aber wenn Sie ein separates Repo für ein anderes Verzeichnis möchten, hätten Sie ein Problem ...
To1ne
0

Ich erstelle Skripte, die aussehen

~ / 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 $?

Die Verwendung von --git_dir = $ GIT_DIR ist überflüssig, erinnert mich jedoch daran, dass ich Umgebungsvariablen auch außerhalb des Skripts festlegen kann.

Das obige Beispiel dient zum Verfolgen lokaler Änderungen an Cygwin-Systemdateien.

Kann ein solches Skript für jedes größere Projekt erstellen, das dies benötigt - aber / ohne /.git ist meine Hauptverwendung.

Das Obige ist klein genug, um einen Shell-Alias ​​oder eine Shell-Funktion zu erstellen, wenn Sie die Redundanz beseitigen.

Wenn ich dies oft genug mache, würde ich den Arbeitsbereich für die Repository-Zuordnung von wiederbeleben

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

Das nächste moderne Gegenstück sind Perforce-Zuordnungen oder -Ansichten , die teilweise Auschecken sowie die Nicht-Colocation von Arbeitsbereich und Repo unterstützen.

Krazy Glew
quelle