4

I work on a team of web developers. We each have a personal web site set up in our home directories on the development server.

We want to convert them to git working repos so we can branch, rebase, and generally enjoy the benefits of git goodness.

In reading online, there's a couple of options:

1) create a bare repo that syncs to the working repo in www/ via a post-receive hook

2) push directly to the working repo

Problem with option 1 is it doesn't handle branching well. When we push a branch other than master, the post-receive hook still only syncs master so our changes never appear on the development site.

Problem with option 2 is git disallows pushing to a checked-out branch to prevent a detached HEAD state.

In reading around the web, the "best practice" solution to option 2 goes something like this:

1) on CLIENT push to dummy branch

2) on SERVER merge dummy into master... BUZZZZ wrong answer. Assume the end users don't have shell access to the server.

So I thought, "no problem, just create a post receive hook like this":

#!/bin/bash
read oldSHA newSHA branch
git merge $branch

Now here's the weird part: when the post-receive hook executes I get

Please, commit your changes or stash them before you can merge.

Yes, I have confirmed that master is the checked-out branch on the server, and that the dummy branch has been updated correctly. When I run the very same command (git merge dummy) directly on the server, everything works fine.

Can anyone explain why?

Thanks in advance.

EDIT 1

Here are the results of git status, both pre-merge and post-merge

Counting objects: 5, done.                                                                                                                                                            
Delta compression using up to 8 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 307 bytes, done.
Total 3 (delta 2), reused 0 (delta 0)
remote: **** PRE MERGE ****
remote: # On branch master
remote: # Untracked files:
remote: #   (use "git add <file>..." to include in what will be committed)
remote: #
remote: #       COMMIT_EDITMSG
remote: #       FETCH_HEAD
remote: #       HEAD
remote: #       ORIG_HEAD
remote: #       config
remote: #       description
remote: #       hooks/
remote: #       index
remote: #       info/
remote: #       logs/
remote: #       objects/
remote: #       packed-refs
remote: #       refs/
remote: no changes added to commit (use "git add" and/or "git commit -a")
remote: error: Your local changes to the following files would be overwritten by merge:
remote:         index.htm
remote: Please, commit your changes or stash them before you can merge.
remote: Aborting
remote: **** POST MERGE ****
remote: # On branch master
remote: # Changes not staged for commit:
remote: #   (use "git add <file>..." to update what will be committed)
remote: #   (use "git checkout -- <file>..." to discard changes in working directory)
remote: #
remote: #       modified:   index.htm
remote: #
remote: # Untracked files:
remote: #   (use "git add <file>..." to include in what will be committed)
remote: #
remote: #       COMMIT_EDITMSG
remote: #       FETCH_HEAD
remote: #       HEAD
remote: #       ORIG_HEAD
remote: #       config
remote: #       description
remote: #       hooks/
remote: #       index
remote: #       info/
remote: #       logs/
remote: #       objects/
remote: #       packed-refs
remote: #       refs/
remote: no changes added to commit (use "git add" and/or "git commit -a")

Note that I can do a manual git add ., git commit -m "foo" and re-do this process with the same result

vaFyreHeart
  • 275
  • 1
  • 3
  • 13
  • When you get this message, do this: `git status`. And show us the result. – Tadeck May 08 '13 at 21:12
  • Another route to consider would be using [`git archive`](http://git-scm.com/docs/git-archive) and unpacking the archives into your actual site directories (don't have them be repositories). You should be able to do this in a `post-receive` hook that lives in a bare repo. How do you want it to decide what branch to use anyway? Should it just be whatever branch has the most recent commit? – Matt Kantor May 08 '13 at 21:41
  • Yes, I want to commit the most recent branch. Should be whatever's passed to post-receive by the receive-pack. Really, I want to display the most recent branch pushed for debugging purposes. – vaFyreHeart May 08 '13 at 22:42
  • Gotcha. My usual setup for this kind of thing is to have a separate deploy for each branch/tag; e.g. `branchname.domain.com` would be deployed from the most recent commit to the `branchname` branch. – Matt Kantor May 08 '13 at 23:32
  • Doesn't that require a DNS change, or at least updating your HOSTS file? – vaFyreHeart May 09 '13 at 00:02
  • You could use a [wildcard subdomain](http://en.wikipedia.org/wiki/Wildcard_DNS_record). In any case that was just an example, you could also deploy to `domain.com/branchname` or whatever floats your boat. – Matt Kantor May 09 '13 at 03:40
  • You might want to check out what I learned here about securely deploying a git project to a remote webserver without exposing your repo to your webserver: http://stackoverflow.com/a/18941021/470749 – Ryan Oct 01 '13 at 16:37

1 Answers1

2

In one of those "DUH!" moments, I realized I could use option 1 and just pass the branch name in like I was attempting with option 2.

So, I created a /home/username/www.git bare repository, cloned it to /home/username/www and added a post-receive hook to /home/username/www.git that looks something like this:

#!/bin/bash
read oldSHA newSHA branch
git --git-dir="/home/username/www/.git" --work-tree="/home/username/www" pull /home/username/www.git $branch

Then I changed my remote to ssh://username@example.com/home/username/www.git (the bare reop, not the working one) and push to that remote via:

git push remoteName branchName

Voila! Everything works.

The actual post-receive code is more complex as I use some error traps and variables for the directory names (so they can be deployed to any user), but you get the idea.

(Be careful to distinguish between www/.git and www.git when reading the code samples.)

vaFyreHeart
  • 275
  • 1
  • 3
  • 13