Git /

Htdocs

Our current host setup runs all services and web applications on the same machine; we use no virtual machines or separate hosts for compartmentalization. As such, we manage a single web server deployment (OpenBSD httpd) with multiple third-party PHP applications living under one htdocs/ tree:

htdocs/
  wiki/      (PmWiki - wiki.sophia.host)
  market/    (OpenCart - market.sophia.host)
  bbs/       (phpBB - bbs.sophia.host)
  project/   (Kanboard - project.sophia.host)
  www/       (home page - sophia.host)
  doc/       (documentation - doc.sophia.host)

We use one Git repository that mirrors this entire server structure. We work as a team, with a remote repository (gitolite), and deployment is handled by a gitolite hook when master is pushed.

Our upstream relationship is tarball-based. We download vendor releases manually, extract them, and integrate them. We do not use git remote add upstream because these projects release as tarballs, not as Git repositories we can fetch from.

Branches

upstream
Branched from master, contain clean vendor code only. When a new vendor release arrives, we check out upstream, delete the old application files (rm -rf wiki/*), extract the new tarball, commit, and tag with the vendor version (e.g., pmwiki-2.5.7). No customizations are ever applied.
develop
Contains our live working tree with all customizations across all applications. This is where we edit core PHP files, add skins, modify configs, and do our actual work.
master
The stable, deployable branch. It accepts merges only from develop (via release branches) and hotfix branches. Each commit represents a tested, deployable state.

Upstream update

Our integration workflow is documented in tools/git.txt. When upstream updates, we:

  • Create a short-lived u-<app>-<version> branch from develop
  • Rebase it onto upstream to replay our local commits on the new vendor code
  • Resolve conflicts per-commit
  • Merge the result back to develop via --no-ff
  • Delete the u- branch

Our commit discipline: We aim for each commit to impact only one application. A single commit will not introduce changes to multiple web applications; for example, it will not touch both wiki/ and bbs/. This keeps history clean and makes rebase conflicts localized.

Our customization trajectory: We will edit core PHP files for bugfixes, feature additions, and structural changes. Gradually, if everything goes well, we may end up with a hard fork of some applications and stop using upstream entirely. For some time — possibly years — we will maintain a fork with a mix of all three types of changes.

Constraints

  • No submodules, no subtrees
  • No separate repositories per application
  • No package managers (composer, ports, etc.)
  • Tarball-based upstream workflow
  • One repo matching our deployment structure exactly
  • Core file edits are intentional and will increase over time
  • Git history must reflect what actually happened
  • rerere is enabled globally for conflict-resolution memory
  • Deployment is automated via a gitolite hook on master push

The workflow in tools/git.txt aims to give the team a consistent procedure. We want to ensure that:

  • The documented workflow aim at not silently lose work
  • The branch topology and merge/rebase strategy are correct for our constraints
  • The documentation is clear enough for team members to follow without constant supervision

Improvements

Proposed improvements.

Upstream branches

Each vendor application releases on its own schedule. PmWiki might ship 2.5.7 today while OpenCart ships 4.1.2 next month. If you keep all vendor code in a single upstream branch, you are forced to update every application simultaneously, or you end up with a single branch that contains a mix of unrelated vendor versions and tags (pmwiki-2.5.7, opencart-4.1.2, etc.) in the same timeline. This makes it impossible to know which upstream commit represents the baseline for any given application, and git rebase --onto becomes ambiguous.

One upstream-<app> branch per vendor tree (e.g., upstream-wiki, upstream-market) keeps vendor histories isolated. Each branch contains only the clean vendor tree for that application, tagged independently. The u-<app>-<version> workflow is repeated per branch without cross-contamination.

Upstream workflow

The problem: git rebase rewrites history. If Alice pushes a rebased u-pmwiki-2.5.7, and Bob pulls it and tries to add a fixup commit, he is fine. But if Alice or Bob tries to rebase that branch again to "fix" something, they must force-push, and everyone else's local copy of the branch diverges. Rebase is inherently a single-user operation.

The solution: Treat the u- branch as a shared integration branch, but perform the rebase locally before pushing it.

Integrate the new upstream into develop. One team member performs
the rebase locally; the u- branch is then pushed for team review
and fixups. Never rebase a pushed u- branch.

___________________________________________________________
$ git checkout -b u-pmwiki-2.5.7 develop
$ git rebase --onto upstream pmwiki-2.5.2 u-pmwiki-2.5.7
___________________________________________________________

Push the rebased branch so the team can test and commit fixups.
___________________________________________________________
$ git push -u origin u-pmwiki-2.5.7
___________________________________________________________

Team members check out the branch, test the integration, and
commit fixes directly to it. Do not rebase it again.
___________________________________________________________
$ git checkout u-pmwiki-2.5.7
$ git commit -m "Fix skin paths after pmwiki-2.5.7 update"
$ git push origin u-pmwiki-2.5.7
___________________________________________________________

Merge into develop when the integration is stable.
___________________________________________________________
$ git checkout develop
$ git merge --no-ff u-pmwiki-2.5.7
$ git branch -d u-pmwiki-2.5.7
$ git push origin :u-pmwiki-2.5.7
___________________________________________________________