可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have an unusual idea to use git as a backup system. So let\'s say I have a directory ./backup/myfiles and I want to back that up using git. To keep things clean I don\'t want to have a .git directory in the myfiles folder, so I thought I could create ./backup/git_repos/myfiles. From looking at the git docs, I\'ve tried doing this:
$ 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
You can see the error message I get there. What am I doing wrong?
回答1:
git --git-dir=../repo --work-tree=. add foo
This will do what you want but will obviously suck when you have to specify it with every git command you ever use.
You can export GIT_WORK_TREE=.
and GIT_DIR=../backup
and Git will pick them up on each command. That will only comfortably allow you to work in a single repository per shell, though.
I’d rather suggest symlinking the .git directory to somewhere else, or creating a symlink to the .git directory from your main backup directory.
回答2:
You just need to ensure that the repository knows where the work tree is and vice versa.
To let the repository know where the work tree is, set the configuration value core.worktree
. To let the work tree know where it\'s git directory is, add a file named .git (not a folder!) and add a line like
gitdir: /path/to/repo.git
Since git 1.7.5 the init command learned an extra option for this.
You can initialize a new separate repository with
git init --separate-git-dir /path/to/repo.git
This will initialize the git repository in the separate directory and add the .git file in the current directory, which is the working directory of the new repository.
Previously to 1.7.5 you had to use slightly different parameters and add the .git file yourself.
To initialize a separate repository the following command links the work-tree with the repository:
git --git-dir=/path/to/repo.git --work-tree=. init && echo \"gitdir: /path/to/repo.git\" > .git
Your current directory will be the working tree and git will use the repository at /path/to/repo.git
. The init command will automatically set the core.worktree
value as specified with the --git-dir
parameter.
You could even add an alias for this:
[alias]
initexternal = !\"f() { git --work-tree=. --git-dir=\\\"$1\\\" init && echo \\\"gitdir: $1\\\" >> .git; }; f\"
Use git version control on a read-only working directory
With the knowledge above, you can even set up git version control for an working directory without having write permissions. If you either use --git-dir
on every git command or execute every command from within the repository (instead of the working directory), you can leave out the .git file and therefore do not need to create any files within the working directory. See also Leos answer
回答3:
The --separate-git-dir
option for git init
(and git clone
) can be used to accomplish this on my version of git (1.7.11.3
). The option separates the git repository from the work tree and creates a filesystem agnostic git symbolic link (in the form of a file named .git
) in the root of the work tree. I think the result is identical to niks\' answer.
git init --separate-git-dir path/to/repo.git path/to/worktree
回答4:
I find it simpler to reverse the --work-tree
and --git-dir
directories used 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
...
This approach has two advantages:
- It removes the need to have any command-line options or
.git
files. You just operate normally from within the root of the repository.
- It allows you to version a file system even if you don\'t own it. Git will only write to the repository location.
The only caveat I have encountered is that instead of using a .gitignore
file, you edit info/exclude
.
You can then use the repository read_only_repos/foo
as a remote in your own repositories even if the original files are not under version control.
回答5:
It\'s conventional to name a directory that is a git repository that has its working tree in an unusual place with a \'.git\' extension, much like a bare repository.
mkdir ../git_repos/myfiles.git
If you had provided the --work-tree
option at init time then this would have automatically set up the core.worktree
config variable that means that git will know where to find the working tree once you specify the git directory.
git --git-dir=../git_repos/myfiles.git --work-tree=. init
But you can set this variable after the fact as well.
git --git-dir=../git_repos/myfiles.git config core.worktree \"$(pwd)\"
Once you\'ve done this, the add command should work as expected.
git --git-dir=../git_repos/myfiles.git add foo
回答6:
Use git
inside the repo:
cd ./backup/git_repos/myfiles
git init --bare
git config core.worktree ../myfiles
git config core.bare false
From now on, you can use git
inside the ./backup/git_repos/myfiles
directory, without setting any environment variables or additional parameters.
回答7:
You could create a \"nodgit\" script (No Dot GIT) with somet like
#!/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
You can call nodgit in place of git and it will set variables as necessary by looking for a git repo. For example say you have a (bare) repo in /usr/local/gits/__home__foo_wibbles and you are in in /home/foo/wibbles/one then it will find the correct working directory (/home/foo/wibbles) and repo.
Oh you can also use \"nodgit shell\" to get a shell with the correct vars set so you can use plain old git commands.
回答8:
Assuming your myfiles
directories already exists and has some content, could you live with this:
cd ~/backup
git init
git add myfiles
The .git
directory will be in backup
, not in myfiles
.
回答9:
I create scripts that look like
~/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 $?
It\'s redundant to use --git_dir=$GIT_DIR, but reminds me that I can also set environment variables outside the script.
The above example is for tracking local changes to cygwin system files.
Can make one such script for any major project that needs this - but / without /.git is my main use.
The above is small enough to make a shell alias or function, if you eliminate the redundancy.
If I do this often enough, I would revive the workspace to repository mapping of
\"Boxes, Links, and Parallel Trees: Elements of a Configuration Management System\",
in Workshop Proceedings of the Software Management Conference. 1989.
whose closest modern counterpart is Perforce mappings or views, supporting partial checkouts as well as non-colocation of workspace and repo.