Preparing the Server Environment
Before configuring Git, ensure your CentOS server has the necessary tools installed. You need Git itself and typically Nginx or Apache depending on your stack. For this example, we assume you are deploying to a standard web root like/var/www/html. It is critical to create a dedicated system user for deployments rather than using root. This limits the blast radius if something goes wrong during a push.
Create a user named deployer and add them to the nginx group (or www-data for Apache) so they can write to the web directory. Set the home directory to /home/deployer. This user will own the bare repository and execute the hooks.
Creating the Bare Repository
A bare repository contains only the version history without a working directory. On your server, navigate to a secure location, such as/srv/git, and create a new project folder. Initialize it as a bare repo using the following command:
mkdir /srv/git/myproject.git
cd /srv/git/myproject.git
git init --bare
This structure prevents direct editing of files on the server via Git commands, forcing all changes through your local workflow. Ensure the deployer user owns this directory recursively:
chown -R deployer:deployer /srv/git/myproject.git
You must also configure the SSH daemon to allow key-based authentication for the deployer user. If you are struggling with connection timeouts or permission denied errors, refer to our guide on Troubleshooting SSH Access and Web Server Ping Failures in a Local Network to ensure network connectivity is not the root cause.
Configuring the Post-Receive Hook
The core mechanism for updating files is thepost-receive hook. This script runs automatically after a successful push. Navigate to the hooks directory inside your bare repo:
cd /srv/git/myproject.git/hooks
Create a file named post-receive and make it executable. The script must check out the current branch into your web root. A common mistake is hardcoding paths or ignoring environment variables. Use this robust template:
#!/bin/bash
GIT_WORK_TREE=/var/www/html git checkout -f master
The -f flag forces the checkout, overwriting existing files. However, this approach leaves deleted files from previous commits intact unless you clean the working tree. To truly sync missing files, you should use git clean -fdx before checking out. Add these lines to the hook:
#!/bin/bash
GIT_WORK_TREE=/var/www/html git clean -fdx
GIT_WORK_TREE=/var/www/html git checkout -f master
Ensure the deployer user owns this hook and has execute permissions:
chmod +x post-receive
chown deployer:deployer post-receive
If you encounter issues where Git ignores your identity file or prompts for passphrases unexpectedly, check our article on Git SSH: Passphrase Prompted Even After Caching Credentials to resolve authentication blockers that might prevent the hook from running smoothly.
Local Configuration and Deployment
On your local machine, add the server as a remote. Replaceuser@server_ip with your actual credentials:
git remote add production ssh://deployer@your_server_ip/srv/git/myproject.git
When you push to this remote, Git transfers the objects to the bare repo, triggers the hook, and the server updates the web root. Always test with a small change first. Verify that the files appear in /var/www/html and that old files are removed if deleted locally.
For advanced security, consider signing your commits. Setting up private GPG keys ensures that your team knows exactly who deployed what. See Secure Git Commits Server: Setting Up Private GPG Key with SSH Login for details on implementing cryptographic verification.
Troubleshooting Common Issues
If files are still missing, check the ownership of the web directory. Thedeployer user must have write access to /var/www/html. You can grant this by changing the group ownership of the web root to deployer and setting the setgid bit:
chgrp -R deployer /var/www/html
chmod -R g+w /var/www/html
Check the server logs for any errors generated by the hook. Since the hook runs in a limited environment, relative paths often fail. Always use absolute paths in your scripts. Additionally, verify that SELinux is not blocking the write operation. If SELinux is enabled, you may need to adjust the context of the web directory or disable enforcing mode temporarily for testing.
Finally, ensure that your local Git configuration matches the server expectations. If you are using different branches, update the hook to checkout the correct branch name instead of hardcoding master.
Frequently Asked Questions
Why are deleted files not removed from my web server?
The default git checkout command does not remove files that no longer exist in the latest commit. You must explicitly run git clean -fdx in your hook to purge untracked and ignored files before checking out the new code.
Can I use root permissions for the deployment user?
No, using root is dangerous and unnecessary. Create a dedicated user with minimal privileges and grant it specific write access to the web directory via group permissions. This limits potential damage from compromised keys or buggy scripts.
What if my hook fails silently?
Hooks run in a restricted environment and do not output to your terminal. Redirect stderr to a log file in your hook script, such as exec >> /var/log/git-deploy.log 2>&1, to capture errors for debugging.
How do I handle database migrations during deployment?
Git hooks are not ideal for complex multi-step deployments. Consider using a tool like Capistrano or Ansible that can orchestrate Git pulls alongside database schema updates and service restarts in a controlled sequence.
Is it safe to force checkout with -f?
Yes, within the context of a CI/CD pipeline, -f ensures consistency. It discards any local modifications in the working tree, which is desired behavior for automated deployments to prevent drift between the repository and the live server.