Git submodule on remote bare
I figured out another solution which looks rather clean to me. Just give git all the info it needs to perform the submodule stuff:
$ cd /path/to/your/git_work_tree
$ git --git-dir=/path/to/your/bare_repo.git --work-tree=. submodule init
$ git --git-dir=/path/to/your/bare_repo.git --work-tree=. submodule update
One possible way might be:
- to setup
/var/www/website
as a (non-bare) repo - have your
post-receive
hook of your bare repo:- set
GIT_DIR
andGIT_WORK_TREE
to the non-bare repo at/var/www/website
cd /var/ww/website
git pull ~/website
-
git submodule update
(a bit like in "How do I init/update a git submodule in a working tree after pushing to a bare working directory?")
- set
In other words:
Pull from the bare repo instead of trying to checkout from a bare repo: a non-bare repo should be able then to accommodate the git submodule update
step.
An example script may look like
#!/bin/sh
# Get the latest code
cd /path/to/bare/repo
# Set git variables
GIT_WORK_TREE=/var/www/website
GIT_DIR=/var/www/website/.git
# Go to website and pull
cd /var/www/website
git pull /path/to/bare/repo
git submodule update --init --recursive
# Run additional build stuff here
I stumbled across this thread two days ago while I struggled with the same issue. After finally arriving at a nice, tidy solution, I wrote an article about it here:
Git push with submodules: a how-to guide
I realized that if I'm going to push
to a bare repo, only to use post-receive
to pull
into a non-bare repo, I might as well just keep it simple and push
directly to the non-bare repository. This is a clear case where the "best practice" of only pushing to a bare repo is only adding complexity.
In case of link rot, I'll paste my solution here, skipping over the bits where I run into all of the same problems that I'm sure you did.
First, let’s create a universal post-receive
hook, one that I won’t need to change on a per-repository basis:
[aaron@aaronadams]$ cat > /usr/local/share/git-core/templates/hooks/post-receive.sample
#!/bin/sh
#
# An example hook script to update the working tree, including its
# submodules, after receiving a push.
#
# This hook requires core.worktree to be explicitly set, and
# receive.denyCurrentBranch to be set to false.
#
# To enable this hook, rename this file to "post-receive".
# Read standard input or hook will fail
while read oldrev newrev refname
do
:
done
# Unset GIT_DIR or the universe will implode
unset GIT_DIR
# Change directory to the working tree; exit on failure
cd `git config --get core.worktree` || exit
# Force checkout
git checkout --force
# Force update submodules
git submodule update --init --recursive --force
[aaron@aaronadams]$ chmod +x /usr/local/share/git-core/templates/hooks/post-receive.sample
Now let’s go ahead and break all the rules.
We’re going to initialize a non-bare Git repository, right in our website directory; make sure it can receive from git push
; explicitly set its working tree to its parent directory; and enable our hook we just created.
[aaron@aaronadams]$ cd /var/www/vhosts/aaronadams.ca/sites/staging.aaronadams.ca
[aaron@aaronadams]$ git init && git config --bool receive.denyCurrentBranch false && git config --path core.worktree ../ && mv .git/hooks/post-receive.sample .git/hooks/post-receive
Initialized empty Git repository in /var/www/vhosts/aaronadams.ca/sites/staging.aaronadams.ca/.git/
Finally, on our local machine, we’ll change our remote to reflect the location of our new repository, and push.
[aaron@aaronadams]$ git remote set-url staging [email protected]:sites/staging.aaronadams.ca
[aaron@aaronadams]$ git push staging master
remote: Submodule 'codeigniter' (git://github.com/EllisLab/CodeIgniter.git) registered for path 'codeigniter'
remote: Cloning into 'codeigniter'...
remote: Submodule path 'codeigniter': checked out 'fd24adf31255822d6aa9a5d2dce9010ad2ee4cf0'
To [email protected]:sites/staging.aaronadams.ca
* [new branch] master -> master
Holy crap, it worked!
Not only is this method compatible with submodules, it also requires just one command to set up a new remote repository (which, okay, consists of four commands). It also keeps the repository and the working tree in the same place; and with no absolute paths required in our configuration or hook files, it’s now completely portable as well.
I hope this answer helps somebody as much as everyone else's Stack Exchange posts helped me over the last two days!