How to use vim-fugitive with a git bare repository? - vim

Environment
Setup
I use a git bare repository to version my config files. I can use same commands as if I were using a normal git repository just have to include some flags:
git --git-dir=/home/kunzaatko/.cfg/ --work-tree=/home/kunzaatko/ __command__
instead of
git __command__
Usage
I make use of vim-fugitive with normal git repositories mainly for making a big change and adding it in many different commits by staging partially (only a discrete set of hunks/changes) and committing them separately . I use :Gdiff for this for the nice and productive interface I can make use of.
Desire
I want to do this with my config git bare repository.
What I tried:
Renaming the repository to .cfg.git. This didn't make any change. issue that suggests this should work
I tried to change the b:git_dir internal variable of git-fugitive:
:let b:git_dir=/home/kunzaatko/.cfg/
Changing the working directory to the git directory for fugitive to recognize that it is a git repo:
:chdir /home/kunzaatko/.cfg/
What would be worthy of trying if I knew how:
I think that there may be a way to use the git submodule command to put the bare repo into scope. The problem with that is where to put the root of the git repository... issue that I base this possibility of of
Question
Is there a way to use a git bare repository with git-fugitive?
(or any other suggestion that would solve my use-case)

I agree with #okket, but there is a problem when I use that method.
When in Gstatus window, I cannot get the status of changed files. And I find the reason is that fugitive gets the core.worktree attribute from the GIT_DIR repository.
So for me, the viable way to do this is as follows:
Same as #okket says, set GIT_DIR env variable when using vim/nvim command (GIT_WORK_TREE may be omitted):
GIT_DIR=$HOME/.cfg GIT_WORK_TREE=$HOME [n]vim
For users of fish shell (like me), should use env command:
env GIT_DIR=$HOME/.cfg GIT_WORK_TREE=$HOME [n]vim
Set core.worktree for your git repository:
git --git-dir=$HOME/.cfg --work-tree=$HOME config --local core.worktree $HOME
You can make sure you get it right with the following command:
git --git-dir=$HOME/.cfg --work-tree=$HOME config --local core.worktree
The output should be your HOME path.
If you get the git repository by git clone --bare ..., you need to unset core.bare to avoid git status error warning: core.bare and core.worktree do not make sense:
git --git-dir=$HOME/.cfg --work-tree=$HOME config --unset core.bare
And there is one more thing to notice for this method. You cannot use fugitive outside of $HOME directory where you will get fugitive: working directory does not belong to a Git repository error.
PS: I'd like to comment on #okket 's answer, but due to low reputation I can only post a new answer here.

The environment variables $GIT_DIR and $GIT_WORK_TREE let you point git and fugitive to the dotfile directory when using a bare repository. This solution works with the caveat, that fugitive/git will ignore other repositories while these variables are set.
To limit this environment pollution start vim like this:
GIT_DIR=$HOME/.cfg GIT_WORK_TREE=$HOME vim [file(s)]
In case the syntax is unfamiliar: it is possible to prepend setting environment variables before calling a binary in most (all?) shells. This limits redirecting git through the environment variables to this specific vim instance.
A quality of life improvement would be to put this line into a shell alias or use a full featured dotfile manager like yadm, which is a wrapper around a git bare repository.

Related

Track file but ignore changes, as repo config

It is possible to track one file, but discard changes to it:
git update-index --assume-unchanged <file>
But this is local setting.
How can I make this visible to my team members, without forcing them to locally do the git update-index --assume-unchanged dance?
The answer is that you can't. Git doesn't support doing this and using git update-index --assume-unchanged for this purpose is not a supported use of that feature.
If you have a config file or other file that needs to change depending on the user or system, then check in a template and generate it as part of a local build step. For example, GitHub uses templating and a set of scripts to set up local configuration in a project-independent way.

Use git shortcuts with a new version, overriding old

I'm using git on a shared hosting plan which runs a Linux distribution. Because it's shared, I don't have access to sudo. The machine already has git version 1.7.1 installed in /usr/bin/, but this version is rather prehistoric at this point. I've already used make install to get the current version 2.14.1, which is in ~/git-2.14.1/. As detailed by this answer, I can access the correct version of git from the command line like so:
$ git --version
git version 2.14.1
which was a simple change to the $PATH variable, in the ~/.bash_profile, so I can use git just fine.
I have a list of shortcuts in my ~/.gitconfig file that make git much faster for me to use:
[alias]
co = checkout
st = status
ci = commit
... etc etc etc
When I invoke these (e.g. git st), I get the results from the wrong version of git. It goes back to 1.7.1. If I type out the full command (e.g. git status), it uses the correct version of git.
I also have these commands in my ~./bashrc:
git () {
case "$*" in
st* ) shift 1; command ~/git-2.14.1/git status "$#" ;;
* ) shift 1; command ~/git-2.14.1/git "$#" ;;
esac
}
Which I have source-ed since writing.
I have also tried:
alias git="~/git-2.14.1/git"
To no avail.
Is there a work-around that would allow me to use these shortcuts with my preferred version of git? I am imagining a way to hide the config file from the other version by redirecting the pointer to a different location, but I have no knowledge of the existence of any such pointer.
Alternatively, is there a way to totally disable the previous version of git without root access?
When I invoke these (e.g. git st), I get the results from the wrong version of git. It goes back to 1.7.1
That is not what I see in my Ubuntu session.
I have in my .gitconfig
[alias]
st = status
br = branch
v = !git version
That means I type git v, to check git version (which is the same as git --version).
If I change my PATH to a new compiled Git, I do see a different version.
vonc#VONC:~/gits$ echo $PATH
/usr/local/bin:/usr/bin:/bin
vonc#VONC:~/gits$ which git
/usr/bin/git
vonc#VONCAVN7:~/gits$ git v
git version 2.13.0
vonc#VONC:~/gits$ export PATH=~/gits/v2.14.0/bin:$PATH
vonc#VONC:~/gits$ git v
git version 2.14.0
Here's what I found. If I took out the alias section of the .gitconfig, the aforementioned shell wrapper function worked. If I removed that and restarted the ssh connection, nothing worked (as expected).
I found, with help from this answer, that there is a magical GIT_EXEC_PATH variable which tells git where to find tools like git-add, git-commit, git-status, et. al.. Uncommenting my alias section of the .gitconfig file and using
$ export GIT_EXEC_PATH=/path/to/my/new/git's/executables/
made it possible to use the aliases in the .gitconfig file. For me the path that worked was the same folder as I installed into: ~/git-2.14.1.You can check the current value of GIT_EXEC_PATH with:
$ git --exec-path
/path/to/my/new/git's/executables/
Also, echo $GIT_EXEC_PATH works as well. My understanding is that git uses its aliases not through the instance of git which called git <alias>, but rather directly through the executables in it's exec path.
Note: for me,
$ git --exec-path=/path/to/my...
did not work, but if I understand correctly, this is the equivalent command.
TL;DR: add the path to the new executables (git-add, git-status, etc.) in your .bash_profile:
export GIT_EXEC_PATH=/your/path/

What mechanism does git use to find its repository?

I have several git repositories. One of these is in $PATH. Today, I accidentally moved to a directory that I thought had a git repository, but did not have one.
cd <another_directory_without_.git>.
So, when I entered git status, the output was confusing.
It appears git found the repository in $PATH, so in this case, git found the repository in ~/bin, which is in my PATH.
Does git search for repositories by looking in $PATH, or is there another search mechanism at work?
I can't find a definitive reference for the actual details, but we can infer most of it from the documentation to the git repository variables.
Git looks for its a repository, by order of preference:
in a directory provided by the --git-dir argument
in a directory provided by the GIT_DIR environment variable
in subdirectory .git or the current directory
in subdirectory .git of an ancestor directory. Environment variables GIT_CEILING_DIRECTORIES and GIT_DISCOVERY_ACROSS_FILESYSTEMS set a few constraints on that.
According to the git(1) manual page, Git goes like this when it looks for its object store:
If the "--git-dir" command-line option was specified its value is used to locate the repository.
If the GIT_DIR environment variable is available and set its value is used to locate the repository.
Note that in both of these cases no search/heuristics is done.
Otherwise Git tries to figure out if the current directory is the repository — in case it's a bare repository which has no work tree.
The logic it uses to carry out this task is explained here. To cite it:
Test if it looks like we're at a git directory.
We want to see:
- either an objects/ directory _or_ the proper
GIT_OBJECT_DIRECTORY environment variable
- a refs/ directory
- either a HEAD symlink or a HEAD file that is formatted as
a proper "ref:", or a regular file HEAD that has a properly
formatted sha1 object name.
Failing that, Git tries to find a directory named ".git" in the current directory.
If it succeeds, it uses the test from the previous step to verify if it's really what it was looking for.
If it fails, it ascends one level up — to the parent directory and tries again.
The last two steps are carried out until / on POSIX-like systems or the root of the drive — on Windows is hit (and hence there's nothing to ascent). By default, Git also won't cross the boundary of a filesystem of the current directory.
As you can see, no $PATH is involved: this directory is used only to look up executable programs, and Git has no business with it.

How to make current directory a git working directory

I've written multiple *.cpp files in the location ~/Code/CPLUS before I know the existence of git.
Now I want to use git for version control.
I created a folder ~/git_repo/, and in this folder, I ran git init command. When I tried to run the command git add my_first_c.cpp under the path ~/Code/CPLUS, the following message appeared:
fatal: Not a git repository (or any of the parent directories): .git
Then I typed git init ~/git_repo/ under the path ~/Code/CPLUS, the same error still appeared when git status was typed.
If I type git init under the path ~/Code/CPLUS, the add and commit can be executed. The only problem is that .git is stored in ~/Code/CPLUS/, while I'd like it be stored in ~/git_repo.
My question is how to make the folder ~/Code/CPLUS a working directory while the repo info is stored in ~/git_repo/? And my machine has no GUI.
You could try exporting the variables export GIT_WORK_TREE=~/git_repo/ and export GIT_DIR=../Code/CPLUS from terminal (or in your ~/.bashrc) so Git uses these.
Thanks #Alariva , the suggested solution indeed solved this question. With .git created in ~/git_repo/, typing git --git-dir=/abs/path/to/repo/git_repo/.git add my_first_c.cpp works.
The solution comes from this post.

gitolite hook for specific repository

I don't understand how do I create a post-receive hook for a specific repository in gitolite (non-root install)
My bare repository contains a website that should copy the working directory to the docRoot
(GIT_WORK_TREE=/path/htdocs git checkout -f) on update
Before gitolite, I would just update the hook for the specific repository.
Gitolite documentation mentions that all hooks should be at hooks/common so I don't understand how it works.
What should be the name of hooks, where it should be located and how it's structure should be changed (if it should)?
Update July 2013: what follows is for gitolite V2 (or 'g2'), which was the version used by the OP at the time (November 2011).
Update August 2013, with the latest gitolite 3.x:
You now have official specific repo hook:
it's basically just creating a symlink in <repo.git>/hooks pointing to some file inside $rc{LOCAL_CODE}/hooks/repo-specific (except the gitolite-admin repo)
All hooks in gitolite/hooks/common are replicated in all repositories managed by Gitolite, as detailed in the hook propagation documentation.
That means your hook script must take specific action depending on the repo which execute said hook.
You can either use the $GL_REPO variable (which gitolite set and pass to all its scripts for any git command it receives).
Or you can use some git configuration registered on the gitolite server, like the mirroring hook does. See the post-receive.mirrorpush hook.
The OP Eyal R adds in the comments:
But I still don't understand how it is done (I understand that $GL_REPO is used to determine which repo I am updating but I'm missing the practical part).
I have created a file called post-receive.test with echo "test", put it in $HOME/gitolite/hooks/common, ran gl-setup, ran push from workstation - nothing happens (no "test" output)
To which I replied:
The hook should appear in the hook directory of your repo on the gitolite server as a link, linking back to the .gitolite/common/hook. Note that it should be in $HOME/.gitolite/common/hook, not /gitolite.
The OP confirms the missing dot was the issue.
The process to add an hook is detailed in Hook propagation in gitolite, and their usage in "Using Hooks".
This is a fairly common need for someone using gitolite, and appears to be a little difficult to tie up loose ends when being not a very advanced user (at leas it was for me).
Following stackoverflow's and gitolite's links back and forth can be a little confusing. These are my conclusions and the path I followed to be able to achieve this.
As #VonC mentioned creating repository specific hooks is already possible since version 3.5.3.1 (github link)
Update/Upgrade Gitolite
The first thing you should do is update your gitolite repo. So ssh into your server that is hosting gitolite and move to the location where gitolite is installed (usually /home/git/gitolite) as the git user (usually git)
Example:
$ ssh myusername#devserver.com
$ sudo su - git
$ pwd
/home/git
$ cd gitolite
Then we have to upgrade gitolite. To do so, first we need to update the gitolite repository
$ git pull
Then we have to repeat the install command (make sure you use the same arguments as before)
$ ./install
And finally run the setup again.
$ gitolite setup
If that doesn't work, you probably haven't set up gitolite executable in your PATH, so you could do something like this:
$ src/gitolite setup
Gitolite Settings (The "RC" file)
This was one of the parts that confused me the most, but it ended up it was pretty straight forward.
The famous "rc" file is located at git's home directory /home/git/.gitolite.rc. There make sure you have a variable called LOCAL_CODE, you should see something like this on that file, if not, add it.
LOCAL_CODE => "$ENV{HOME}/.gitolite/local"
And in the "commands an feature to enable" section you should make sure that repo-specific-hooks is available, if not, add it.
ENABLE => [
# COMMANDS
# These are the commands enabled by default
'help',
'desc',
'info',
...,
...,
...,
'repo-specific-hooks'
...,
...,
...
]
Here is the link to the documentation
Writing Repository Specific Hooks
Finally, in your local gitolite-admin repository create the following directories hooks/repo-specific under the directory you just set in the LOCAL_CODE variable, for example:
gitolite_admin/local/hooks/repo-specific
After that you can actually add your hooks scripts to that location and manage them through the gitolite conf file as stated in the documentation. Make sure the scripts are executable.
repo foo
RW+ = #all
option hook.post-receive = deploy
Again, I hope this helps some of you guys.
Cheers!

Resources