Contents
- Git Triangular Workflow
- Introduction
- Local Git Repository First Steps
- Origin Repository Branches
- Create a `X.Y-next` Branch and Publish it
- Create `master` Branch and Publish it
- Make and Publish Custom Changes in Origin Repository
- Merge Errata/Security Patches from Upstream
- Rebase Custom Changes onto a New Release Branch
- Advantages/Disadvantages
- More Usages Examples
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.
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 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