23 Dec 2025
I have recently moved away from Github to Codeberg. This was a very smooth transition, migrating all my repos over, and starting my development there. I also decided to use Codeberg Pages to host this site, after a bit of wrestling with HTML and CSS only I decided to try Jekyll as a Static Site Generator (SSG). It made reusing sections and managing page styles very simple. There is a difference with Github and Codeberg Pages.
Jekyll has built in support for Github pages and is the recommended way to produce a page. Codeberg doesn’t have this functionality, and doesn’t have a Github Actions equivalent without requesting access to the Codeberg CI.
I had 2 options, find a way to get this linked up correctly or find a new way to create my site. I really liked jekyll for how simple it was to load pages in, the number of examples on Github already and the ability to write in markdown and move it over to a web format. I did manage to find a way to do it that involved multiple git repos connected up and managed independently.
This guide does assume familiarity with Codeberg, git and Neovim.
To get started you will need to create 2 new repositories on Codeberg. One needs to be called ‘pages’. This will be the page that Codeberg uses to display at [codeberg-username].codeberg.page. The other repository can be named anything, I named mine pages-generator, it will be used to store the actual workings of Jekyll.
Once this is done, create your Jekyll project in your local directory. A step by step guide on Jekyll can be found here.
In the new folder with your Jekyll code create a new git remote to your main repository. You can use
git init
git add remote origin ssh://git@codeberg.org/<codeberg-username>/pages-generator.gitOnce you have made your changes are are happy with the way your Jekyll site looks. Running
jekyll buildwill take your Jekyll files and generate a folder titled _site.
Within this folder you can repeat the process above with
git add remote origin ssh://git@codeberg.org/<codeberg-username>/pages.gitAt the end of this, you should have a folder structure like the one below:
|
├── index.html
├── .git -> pages-generator git repo
├── _site
│ └── .git -> pages git repo From here, you can just keep updating your model as is. When you make any changes you just need to push from the root, then into _site and run push again from there.
Although this isn’t that difficult, I knew I would forget to do both each time. Why would I do the same 8 commands in row each time when I can create a shortcut to do it for me.
In order to marginally speed up releases I created git-pusher.nvim. A very simple neovim plugin that lets you push to git. This creates a function that opens a window to accept a commit message before opening a terminal within Neovim and running a sequence of git commands to push both the generator and page into my codeberg repositories.
The bulk of the work is done in this block of code. This stores any data we need, creates floating windows and on pressing enter calls a function. This allows us to use the same code any time we want to create a window and take a message into the function. call_function allows us to pass this in as a function to be used, in this case, this is all of our git commands.
local function create_push_message(title, call_function)
-- store the original window this is being run from to go back on finish.
local curr_win = vim.api.nvim_get_current_win()
-- create entry window and go to insert mode
local buf, win = create_floating_window(title)
local keymap_opts = {
buffer = buf,
}
vim.cmd('startinsert')
local text
-- on pressing enter, close the window, push the text into our git function.
vim.keymap.set('i', '<CR>', function()
-- lua starts at 1!
text = vim.api.nvim_buf_get_lines(buf, 0, -1, false)[1]
vim.api.nvim_win_close(win, true)
call_function(text)
-- go back to the original window making it seamless.
vim.api.nvim_set_current_win(curr_win)
vim.cmd('stopinsert')
end, keymap_opts)
endNow we have the part that manages all the windows we just the function that tells the terminal how to manage with git. This is just a set of terminal commands that do standard git functions in the correct order. vim.fn.chansend just pushes the command into the terminal id we have opened.
local function git_push_pages(msg)
open_terminal()
vim.fn.chansend(job_id, { 'jekyll build\r\n' })
vim.fn.chansend(job_id, { 'git add .\r\n' })
vim.fn.chansend(job_id, { 'git commit -m "' .. msg .. '"\r\n' })
vim.fn.chansend(job_id, { 'git push -u origin main\r\n' })
vim.fn.chansend(job_id, { 'cd _pages\r\n' })
vim.fn.chansend(job_id, { 'git add .\r\n' })
vim.fn.chansend(job_id, { 'git commit -m "' .. msg .. '"\r\n' })
vim.fn.chansend(job_id, { 'git push -u origin main\r\n' })
vim.fn.chansend(job_id, { 'cd ..\r\n' })
vim.api.nvim_win_close(term_win, true)
endFinally, we just need to make a keymap to call this. In this case I have used gpc [G]it [P]ush [C]odeberg. This checks to make sure I am in the right directory to prevent it from erroring. It returns doing nothing if the location is incorrect.
vim.keymap.set('n', '<leader>gpc', function()
local cwd = vim.uv.cwd()
if cwd ~= "/home/paul/projects/pages" then
print("incorrect location to use this.")
return nil
end
create_push_message(" Add Commit Message ", git_push_pages)
end)NOTE:
If you move to a new laptop or operating system (I now use Arch BTW), and want this to work, you need to rungit clone ...on the SSG repo first. Then take within that, rungit cloneon the actual pages location within. Once this is done, usemv pages/ _site/to get it correctly set up for Jekyll, and you should be good to go! —
The plugin is very simple for now, and just pushes a single repo or a Jekyll page. To improve going forwards I could do the following: