Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Including submodules in git checkout to GIT_WORK_TREE in hook

Is it possible to include submodules when using the following code in a post-update hook?

GIT_WORK_TREE=/path/to/directory git checkout -f

What other options would I have to distribute code, including submodules from a post-update hook?

Thanks.

like image 773
iliveinapark Avatar asked Apr 15 '13 05:04

iliveinapark


People also ask

Does git pull include submodules?

Pulling with submodules. Once you have set up the submodules you can update the repository with fetch/pull like you would normally do. To pull everything including the submodules, use the --recurse-submodules and the --remote parameter in the git pull command .

How does Git keep track of submodules?

A git submodule is a record within a host git repository that points to a specific commit in another external repository. Submodules are very static and only track specific commits. Submodules do not track git refs or branches and are not automatically updated when the host repository is updated.

When should I use git submodules?

In most cases, Git submodules are used when your project becomes more complex, and while your project depends on the main Git repository, you might want to keep their change history separate. Using the above as an example, the Room repository depends on the House repository, but they operate separately.


1 Answers

The question "Using git submodule update --init on a post hook" mentions the error message you could see if using this in your post-update hook:

GIT_WORK_TREE=/path/to/directory git submodule update --init

That would give a:

remote: You need to run this command from the toplevel of the working tree.

So it is best to cd directly in the target repo and run your command from there:

export GIT_DIR=$(pwd)

cd /path/to/target/workingtree

git checkout -f master
git submodule update --init --recursive

However, as shown in "How do I init/update a git submodule in a working tree after pushing to a bare working directory?":

It looks like when your running "git submodule update" you can't set the GIT_WORK_TREE:
it will try to use this as the working tree for the submodule, not for the super project.

The blog post "Git push with submodules: a how-to guide" by Aaron Adams describe similar error messages as the OP iliveinapark shows in the comments:

Sadly, this doesn't work, I suspect because my repo is a bare repo.
The error that I get following these commands is:

fatal: This operation must be run in a work tree

If, to overcome the above error, I use something like:

git --git-dir=<my bare repo> --work-tree=<where I export to> submodule update --init --recursive 

I get:

fatal: working tree '<where I export to>' already exists. Clone of '<submodule repo>' into submodule path '<submodule path>' failed

The blog post mentioned above suggests an approach based on a non-bare repo (which usually isn't recommended for pushing to, but is necessary in this case) :

Using Git to manage a website with submodules: the right way

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.


The OP iliveinapark mentions though:

This became a bit too fiddly, though, so I went with a simple forced checkout, and will manage updating my submodules manually.

like image 110
VonC Avatar answered Sep 22 '22 20:09

VonC