====== Git Triangular Workflow ======
The main characteristics of this workflow are:
* Develop changes on top of %%FreeBSD%% release branch, e.g. ''%%releng/X.Y%%''
* Publish these changes in a personal/corporate git repository for testing and use in production
* Once these changes have been tested and have matured enough, up-port them on top of HEAD for review
* Once review accepted, push them in HEAD
* Rebase changes that have not yet been accepted to old ''%%releng/X.Y%%'' branch to new ''%%releng/X.(Y+1)%%'' branch
For experimented git users (i.e. users that already fell in every git pitfalls) this workflow is common sense, but might help some to start %%FreeBSD%% contributions with a straightforward workflow.
{{gitworkflow/triangularworkflow/git-47.png}}
====== Introduction ======
This workflow assumes you use multiple repositories, i.e.:
* **origin repository**: Our own personal/corporate repository with full access, e.g. ''%%https://github.com/user/freebsd/%%''
* **upstream repository**: The official %%FreeBSD%% repository with read-only access, e.g. ''%%https://github.com/freebsd/freebsd/%%''
* **Main workflow rules being**
* Changes coming from ''%%upstream%%'' repository are merged
* Changes developed in ''%%origin%%'' repository are rebased
====== Local Git Repository First Steps ======
Clone personal %%FreeBSD%% git repository (can be empty at first)
$ git clone git@github.com:user/freebsd.git
$ cd freebsd/
Add %%FreeBSD%% upstream as remote repository and fetch changes
$ git remote add upstream git@github.com:freebsd/freebsd.git
$ git fetch upstream
* **Note**: ''%%$ git fetch upstream%%'' command will take roughly 5/10 minutes depending on our internet connection
====== Origin Repository Branches ======
Origin repository branches will look like:
8.3-next/
8.4-next/
10.0-next/
10.1-next/
10.2-next/
master
The ''%%X.Y-next%%'' branches are where changes/fixes are developed. These branches are created from corresponding upstream release branches ''%%releng/X.Y/%%'' from upstream repository. ''%%master%%'' branch is just ''%%CURRENT%%'', and used for review creation. See below how they are created.
====== Create a X.Y-next Branch and Publish it ======
Get last upstream changes
$ git fetch upstream
Create new ''%%X.Y-next%%'' branch from corresponding ''%%upstream/releng/X.Y%%'' release branch
$ git checkout -b 10.2-next upstream/releng/10.2
Publish branch to origin repository
$ git push -u origin 10.2-next
===== Checkout a X.Y-next Branch =====
If the ''%%X.Y-next%%'' is already present in origin repository:
$ git fetch origin
$ git checkout -t origin/10.2-next
====== Create master Branch and Publish it ======
Get last upstream changes
$ git fetch upstream
Create new ''%%master%%'' branch from corresponding ''%%upstream/master%%'' ''%%CURRENT%%'' branch
$ git checkout -t upstream/master
Publish ''%%master%%'' branch to origin repository
$ git push origin HEAD
====== Make and Publish Custom Changes in Origin Repository ======
Checkout ''%%X.Y-next%%'' branch and get last origin changes
$ git checkout 10.2-next
$ git pull --rebase
Make changes and locally commit them
$ vim foo/bar.c
# Hack, test, hack
$ git add foo/bar.c
$ git commit -m "[bz#42]: Fix this issue/Improve performances"
Once tested, rebase on top of last origin repository changes, and publish
$ git pull --rebase
$ git push origin HEAD
====== Merge Errata/Security Patches from Upstream ======
* **Note**: No Operating System is without sins, thus you need to merge Errata/Security patches from corresponding release branch in a timely manner
Checkout ''%%X.Y-next%%'' branch and get last origin changes
$ git checkout 10.2-next
$ git pull --rebase
Get last upstream changes and check the log for Errata/Security details
$ git fetch upstream
$ git log upstream/releng/10.2
Merge last upstream changes from corresponding release branch
$ git merge upstream/releng/10.2 -m "Merge Errata/Security from releng/10.2 into 10.2-next"
Resolve conflicts if any, than check the result
$ git log -p -m --first-parent
Publish merged upstream changes in origin
$ git push origin HEAD
Next you can update %%FreeBSD%% release number in ''%%release/Makefile%%'' and create your own tag for release/testing purpose. See below.
===== Create Tag and Publish it =====
$ git tag -a v10.2.4.0 -m "My FreeBSD Release 10.2.4.0"
$ git push --tags
===== Checkout a Tag =====
$ git checkout -t tags/v10.2.4.0
====== Rebase Custom Changes onto a New Release Branch ======
Get all origin and upstream repositories changes. For example to rebase your changes made in ''%%10.1-next%%'' to ''%%10.2-next%%''
$ git fetch upstream
$ git fetch origin
$ git checkout 10.1-next
$ git pull --rebase
$ git checkout 10.2-next
$ git pull --rebase
Start an interactive rebase for all changes made in ''%%X.Y%%'' to ''%%X.(Y+1)%%''
$ git rebase -i --onto 10.2-next upstream/release/10.1.0 10.1-next
* **Note**: See [[/Interactive rebase|https://help.github.com/articles/interactive-rebase]] documentation
* **Note**: Rebase is smart/dumb enough to skip all already accepted included the new ''%%X.(Y+1)-next%%'' branch
* **Note**: Rebase will skip all Errata/Security merge commits, this is the default behaviour and that you actually want as all Errata/Security changes are already in ''%%X.(Y+1)-next%%'' branch by definition of a %%FreeBSD%% release branch
During the interactive rebase you have in opportunity to:
* Remove now irrelevant changes
* Squash changes related to same fix/feature implementation in only one commit:
* Make things easier for future rebases
* Make history easier to read
* Cleaner patch for upstream proposal
* Re-order your changes
This is different workflow than the classical SVN vendor model merge workflow, here we want to see our changes always on top of the last release branch:
* Custom changes will appear clearly
* Custom changes will be on top the last release version, and be easier to propose them to upstream
====== Advantages/Disadvantages ======
===== Advantages =====
* Use of last release branch for stability
* Custom changes/fixed are used/tested in production before review
* No need to wait upstream acceptation before enjoying fixes and improvements
* These changes make great candidates for MFC (Merge From Current) once accepted in CURRENT
* Keep patches clean over new release branches
* The origin repository includes only the branches you are working on/you care about. It is not a full complete fork of the upstream repository
* Interface nicely with %%FreeBSD%% reviews (Phabricator/arc) (see below)
===== Disadvantages =====
* Development is not done in CURRENT
* Patches are “up-ported” to CURRENT once tested/have matured enough
* Patches are in two branches until accepted:
* ''%%X.Y-next%%'' (Release branch)
* ''%%feature-review%%'' (Branch for upstream review) (see below)
====== More Usages Examples ======
===== Creating a Review for CURRENT from X.Y-next branch =====
Checkout last changes from ''%%upstream/master%%''
$ git fetch upstream
$ git checkout master
$ git pull --rebase
Create review branch
$ git checkout -b feature-foo-review master
$ git push -u origin HEAD # It creates the base commit for the review
Cherry-pick changes related to "feature foo" from ''%%X.Y-next%%'' branch
$ git log origin/10.2-next # Note SHA strings of desired commits
$ git cherry-pick $SHA1 $SHA2
and create the review
$ arc which # Check that commit $SHA1 and $SHA2 will be part of the review
$ arc diff --create # Create review D1234
==== Update your Review ====
If during review changes are required, local commit the desired changes and include them in the review
$ vim foo/bar.c
# Hack, test, hack
$ git add foo/bar.c
$ git commit -m "Address comments from review D1234"
$ arc which # Check that all desired commits are part of the review
$ arc diff --update D1234
==== Rebase your Review on more Recent CURRENT ====
If the review takes a while, you can rebase your changes on top of the current master and update the review.
First get last upstream changes
$ git checkout master
$ git pull --rebase
Then rebase your changes on it
$ git checkout feature-foo-review
$ git rebase master
And update the review
$ git push origin master:feature-foo-review # Update the review base commit
$ arc which # Check that the review includes all desired commit changes, and only them
$ arc diff --update D1234
===== Cherry-pick Specific Commits from Upstream =====
Note: Sometimes You might want to get a change from ''%%CURRENT%%'' to your ''%%X.Y-next%%'' branch
Checkout ''%%X.Y-next%%'' branch and get last origin changes
$ git checkout 10.2-next
$ git pull --rebase
Get last upstream changes and check the log for the SHA of the desired commit(s) to cherry-pick
$ git fetch upstream
$ git log upstream/master
Cherry-pick desired changes from ''%%upstream/master%%''
$ git cherry-pick SHA
* **Note**: Where SHA is the SHA string of the commit to cherry-pick
Resolve conflicts and check result
$ git log -p
Publish cherry-picked changes to origin repository
$ git pull --rebase
$ git push origin HEAD