This commit is contained in:
Joey Hess 2013-11-04 17:30:53 -04:00
parent 07ba5a6991
commit 78449ed2ae
2 changed files with 89 additions and 0 deletions

View file

@ -0,0 +1,29 @@
I've been investigating ways to implement a [[/todo/direct_mode_guard]].
Preventing a stray `git commit -a` or `git add` doing bad things in a
direct mode repository seems increasingly important.
First, considered moving `.git`, so git won't know it's a git repository.
This doesn't seem *too* hard to do, but there will certianly be unexpected
places that assume `.git` is the directory name.
I dislike it more and more as I think about it though, because it moves
direct mode git-annex toward being entirely separate from git, and I don't
want to write my own version control system. Nor do I want to complicate
the git ecosystem with tools needing to know about git-annex to work in
such a repository.
So, I'm happy that one of the other ideas I tried today seems quite
promising. Just set core.bare=true in a direct mode repository. This nicely
blocks all git commands that operate on the working tree from doing
anything, which is just what's needed in direct mode, since they don't know
how to handle the direct mode files. But it lets all git commands and other
tools that don't touch the working tree continue to be used. You can even
run `git log file` in such a repository (surprisingly!)
It also gives an easy out for anyone who really wants to use git commands
that operate on the work tree of their direct mode repository, by just
passing `-c core.bare=false`. And it's really easy to implement in
git-annex too -- it can just notice if a repo has core.bare and
annex.direct both set, and pass that parameter to every git command it
runs. I should be able to get by with only modifying 2 functions to
implement this.

View file

@ -20,3 +20,63 @@ add`. The git wrapper could instead be another program, or it could be
something like `git annex git add`
--[[Joey]]
----
Or, no git wrapper could be provided. Limit the commands to only git-annex
commands. This should be all that is needed to manage a direct mode
repository simply, and if the user is doing something complicated that
needs git access, they can set `GIT_DIR=.git-annex` and be careful not to
shoot off their foot. (Or can just switch to indirect mode!)
This wins on simplicity, and if it's the wrong choice a git wrapper
can be added later. --[[Joey]]
---
Implementation: Pretty simple really. Already did the hard lifting to
support `GIT_DIR`, so only need to override the default git directory
in direct mode when that's not set to `.git-annex`.
A few things hardcode ".git", including Assistant.Threads.Watcher.ignored
and `Seek.withPathContents`, and parts of `Git.Construct`.
---
Transition: git-annex should detect when it's in a direct mode repository
with a .git directory and no .git-annex directory, and transparently
do the move to transition to the new scheme. (And remember that `git annex
indirect` needs to move it back.)
# alternative approach: move index
Rather than moving .git, maybe move .git/index?
This would cause git to think that all files in the tree were deleted.
So git commit -a would make a commit that removes them from git history.
But, the files in the work tree are not touched by this.
Also, git checkout, git merge, and other things that manipulate the work
tree refuse to do anything if they'd change a file that they think is
untracked.
Hmm, this does't solve the user accidentially running git add on an annexed
file; the whole file still gets added.
# alternative approach: fake bare repo
Set core.bare to true. This prevents all work tree operations,
so prevents any foot shooting. It still lets the user run commands like
git log, even on files in the tree, and git fetch, and push, and git
config, etc.
Even better, it integrates with other tools, like `mr`, so they know
it's a git repo.
This seems really promising. But of course, git-annex has its own set of
behaviors in a bare repo, so will need to recognise that this repo is not
really bare, and avoid them.
(Git may also have some bare repo behaviors that are unwanted. One example
is that git allows pushes to the current branch in a bare repo,
even when `receive.denyCurrentBranch` is set.)