Могу ли я хранить папку .git вне файлов, которые я хочу отслеживать?

147

У меня есть необычная идея использовать git в качестве системы резервного копирования. Допустим, у меня есть каталог ./backup/myfiles, и я хочу сделать резервную копию, используя git. Для сохранения чистоты я не хочу, чтобы в папке myfiles был каталог .git, поэтому я подумал, что могу создать ./backup/git_repos/myfiles. Посмотрев на git docs, я попытался сделать это:

$ 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

Вы можете увидеть сообщение об ошибке, которое я получил там. Что я делаю не так?

Рори
источник
9
Наряду с вашей идеей резервного копирования, это также может быть использовано для сохранения ваших «точечных файлов» (.bashrc, .vimrc и т. Д.) В домашнем каталоге, в то же время сохраняя папку .git в другом месте.
Филипп
6
Самый простой ответ: stackoverflow.com/a/19548676/170352 (похоронен из-за старых голосов)
Брэндон Бертельсен
1
В случае, если у вас нет прав на запись или вы не хотите вносить какие-либо изменения в рабочий каталог (например, добавив .git / и т. Д.), Этот ответ ниже от Лео (также скрытый старыми ответами) является лучшим.
КобеДжон
1
@Philip, если ваш репозиторий dotfiles также не содержит подмодулей Git. Git не поддерживает подмодули в сочетании с внешним рабочим деревом.
maxschlepzig

Ответы:

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

Это будет делать то, что вы хотите, но, очевидно, будет отстой, когда вам нужно будет указать это с каждой командой Git, которую вы когда-либо использовали

Вы можете экспортировать, GIT_WORK_TREE=.и GIT_DIR=../backupGit подберет их для каждой команды. Это только позволит вам удобно работать в одном репозитории на оболочку.

Я бы предпочел использовать символическую ссылку на каталог .git в другом месте или создать символическую ссылку на каталог .git из основного каталога резервного копирования.

Бомбы
источник
1
Вы можете заархивировать то же самое без указания git-dir и рабочего дерева в каждой команде и без каких-либо символических ссылок. Смотри мой ответ.
Ник
Недостатком символической ссылки является то, что она существует в рабочем дереве, и если какой-то другой процесс уничтожит рабочее дерево, то вы потеряли символическую ссылку
Джефф
Кроме того, если OP не хочет подкаталога .git в своем рабочем дереве, зачем ему нужна символическая ссылка?
Джефф
@Jeff: для компромисса. (В его резервном случае стирание его рабочего дерева, вероятно, больше не беспокоит его, чем уничтожение любого другого каталога (например, самого репо).)
Sz.
1
Я использую это вместе с direnv для своих заметок. Мое рабочее дерево находится в папке в Dropbox, а моя папка git где-то снаружи. Таким образом, я могу легко вносить свои изменения на всех компьютерах, но при этом иметь возможность проверять, что изменилось, и фиксировать только тогда, когда что-то значительное изменилось. Спасибо
Пауло Фагула
170

Вам просто нужно убедиться, что хранилище знает, где находится дерево работы, и наоборот.

Чтобы сообщить хранилищу, где находится рабочее дерево, задайте значение конфигурации core.worktree. Чтобы дать рабочему дереву знать, где находится его каталог git, добавьте файл с именем .git (не папка!) И добавьте строку вроде

gitdir: /path/to/repo.git

Начиная с git 1.7.5 команда init изучила дополнительную опцию для этого.

Вы можете инициализировать новый отдельный репозиторий с помощью

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

Это инициализирует репозиторий git в отдельном каталоге и добавит файл .git в текущий каталог, который является рабочим каталогом нового репозитория.

Раньше до 1.7.5 вам приходилось использовать немного другие параметры и добавлять файл .git самостоятельно.

Чтобы инициализировать отдельный репозиторий, следующая команда связывает рабочее дерево с репозиторием:

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

Ваш текущий каталог будет рабочим деревом, а git будет использовать хранилище по адресу /path/to/repo.git. Команда init автоматически установит core.worktreeзначение в соответствии с --git-dirпараметром.

Вы могли бы даже добавить псевдоним для этого:

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

Использовать контроль версий git в рабочем каталоге только для чтения

Обладая знаниями выше, вы даже можете настроить контроль версий git для рабочего каталога, не имея прав на запись. Если вы используете --git-dirкаждую команду git или выполняете каждую команду из репозитория (вместо рабочего каталога), вы можете пропустить файл .git и, следовательно, не нужно создавать какие-либо файлы в рабочем каталоге. Смотрите также ответ Леоса

НИКС
источник
7
Вы можете сделать это и с существующим репо: переместите папку .git туда, куда вы хотите, добавьте файл .git, чтобы указать на нее, и затем вы можете просто продолжать использовать репо, как обычно
joachim
Обратите внимание, что вы можете выполнять только команды git из корня репозитория. Переход в подпапки смущает это! (Это происходит независимо от того, является ли данное значение для gitdir относительным или абсолютным.)
joachim
2
Исправление для этого заключается в указании 'core.worktree' в самом файле конфигурации git, то есть в папке, на которую вы указываете в .git.
Иоахим
2
Да, это то, что я описал во втором предложении моего ответа. core.worktreeРазумеется, значение конфигурации хранится в файле конфигурации папки .git, на которую указывает файл .git.
Ник
1
Я обнаружил, что когда я использовал эти инструкции, сделанное репо стало пустым хранилищем, и оно выдает ошибку fatal: core.worktree and core.bare do not make sense. Похоже, что просто изменение конфигурации, так что это не просто решает это.
Стивен Лу
62

--separate-git-dirВариант git initgit clone) может быть использован для достижения этой цели на мою версию мерзавца ( 1.7.11.3). Опция отделяет репозиторий git от рабочего дерева и создает символическую ссылку git, независимую от файловой системы (в форме файла с именем .git), в корне рабочего дерева. Я думаю, что результат идентичен ответу Никса .

git init --separate-git-dir path/to/repo.git path/to/worktree
Фрайер
источник
2
+1 Использование параметра командной строки для initсебя выглядит яснее и чище
goncalopp
в окнах repo.gitсоздается с установленным атрибутом hiden. Затем я изменяю это вручную. Вы случайно не знаете, безопасно ли это?
ПА.
+1 Да, git использовал эту опцию командной строки в версии 1.7.5, которая тогда была недоступна (если я правильно помню). Я обновил свой ответ, чтобы предложить использовать этот параметр.
Ник
25

Я считаю , что проще поменять местами --work-treeи --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
        ...

Этот подход имеет два преимущества:

  • Это устраняет необходимость иметь какие-либо параметры командной строки или .gitфайлы. Вы просто работаете в обычном режиме из корня хранилища.
  • Это позволяет вам создавать версии файловой системы, даже если она вам не принадлежит. Git будет писать только в хранилище.

Единственное предостережение, с которым я столкнулся, это то, что вместо использования .gitignoreфайла вы редактируете info/exclude.

Затем вы можете использовать хранилище read_only_repos/fooв качестве удаленного в своих собственных хранилищах, даже если исходные файлы не находятся под контролем версий.

Лео
источник
Ну, это точно такая же команда. Единственное отличие, которое я вижу, заключается в том, что вы поменяли местами аргументы --work-tree и --git-dir. И, конечно же, вы не создаете файл .git в рабочем каталоге, поскольку у вас нет прав на запись в него. Тем не менее, использование контроля версий для каталога без доступа для записи является хорошим вариантом использования. :-)
Ник
3
Ты понял. Ключ создает репо за пределами рабочего каталога.
Лев
4
Мне это нравится - это позволяет мне использовать git в каталогах, которыми я делюсь с Dropbox, без того, чтобы другие участники даже не знали, что git используется.
Квентин Стаффорд-Фрейзер,
19

Обычно принято называть каталог, являющийся репозиторием git, рабочее дерево которого находится в необычном месте с расширением .git, очень похожим на пустой репозиторий.

mkdir ../git_repos/myfiles.git

Если вы предоставили --work-treeопцию во время инициализации, то это автоматически настроило бы core.worktreeпеременную config, которая означает, что git будет знать, где найти рабочее дерево, когда вы укажете каталог git.

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

Но вы можете установить эту переменную и после факта.

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

Как только вы это сделаете, команда add должна работать как положено.

git --git-dir=../git_repos/myfiles.git add foo
CB Bailey
источник
Я обнаружил, что если вы сначала перейдете на ../git_repos/myfiles.git, а не в настоящее дерево работы, 'git add foo' будет просто работать, и вам не нужно указывать --git-dir all время.
Стив Фолли
1
Это правда, но я думаю, что большинство людей склонны работать в своем рабочем дереве, а не в своих хранилищах. Конечно, если вы используете отдельное рабочее дерево, вы, вероятно, делаете что-то «особенное» и вполне можете использовать некоторые макросы, чтобы помочь.
CB Bailey
6

Используйте gitвнутри репо:

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

Отныне вы можете использовать gitвнутри ./backup/git_repos/myfilesкаталога, без установки каких-либо переменных среды или дополнительных параметров.

To1ne
источник
Это кажется лучшим ответом, но я получаю сообщение warning: core.bare and core.worktree do not make sense, значит ли это, что оно не сработало?
hazrpg
1
Я все еще думаю, что это работает, но он жалуется на то, что он голый при настройке рабочего дерева. Вот почему я устанавливаю core.bareна falseпотом.
до
Ах! Это имеет больше смысла сейчас. Спасибо за это.
hazrpg
1

Вы можете создать скрипт "nodgit" (No Dot GIT) с чем-то вроде

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

Вы можете вызвать nodgit вместо git, и он при необходимости установит переменные, ища git-репо. Например, у вас есть (голое) хранилище в / usr / local / gits / __ home__foo_wibbles и вы находитесь в / home / foo / wibbles / one, тогда он найдет правильный рабочий каталог (/ home / foo / wibbles) и репо ,

О, вы также можете использовать «nodgit shell», чтобы получить оболочку с правильным набором переменных, чтобы вы могли использовать простые старые команды git.

Пол Хеддерли
источник
0

Предполагая, что ваши myfilesкаталоги уже существуют и имеют некоторый контент, вы могли бы жить с этим:

cd ~/backup
git init
git add myfiles

.gitКаталог будет backup, а не в myfiles.

Abie
источник
Хотя это может исправить то, что я хочу, я бы предпочел просто хранить папку myfiles в git и ничего больше.
Рори
Вы можете сохранить выбор файлов, которые вы хотите gitотслеживать, используя .gitignoreфайл. Если вы добавите *и !myfilesк нему, будет отслеживаться только этот каталог. Но если вы хотите отдельное хранилище для другого каталога, у вас возникнет проблема ...
To1ne
0

Я создаю сценарии, которые выглядят как

~ / Bin / ГИТ-слэш:

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

Использование --git_dir = $ GIT_DIR излишне, но напоминает мне, что я также могу устанавливать переменные окружения вне скрипта.

Приведенный выше пример предназначен для отслеживания локальных изменений системных файлов cygwin.

Может сделать один такой скрипт для любого крупного проекта, который нуждается в этом - но / без / .git - мое основное использование.

Вышеуказанное достаточно мало, чтобы создать псевдоним или функцию оболочки, если вы исключите избыточность.

Если бы я делал это достаточно часто, я бы восстановил рабочее пространство для отображения репозитория

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

ближайшим современным аналогом которого является выполнение отображений или представлений , поддержка частичных проверок, а также неколокация рабочего пространства и репо.

Крейзи Глеу
источник