views:

597

answers:

3

Hi, I am wondering if anyone has experience working on Django projects in a small team (3 in my case), using Git source control management.

The project is hosted on a development server, which is why I am having such a problem. Developers can't see if their code works until they commit their changes to their local repository, then push those changes to the server. Even then, however, git doesn't seem to be updating the files inside the directory holding the repository on the server - probably because it only stores the changes to save space.

We are beginning to tread on each other's toes when working on this project, so some kind of version control is required - but I just can't figure out an solution.

If anyone has overcome a similar problem I'd love to hear how it can be done.

+3  A: 

When pushing to a remote repository, best results are when the remote repository is a "bare" repository with no working directory. It sounds like you have a working directory on the remote repository, which will not be updated by Git when doing a push.

For your situation, I would recommend that developers have their own testing environment that they can test against locally before having to push their code anywhere else. Having one central location where everybody needs to push their work before they can even try it will lead to much pain and suffering.

For deployment, I would recommend pushing to a central "bare" repository, then having a process where the deployment server pulls the latest code from the central repository into its working directory.

Greg Hewgill
+1 The git-not-updating-remote-working-tree is a side issue. Developers simply MUST each have a local working test setup (honestly, with SQLite and the django dev server it's not hard).
Carl Meyer
+3  A: 

When you push to a (shared) git repository, it doesn't update that repository's working files. Basically because the working files might be dirty and in that case you'd have to merge--- and for that you need to have full shell access there, which may not be the case in general.

If you want to have the most recent "master" of the shared repo checked out somewhere, you can arrange for that by writing a post-update hook. I'll give an example of one below that I use to check out the "ui" subdirectory and make it available to Apache.

However, I will say that I think your process could be improved. Developers generally need personal servers that they can test on before pushing to a shared point: otherwise that shared repo is likely to be hideously unreliable. Consider, if I push a change to it and it doesn't work, is that my change that broke it or a side-effect of someone else's?

OK, I use this as a post-update hook:

#!/bin/sh
# Should be run from a Git repository, with a set of refs to update from on the command line.
# This is the post-update hook convention.

info() {
    echo "post-update: $@"
}

die() {
    echo "post-update: $@" >&2
    exit 1
}

output_dir=..
for refname in "$@"; do
    case $refname in
        refs/heads/master)
            new_tree_id=$(git rev-parse $refname:ui)
            new_dir="$output_dir/tree-$new_tree_id"
            if [ ! -d "$new_dir" ]; then
                info "Checking out UI"
                mkdir "$new_dir"
                git archive --format=tar $new_tree_id | ( cd $new_dir && tar xf - )
            fi
            prev_link_target=$(readlink $output_dir/current)
            if [ -n "$prev_link_target" -a "$prev_link_target" = "tree-$new_tree_id" ]; then
                info "UI unchanged"
            else
                rm -f $output_dir/current
                ln -snf "tree-$new_tree_id" "$output_dir/current"
                info "UI updated"
                title=$(git show --quiet --pretty="format:%s" "$refname" | \
                    sed -e 's/[^A-Za-z][^A-Za-z]*/_/g')
                date=$(git show --quiet --pretty="format:%ci" "$refname" | \
                    sed -e 's/\([0-9]*\)-\([0-9]*\)-\([0-9]*\) \([0-9]*\):\([0-9]*\):\([0-9]*\) +0000/\1\2\3T\4\5\6Z/')
                ln -s "tree-$new_tree_id" "$output_dir/${date}__${title}"
            fi
            ;;
    esac
done

As mentioned, this just checks out the "ui" subdirectory. That's the ":ui" bit setting new_tree_id. Just take the ":ui" out (or change to "^{tree}") to check out everything.

Checkouts go in the directory containing the git repo, controlled by output_dir. The script expects to be running inside the git repo (which in turn is expected to be bare): this isn't very clean.

Checkouts are put into "tree-XXXX" directories and a "current" symlink managed to point to the most recent. This makes the change from one to another atomic, although it's unlikely to take so long that it matters. It also means reverts reuse the old files. And it also means it chews up disk space as you keep pushing revisions...

araqnid
A: 

Had the same problem, also working with django.

Agree to testing locally prior to deployment, as already mentioned.

You can then push the local version to a new branch on the server. Then you do a merge with this branch and the master. After this you'll see the updated files.

If you accidentally pushed to the master branch, then you can do a git reset --hard. However all changes not commited in the current working branch will be lost. So take care.

msmart