1

Maybe this question is too broad (I hope not) but I'm currently don't know, how to solve my WordPress Git Branching Model problem.

My plan was to create a branching model like this without using a BitBucket Server or Jenkins:

enter image description here

So I've started making a git init in the wp-content folder of my PROD (at this time only installation of WP) system.

After I was done with this, I've cloned the whole PROD page and created a staging subdomain. After cloning was completed, I've deleted the wp-content folder at the staging system and typed in a git clone <prod-path>/.git.

This worked great and after doing some changes (for testing purposes) at the staging version, I was able to push them back to the PROD. Until now, everything is logic and normal and worked very well.

After thinking some time, I've got the great (maybe stupid) idea, to do the same with a local DEV clone on my PC. So I've did the same like at the staging version before, but this time, I've cloned the staging wp-content clone (PROD clone) to my local DEV version.

For the first view, everything looked fine but after trying to push something to the Staging system, I've got rejected from the target staging Git:

remote: error: refusing to update checked out branch: refs/heads/development        
remote: error: By default, updating the current branch in a non-bare repository   

So I first thought, that it's very stupid what I did, because the staging is also a clone without a HEAD like on the PROD (I think).

So my question to you:

Do you have an idea, how I can keep this kind of Workflow without any 3rd party software, but with 2 clones that I can work on DEV, test on Staging and going live on PROD?

To say it with commands:

1. git push <to the staging>
2. git push <to the prod>
3. git merge <dev to master>

Update

This is the content of my bare hooks folder (there is no post-received, what should I do?):

/wp-content/.bare/hooks$ ls -la
total 56
drwxr-xr-x 2 wp_ftp psacln 4096 Apr 11 13:09 .
drwxr-xr-x 7 wp_ftp psacln 4096 Apr 11 13:20 ..
-rwxr-xr-x 1 wp_ftp psacln  478 Apr 11 13:09 applypatch-msg.sample
-rwxr-xr-x 1 wp_ftp psacln  896 Apr 11 13:09 commit-msg.sample
-rwxr-xr-x 1 wp_ftp psacln 3327 Apr 11 13:09 fsmonitor-watchman.sample
-rwxr-xr-x 1 wp_ftp psacln  189 Apr 11 13:09 post-update.sample
-rwxr-xr-x 1 wp_ftp psacln  424 Apr 11 13:09 pre-applypatch.sample
-rwxr-xr-x 1 wp_ftp psacln 1642 Apr 11 13:09 pre-commit.sample
-rwxr-xr-x 1 wp_ftp psacln 1492 Apr 11 13:09 prepare-commit-msg.sample
-rwxr-xr-x 1 wp_ftp psacln 1348 Apr 11 13:09 pre-push.sample
-rwxr-xr-x 1 wp_ftp psacln 4898 Apr 11 13:09 pre-rebase.sample
-rwxr-xr-x 1 wp_ftp psacln  544 Apr 11 13:09 pre-receive.sample
-rwxr-xr-x 1 wp_ftp psacln 3610 Apr 11 13:09 update.sample
Mr. Jo
  • 4,946
  • 6
  • 41
  • 100
  • If their is no post-receive, you can create it. Make sure the first line is `#! /bin/bash` – VonC Apr 11 '19 at 12:15

1 Answers1

1

but after trying to push something to the Staging system, I've got rejected from the target staging Git

It depends what is the "rejected" message.
If it is

remote: error: refusing to update checked out branch: refs/heads/development        
remote: error: By default, updating the current branch in a non-bare repository   

That means you need to have a subfolder "bare" within your staging repo:

cd staging
git init --bare . bare
echo /bare/>>.gitignore
git add .gitignore
git commit -m "Ignore nested bare repo /bare/"
git remote add bare bare
git config remote.bare.fetch '+refs/heads/*:refs/remotes/bare/*'

cd bare
git config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'

Then modify the bare/hooks/post-receive file in order for it to:

  • be executable
  • include the following content

post-receive hook in bare nested bare repository:

#!/bin/bash
unset GIT_DIR
cd ..
git --work-tree=. --git-dir=.git fetch bare
git --work-tree=. --git-dir=.git fetch --tags bare

if ! git --work-tree=. --git-dir=.git merge-base --is-ancestor master origin/master; then
  echo "Reset non-bare master to bare master (forced update)"
  git  --work-tree=. --git-dir=.git reset --hard origin/master
else
  echo "Update non-bare master with merge from origin/master"
  git --work-tree=. --git-dir=.git pull --no-rebase origin master
fi

Finally, on your dev cloned repo:

cd dev
git config --unset-all remote.origin.pushurl
git config --add remote.origin.pushurl "/path/to/staging/bare"

That way, you are fetching from the Staging repo as usual, but are pushing to the bare nested Staging repo, and the hook will update said Staging content.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • I've added the error message. Silly me that I've forgot this. – Mr. Jo Apr 11 '19 at 06:00
  • Oh lord this is heavy :o I hope I can implement this correctly without destroying my staging. I'll let you know if it worked. – Mr. Jo Apr 11 '19 at 07:06
  • 1
    @Mr.Jo The alternative would be to push directly to your non-bare staging repo, with a push to deploy: https://stackoverflow.com/a/30030236/6309 – VonC Apr 11 '19 at 07:12
  • @Mr.Jo Don't hesitate to test that on dummy repos (new clones of your existing repos) first. – VonC Apr 11 '19 at 07:15
  • So when I understand it correctly, I create an own, second repo in my cloned staging repo and connect it with the cloned repo there. Now I can use the second repo for checkout and pushing from any local dev version - right? 0.o – Mr. Jo Apr 11 '19 at 09:37
  • 1
    @Mr.Jo the idea is to have a nested bare repo within the repo you want to *push* to. And a post-receive hook which will then update the actual repo working tree accordingly after each push. – VonC Apr 11 '19 at 09:40
  • Should I do the git init --bare . bare inside /wp-content/ or /wp-content/.git of the staging system? – Mr. Jo Apr 11 '19 at 10:20
  • 1
    @Mr.Jo as mentioned in the answer, it would be inside the `repo folder`, not the `repo folder/.git`. – VonC Apr 11 '19 at 10:35
  • Alright, thanks a lot! I apologize for asking, now everything is clear to me. – Mr. Jo Apr 11 '19 at 10:38
  • 1
    @Mr.Jo No problem. By all means, do ask away :) – VonC Apr 11 '19 at 10:38
  • I've did what you said but when I change now something on dev and push it, it seems that the staging branch get's reseted some way. Before I've did a push, I've pulled again on dev and then pushed up some things. I've expected them now on the staging .git but it seems that it's not working because nothing of my changes are there. – Mr. Jo Apr 11 '19 at 11:58
  • 1
    @Mr.Jo Staging branch? You mention a staging repo in your question. The branch which is reset or updated is the branch you are pushing from dev repo to the staging repo. The hook is there to avoid you to have to manually go to staging and pull from dev repo: since you can push directly to the nested bare repo, said nested repo will update the actual staging repo for you. – VonC Apr 11 '19 at 12:15
  • My dev is a clone of the staging repo. But this don't worked because staging is already a clone from prod. So when I talk from dev, I talk from a staging clone. And when I change something at dev and push, it should land on the staging. – Mr. Jo Apr 11 '19 at 12:25
  • 1
    It you set the push URL as indicated in the answer, it *will* land on staging. – VonC Apr 11 '19 at 12:27
  • This is what I did: git config --add remote.origin.pushurl "user@host:htdocs/staging/wp-content/.bare" – Mr. Jo Apr 11 '19 at 12:50
  • @Mr.Jo `.bare`? Why `.bare` instead of `bare`? Did you modify the `.gitignore` accordingly? And what error do you see? – VonC Apr 11 '19 at 15:03