Publish to remote directories using git
+ ssh
.
Quickstart
-
Initialize a publish repository. This creates a bare repository on
host
atremote_path
and clones it tolocal_path
(default./<remote_name>
). It also creates an initial commit with the message 'Init Version 0'.$ git publish init <host>:<remote_path> [local_path]
-
Add a publish worktree. This creates a directory on the publish server (default
origin
) that will stay in sync with a branch (defaultmain
orinit.defaultBranch
if set).$ git publish worktree <remote_path> [local_path]
-
Edit files, and publish to a remote repository (default
origin
). An optional commit message can be used instead of the default. A custom commit message has to be set only once, as if no message is given the last commit message is used with an incremented version number.$ touch index.html $ git publish [-m "Custom Message"]
Setup
Currently, the required software has to be installed manually.
A install script is provided to install git-publish
and it’s documentation.
Requirements
Only a few common programs are required to use git-publish
. They can
typically be installed with your distro’s package manager.
git
-
git is required for, well, the
git
command. It’s required to be installed on both your local machine and the remote server. ssh
-
ssh is required for running commands on the remote server and pulling from git repositories. It will also need to be installed on both the local machine and the remote server. The remote server should be running an ssh server that is accessible from the local machine.
bash
-
Currently, the
git-publish
script uses a few "bashism"s, it is not guaranteed to run in other shells. Because of this,bash
is listed as a requirement, however it may work in others.
Installing git-publish
git-publish
is available on github. Clone the repo
to get started, then chose from an automatic install script or manual
installation of the software.
Installation script
An installation script is provided that copies the needed files to the
appropriate directories. You can run this script with make using make install
or run the script independently with ./install.sh
.
The script will prompt for you to choose a directory on your $PATH to copy the
git-publish
script to. It will the copy the git-publish.1
man page to the
first path returned from the manpath
command. You will need write access to
both directories!
$ sudo make install [sudo] password for user: Select an install directory on your $PATH: (1) /usr/local/bin [default] (2) /usr/bin (3) /bin (4) /usr/local/sbin (5) /usr/lib/jvm/default/bin (6) /opt/microchip/xc8/v2.40/bin (7) /home/user/.local/bin/ Input a number (enter for default): Installing 'git-publish' to '/usr/local/bin' -- success Installing 'docs/git-publish.1' to '/usr/local/man' -- success Successfully installed git-publish.
Manual Installation
To install the git publish
command manually, simply place the script
somewhere it is available on your $PATH and mark it executable.
$ cp git-publish ~/.local/bin $ chmod a+x ~/.local/bin/git-publish
Alternatively to stay up-to-date with the latest release, link directly to the git repository. It’s recommended to checkout a tag or a commit in this case.
$ git checkout --detach main $ ln -s git-publish ~/.local/bin $ chmod a+x git-publish
Additional Considerations
.git
Because we create a linked worktree to an existing repo, .git
is a file
that contains a path to the common repo. This might expose sensitive
information e.g. if serving the directory with a web server. An example .git
created with the publish command contains the following:
gitdir: /git/website.git/worktrees/example
Linux File Permissions
The ssh user that you use to connect with git needs to have write permissions
to both the bare repository and the publish directory. An example setup is
a publish
group that has rwx permissions to each parent directory.
The example below will give the git
user appropriate permissions to push to a
repository at <server>:/srv/git/example.git
and publish files in
/srv/publish/example
. Additional users can be granted permissions by adding
them to the publish
group.
# mkdir /srv/git /srv/publish # groupadd publish # chgrp publish /srv/git /srv/publish # chmod g+w /srv/git /srv/publish # usermod -aG publish git
Alternatively, you could just work in the user’s home directory:
$ mkdir ~/git ~/publish
git publish requires absolute paths for all arguments that take a path.
|
SSH Host
The publish server is required to be accessible over ssh. This means we have to
authenticate with it somehow, however, most of the time it is recommend to
disable password logins for security. The easiest way to authenticate using a
key pair is by installing the needed key to your ssh-agent
. This also means
you won’t have to type in any passwords to login to the publish server.
Sometimes, you may not have an ssh-agent running or maybe you are running the
server on a non-standard port. These situations require you to configure the
ssh connection. The current recommended way to do this is by editing
~/.ssh/config
and configuring a custom host for your ssh server. An
example of one such host is given below:
Host <custom-host> Hostname <ip> Port <port> User <user> IdentityFile <path/to/private_key>
All configuration options are optional, just use what you need to change from
the defaults. You can now use <custom-host>
as a hostname like:
$ git publish init <custom-host>:/path/to/repo.git
Usage
The basic workflow this suits is to keep a remote directory in sync with one on your local machine. It achieves this by pushing a local repository to a remote repository over ssh. This means an intermediate git host such as Github is not required. A git server hook that fires after a successful push is used to trigger a force checkout of the main branch for every published worktree on the server. These worktree directories contain a copy of the latest committed files.
Initialize Publish Repository
When you initialize a repository with the git publish init
command, it does
three main things:
-
Creates a bare repository on the given host and installs a post-receive hook.
-
Initializes a local repository and adds the remote as origin.
-
Creates an empty commit and pushes it to the configured branch.
Let’s initialize a publish repository on example.com
. We’ll call it website
.
$ git publish init example.com:/git/website.git Connecting to server: example.com Repo: /git/website.git [email protected]'s password: Initialized empty Git repository in /git/website.git/ Find this repo at: example.com:/git/website.git Cloning into local directory: website/ Initialized empty Git repository in /home/user/website/.git/ [main (root-commit) aa3d154] Init Version 0 [email protected]'s password: Enumerating objects: 2, done. Counting objects: 100% (2/2), done. Writing objects: 100% (2/2), 170 bytes | 170.00 KiB/s, done. Total 2 (delta 0), reused 0 (delta 0), pack-reused 0 To example.com:/git/website.git * [new branch] main -> main
This created two repositories: /git/website.git
on our server and
website/.git
on our local machine.
Inside of our local repo, if we run git remote get-url origin
(or whatever
you set the remote to be) we can see it is set up to push/pull from
example.com:/git/website.git
. The git-publish command just runs a git init
and then git remote add
to setup the local repository. It then creates an
empty commit and pushes it to the remote with the message 'Init Version 0'.
This empty commit can be viewed as the 'creation' commit.
In our server repo, the only interesting thing you will find is a shell script
post-receive
that gets installed in <repo>/hooks/
e.g.
example.git/hooks/post-receive
in the case of the example above. This script,
which runs after a successful push, simply finds all *.publish files in the
hooks/ directory and executes them. Other than this simple one-line script, the
bare repository is bog standard.
Create Publish Worktree
The worktree(s) that hold the actual published files are created with the
git publish worktree
command.
Let’s create a publish worktree on example.com
at /var/www/website/
. Note
how we don’t have to specify a host like example.com
, it is extracted from
the configured remote (default origin
).
$ git publish worktree /var/www/example Using remote 'origin' @ example.com:/git/website.git Creating publish worktree: /var/www/example [email protected]'s password: Preparing worktree (detached HEAD cf7f00d) HEAD is now at cf7f00d Init Version 0 Successfully created worktree: /var/www/example
This created a new linked worktree at /var/www/example
and checked out the
latest commit in the configured branch. If you haven’t yet published any files,
the directory will be empty except for the .git
file. Refer to the
.git section in Additional Considerations for info about this file.
This command also places a .publish
script into the common repository’s
hook/
directory. This script contains the worktree path and the branch to
stay up-to-date with. The file is named after the worktree path, so the
example worktree’s script would be var-www-example.publish
. This script gets
run on every successful push and checks out the latest commit in the configured
branch. There is currently no way to change the branch a worktree tracks.
Publish Files to Worktrees
Files are published to remote worktrees with the git publish
command. Most of
the time, no arguments are required.
Let’s publish an index.html
to our /var/www/example/
.
$ touch index.html $ git publish index.html Publishing files: index.html Using default commit message: Publish Version Using default version: 1 [main 3e9a0d8] Publish Version 1 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 index.html [email protected]'s password: Enumerating objects: 3, done. Counting objects: 100% (3/3), done. Delta compression using up to 4 threads Compressing objects: 100% (2/2), done. Writing objects: 100% (2/2), 259 bytes | 259.00 KiB/s, done. Total 2 (delta 0), reused 0 (delta 0), pack-reused 0 remote: Updating worktree: /var/www/example remote: HEAD is now at 3e9a0d8 Publish Version 1 To example.com:/git/website.git cf7f00d..3e9a0d8 main -> main Published Version: 1
This published the specified files, and then checked out the commit in the
remote worktree. Because this was our first commit (the previous commit’s
version was 0) and no message was specified with -m
, the commit message
defaults to 'Publish Version' plus the version appended to the end. Note how
this changes in the example below.
Now, let’s add some error pages.
$ touch 404.html 403.html $ git publish Publishing directory: /home/user/website Using last commit message: Publish Version 1 Incrementing commit version: 1 + 1 [main 3e9a0d8] Publish Version 2 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 404.html create mode 100644 403.html [email protected]'s password: Enumerating objects: 3, done. Counting objects: 100% (3/3), done. Delta compression using up to 4 threads Compressing objects: 100% (2/2), done. Writing objects: 100% (2/2), 259 bytes | 259.00 KiB/s, done. Total 2 (delta 0), reused 0 (delta 0), pack-reused 0 remote: Updating worktree: /var/www/example remote: HEAD is now at 3e9a0d8 Publish Version 2 To example.com:/git/website.git cf7f00d..3e9a0d8 main -> main Published Version: 2
Since we didn’t specify any files to publish, it publishes every file in the directory. No commit message was specified, so it defaults to the last commit message with an incremented version number.
Existing Repositories
The publish
command works on any existing git repository.
The publish worktree
command works on repositories that are configured to use
an ssh remote and you have general SSH access to the server hosting the
repository. Note this means it will not work on hosted git solutions e.g.
GitHub.
When the repository already exists on the host, you should use the publish hook
command to update worktrees automatically. This command installs a post-receive
hooks that gets run after every commit. After the hook has been installed, you
can commit and push as normal and any worktrees that have been created will be
updated.
$ git publish hook example.com:/git/website.git Connecting to server: example.com Repo: /git/website.git Installed post-receive hook: /git/website.git/hooks/post-receive
git-publish(1)
Synopsis
git publish [init|worktree|hook] [-r remote] [-b branch] [-m message] [files|host:remote_path|remote_path] [local_path]
git publish [-r] [-b] [-m message] [files]
git publish init [-r] [-b] host:remote_path [local_path]
git publish worktree [-r] [-b] [-d] remote_path
git publish hook host:remote_path
Options
All commands accept some common configuration options in case you’d like to change the defaults. All dashed arguments should come before any positional arguments and after the subcommand.
- -r remote
-
The name of the remote to perform the publish operation on. (Default origin)
- -b branch
-
The name of the branch to perform the publish operation on. (Default main or init.defaultBranch if set)
Commands
When run with no arguments, it will publish all files in the repository to
<remote>/<branch>. Any worktrees that are on <remote> and are configured to
track <branch> will get updated.
Note that all remote_path arguments MUST be absolute paths.
- publish [<options>] [files]
-
Publish files to <remote>/<branch>. Any worktrees that have been created on origin will be updated.
- -m message
-
Commit message to use. If no version is found in the message, one will be appended to the end. (Default: Last commit if exists, else "Publish Version")
- files
-
List of files to publish. (Default: -A All files)
- publish init [<options>] host:remote_path [local_path]
-
Initialize a repository on host at remote_path and link it with local_path.
- host
-
Remote host url. Accepts [user@]host and ssh://[user@]host[:port] formats.
- remote_path
-
Absolute path of the bare git repository on host. e.g. /git/something-like.git
- local_path
-
Optional path to the local repository. (Default: Create a directory with the remote repository’s name e.g. ./something-like/)
- publish worktree [<options>] remote_path
-
Create a new worktree on <remote> at remote_path that gets updated on every push to <branch>. If the -d flag is specified, delete an existing worktree.
- -d
-
Delete an existing worktree instead of creating a new one.
- remote_path
-
Absolute path of worktree on the remote.
- publish hook host:remote_path
-
Installs a post-receive hook to remote_path on host. This allows publish worktrees to be created on an existing repository. Note that this command can be run from anywhere.
- host
-
Remote host url. Accepts [user@]host and ssh://[user@]host[:port] formats.
- remote_path
-
Absolute path of the bare git repository on host. e.g. /git/something-like.git
Exit status
- 0
-
Success.
The program thinks everything was successful (you be the judge). - 1
-
Error.
An error occurred, probably an invalid argument or git operation.
github | documentation
© 2022-2024 Rex McKinnon