We backport important fixes and improvements from the current master release to get them to our users faster.
We mostly consider bug fixes for back porting. Occasionally, important changes to the API can be backported to make it easier for developers to keep their apps working between major releases. If you think a pull request (PR) is relevant for the stable release, go through these steps:
Make sure the PR is merged to master
Ask the feature maintainer if the code should be backported and add the label backport-request to the PR
If the maintainer say yes then create a new branch based on the respective stable branch, cherry-pick the needed commits to that branch and create a PR on GitHub.
Specify the corresponding milestone for that series to this PR and reference the original PR in there. This enables the QA team to find the backported items for testing and having the original PR with detailed description linked.
|Before each patch release there is a freeze to be able to test everything as a whole without pulling in new changes. This freeze is announced on the owncloud-devel mailinglist. While this freeze is active a backport isn’t allowed and has to wait for the next patch release.|
The QA team will try to reproduce all the issues with the X.Y.Z-next-maintenance milestone on the relevant release and verify it is fixed by the patch release (and doesn’t cause new problems). Once the patch release is out, the post-fix -next-maintenance is removed and a new -next-maintenance milestone is created for that series.
Because pushing directly to particular ownCloud branches is forbidden
origin/stable-xx), you need to create your own remote branch,
based off of the branch that you wish to backport to. However, doing so
can involve a number of manual steps. To reduce the effort and time
involved, use the script below instead.
The script uses
|This script uses the github API. For unauthenticated requests, the rate limit allows for up to 60 requests per hour. Unauthenticated requests are associated with the originating IP address, and not the user making requests. Please see this link for more information about github rate limiting.|
|In case of conflicts, the script exits. The merge conflicts will need to be resolved before manually continuing the backport.|
#!/bin/bash if ! [ -x "$(command -v jq)" ]; then echo 'Error: jq is not installed.' >&2 echo 'Please install package "jq" before using this script' exit 1 fi if ! [ -x "$(command -v curl)" ]; then echo 'Error: curl is not installed.' >&2 echo 'Please install package "curl" before using this script' exit 1 fi if [ "$#" -lt 2 ]; then echo "Illegal number of parameters" echo " $0 <merge/commit-sha> <targetBranchName>" echo " For example: $0 1234567 stable10" exit fi commit=$1 targetBranch=$2 baseBranch=$(git rev-parse --abbrev-ref HEAD) is_merged=$(git branch --contains $1 | grep -oP '(?<=\*).*') if [ -z "$is_merged" ]; then echo "$commit has not been merged or branch $baseBranch is not pulled/rebased. Exiting" echo exit fi # get the PR number from commit pullId=$(git log $1^! --oneline 2>/dev/null | tail -n 3 | grep -oP '(?<=#)[0-9]*') # get the repository from commit repository=$(git config --get remote.origin.url 2>/dev/null | perl -lne 'print $1 if /(?:(?:https?:\/\/github.com\/)|:)(.*?).git/') # get the list of commits in PR without any merge commit # $1^ means the first parent of the merge commit (that is passed in as $1). # Because $1 is a "magically-generated" merge commit, it happily "jumps back" # to the point on the main branch just before where the PR was merged. # And so the commits from that point are exactly the list of individual # commits in the original PR. # --no-merges leaves out the merge commit itself, and we get just what we want commitList=$(git log --no-merges --reverse --format=format:%h $1^..$1) # get the request reset time window from github in epoch rateLimitReset=$(curl -i https://api.github.com/users/octocat 2>&1 | grep -m1 'X-RateLimit-Reset:' | grep -o '[[:digit:]]*') # get the remaining requests in window from github rateLimitRemaining=$(curl -i https://api.github.com/users/octocat 2>&1 | grep -m1 'X-RateLimit-Remaining:' | grep -o '[[:digit:]]*') # time remaining in epoch now=$(date +%s) ((remaining=rateLimitReset-now)) # time remaining in HMS remaining=$(date -u -d @$remaining +%H:%M:%S) # check if there are commits to cherry pick and list them in case if [[ -z "$commitList" ]]; then echo "There are no commits to cherry pick. Exiting" exit else lineCount=$(echo "$commitList" | grep '' | wc -l) echo "$lineCount commits being cherry picked:" echo echo "$commitList" fi if [ $rateLimitRemaining -le 0 ]; then # do not continue if there are no remaining github requests available echo "You do not have enough github requests available to backport" echo "The current rate limit window resets in $remaining" exit else # get the PR title, this is the only automated valid way to get the title pullTitle=$(curl https://api.github.com/repos/$repository/pulls/$pullId 2>/dev/null | jq '.title' | sed 's/^.//' | sed 's/.$//') fi # build names used targetCommit="$targetBranch-$commit-$pullId" message="[$targetBranch] [PR $pullId] $pullTitle" echo echo "Info:" echo "You have $rateLimitRemaining backport requests remaining in the current github rate limit window" echo "The current rate limit window resets in $remaining" echo echo "Backporting commit $commit to $targetBranch with the following text:" echo "$message" echo set -e git fetch -p --quiet git checkout "$targetBranch" git pull --rebase --quiet git checkout -b "$targetCommit" echo # cherry pick all commits from commitList lC=1 echo "$commitList" | while IFS= read -r line; do echo "Cherry picking commit $lC: $line" # if you do not want to use a default conflict resolution to take theirs # (help fix missing cherry picked commits or file renames) #git cherry-pick $line > /dev/null git cherry-pick -Xtheirs $line > /dev/null lC=$(( $lC + 1 )) done echo git commit --quiet --amend -m "$message" -m "Backport of PR #$pullId" echo "Pushing: $message" echo git push --quiet -u origin "$targetCommit" git checkout --quiet "$baseBranch"
|It is highly recommended to use the merge commit sha when backporting a Pull Request. The merge commit includes all PR sub commits to be backported. With that, no individual sub commit backporting is necessary.|
The following example assumes that:
You save the script in a file called
<path>/backport.shand mark it executable
You have checked out the branch containing the merged sha (like
Your merge sha = 1234567 and your target branch = stable10
The command to backport this Pull Request would be called as follows:
<path>/backport.sh 1234567 stable10 4 commits beeing cherry picked: 2e03d938 fef19729 61ac3f09 0528601f ... Switched to a new branch ‘stable10-1234567-34654‘ ... [stable10] [PR 34654] Each generated birthday or death event gets a new UID ... Cherry picking commit 1: 2e03d938 Cherry picking commit 1: fef19729 ... Pushing: ... ...
Please keep in mind that this is an example and you have to adapt the commit hash and the target branch accordingly.
The script also lists the quantity and commits to be backported and the current one in process. This can be helpful in case there is a conflict and you manually continue after the conflict has been resolved.
When the script completes, go to GitHub, where it will suggest that you make a PR from pushed branch. Even the script tries to automate, you may need to set the Pull Request title and description text manually via copy/paste.
Change the base branch to be committed against,
In case you have installed the
xdg-utils package, you can add at the
end of the script above following code which opens the PR to be
finalized in your browser. macOS does not need this package, use the
echo "Creating pull request for branch $targetBranch in $repository" xdg-open "https://github.com/$repository/pull/new/$targetBranch...$targetCommit" &>/dev/null
This command opens the Pull Request and sets the target branch
(in our example