pg TECHNICAL DETAILS ==================== This document is meant only for those already quite familiar with GIT. If you don't know what `HEAD` is or what the `refs` directory is then this document isn't for you. pg stores a cluster of GIT refs under `refs/pg-patches/`. The directory `refs/pg-patches/` will be created automatically whenever a pg command is executed on that branch. Within the branch directory pg constructs one directory per patch. The first character of a patch directory indicates the patch status: 'a' == applied, 'u' == unapplied. But since applying and unapplying a patch is more complex than just renaming a directory you shouldn't just change this character. :-) Patch directories are numbered. They are considered to be applied in lexographical order (hence the 4 digit padding at the front of the directory name). Don't reorder applied ('a*') directories behind pg's back. But reording unapplied ('u*') directories is ok; pg-push will push the unapplied patches in reverse order (u0009-a will push before u0002-b). The patch name is the stuff after the first '-' in the patch directory name. Changing this portion of a patch directory name is OK (for any patch status). `pg-rename` does just that. Within each patch directory pg stores a few ref files. These files are: - `base` : The commit object referenced by `HEAD` when `pg-new` was run or when this patch was last successfully pushed down with `pg-push`. This is the newest commit which is *not* a part of this patch. Its the base (or foundation) upon which this patch's changes are built. - `last` : The commit object referenced by `HEAD` when `pg-pop` was run against this patch or when `pg-push` was run for another patch being pushed down over this patch. This is the last commit object which *maybe* is part of this patch (see below about the case of `base` == `last`). - `z-last` : The value in `last` if `pg-push` failed for this patch. This is really a backup of `last` created by `pg-push` as it runs, just in case we can't push down cleanly. We don't want to lose the commit as we can't recover from that. :-) - `origin` : The very first value given to `base` and set when the patch was created with `pg-new`. This commit and its ancestors were never part of the patch. Even if `base` changes due to merging, `origin` doesn't. If `origin` == `base` then the patch was never merged; otherwise it was merged at least once (and maybe more than once). If `base` == `last` then the patch is empty. There are no changes contained within it. If `last` is an ancestor of `base` pg is going to be very lost. This should never happen. Don't try to make it happen. Given two patches A and B and both are currently applied (and were pushed in that order) `A/last` will always be `B/base`. That is the base of any given patch is always the last commit of the prior patch. The top-most currently applied patch will not have a `last` because its really whatever is currently in `HEAD`. (And if another GIT porcelain updates `HEAD` it won't know to update `last`, so we just don't keep it in pg.) Popping the top-most currently applied patch with `pg-pop` will copy `HEAD` to `last` then rewind `HEAD` to `last` of the prior applied patch or `base` if no such patch exists. Pushing a new patch down with `pg-push` copies `HEAD` to `last` in the prior patch (if it exists). Cloning a GIT repository with active patches just works. Since all metadata is just stored as object IDs under `refs/pg-patches` git-clone will happily duplicate this directory to the new clone and pg won't know the difference. (Compare with StGIT which loses its metadata during git-clone). When `pg-push` can't fast-forward the patch in place by just updating `HEAD` to `last` it will generate a two-way merge commit. The first parent of this commit is the value of `HEAD` at the time of `pg-push`; the second parent of this commit is the value of `last` of the patch being pushed. Not all changes referenced through `last` will be brought in during the merge; `pg-push` will actually only bring in changes between `base` and `last`; even if `HEAD` does not currently contain `base` (or its ancestors). This may create some somewhat confusing logs where it appears as though changes were deleted by the merge. It can look rather horrible in gitk.