From 0c9c6acb19e5163113be79f06782e5810f01cb63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Tue, 20 Feb 2018 16:44:40 -0500 Subject: [PATCH] michal created page: Backporting a Merge Request --- Backporting-a-Merge-Request.md | 257 +++++++++++++++++++++++++++++++++ 1 file changed, 257 insertions(+) create mode 100644 Backporting-a-Merge-Request.md diff --git a/Backporting-a-Merge-Request.md b/Backporting-a-Merge-Request.md new file mode 100644 index 0000000..c709b91 --- /dev/null +++ b/Backporting-a-Merge-Request.md @@ -0,0 +1,257 @@ +# Backporting a Merge Request + +## Introduction + +When a Merge Request is merged into *master*, it may need to be backported to maintenance branches. As each Merge Request consists of multiple commits, backporting it to another branch without squashing boils down to: + +* cherry-picking the original commits comprising the Merge Request one-by-one on top of the target branch (i.e. the branch to which the Merge Request is being backported), +* creating a merge commit linking the previous HEAD of the target branch with the last cherry-picked commit, preferably retaining the commit log message from the original merge commit (e.g. to leave the Merge Request identifier intact for future reference). + +## `git-replay-merge` to the rescue + +### Overview + +A script called `git-replay-merge` was written to make backporting Merge Requests more convenient by automating the process as much as possible. + +### How it works + +The script can be thought of as a wrapper for `git cherry-pick` and `git merge` which cowardly interrupts its actions as soon as things go south. In short, the script: + +1. Detects the range of commits that needs to be cherry-picked. +1. Initiates the cherry-picking process on a throwaway local branch, called the replay branch below. +1. If conflicts arise while cherry-picking, you need to fix them yourself and let the script know when you are done. +1. Once cherry-picking succeeds, the replay branch is merged into a local branch with the same name as the target branch. Original merge commit log message with a modified subject line is used for the merge commit in the target branch. +1. The replay branch is removed. + +Summing up, given: + +* the ID of the merge commit in the "original" branch (i.e. the branch the Merge Request was merged into), +* the name of the git remote to ask about the target branch, +* the name of the target branch, + +the script prepares a local branch with the relevant Merge Request "replayed" for pushing. + +The script only prepares a branch for pushing; it is *not* pushed automatically. + +If at any point in the process the user decides the script should not continue its work, `git replay-merge --abort` can be used to restore the working copy to the state it was in before `git replay-merge` was called. + +### Installation + +To use the script, [download it](https://gitlab.isc.org/isc-projects/bind9/snippets/2/raw?inline=false) to your development machine, saving it as `git-replay-merge` somewhere in your `$PATH`. Subsequently running `git replay-merge` (without the first hyphen) should reward you with a usage message: + +```sh +$ git replay-merge +Usage: + + git replay-merge + git replay-merge --continue + git replay-merge --abort +``` + +### Example: the hard case (with conflicts) + +Let's take a deep dive first and imagine !22 needs to be backported to *v9_12*. + +#### Initial situation + +Git setup: + +```sh +$ git remote -v +gitlab git@gitlab.isc.org:isc-projects/bind9.git (fetch) +gitlab git@gitlab.isc.org:isc-projects/bind9.git (push) +... +``` + +Original branch (excerpt): + +```sh +$ git log --no-decorate --graph --oneline gitlab/master +... +* 3abc7bf264 Merge branch 'fix-loadpending-handling' into 'master' +|\ +| * 801dfe8f5d Add CHANGES entry +| * f5079bb877 Do not recheck DNS_ZONEFLG_LOADPENDING in zone_asyncload() +| * b9e9361c7b Asynchronous zone load events have no way of getting canceled +| * 29b7efdd9f Only clear DNS_ZONEFLG_LOADPENDING in zone_asyncload() if zone loading is completed immediately +| * 0e4fba2ced Lock zone before checking whether its asynchronous load is already pending +* | 883a9485e9 [master] copyrights +|/ +* 3548061d03 Merge branch 'gitlab-ci-keep-artifacts' into 'master' +... +``` + +Target branch: + +```sh +$ git log --no-decorate --max-count=1 --oneline gitlab/v9_12 +44d995992a Merge branch 'fix-cpp-check-errors' into 'v9_12' +``` + +#### `git replay-merge` session log + +```sh +$ git replay-merge 3abc7bf264 gitlab v9_12 +Attempting to replay 883a9485e95916a686e56d81fff5130ac3102953..801dfe8f5d69ccb1252fbc57e2feeed34a9a438c on top of gitlab/v9_12 in fix-loadpending-handling-v9_12... +Switched to a new branch 'fix-loadpending-handling-v9_12' +[fix-loadpending-handling-v9_12 6b5b0dcb94] Lock zone before checking whether its asynchronous load is already pending + Date: Thu Feb 15 20:31:49 2018 +0100 + 1 file changed, 5 insertions(+), 2 deletions(-) +[fix-loadpending-handling-v9_12 8c9de139df] Only clear DNS_ZONEFLG_LOADPENDING in zone_asyncload() if zone loading is completed immediately + Date: Thu Feb 15 20:31:51 2018 +0100 + 1 file changed, 4 insertions(+), 2 deletions(-) +[fix-loadpending-handling-v9_12 eb8de80fcd] Asynchronous zone load events have no way of getting canceled + Date: Thu Feb 15 20:31:53 2018 +0100 + 1 file changed, 1 insertion(+), 6 deletions(-) +[fix-loadpending-handling-v9_12 87ac04b893] Do not recheck DNS_ZONEFLG_LOADPENDING in zone_asyncload() + Date: Thu Feb 15 20:31:54 2018 +0100 + 1 file changed, 11 deletions(-) +error: could not apply 801dfe8f5d... Add CHANGES entry +hint: after resolving the conflicts, mark the corrected paths +hint: with 'git add ' or 'git rm ' +hint: and commit the result with 'git commit' +Replay failed. Cherry-picking needs to be completed manually. +When done, run "git replay-merge --continue". +Use "git replay-merge --abort" to abort the replay. +``` + +Oops, there is a conflict in `CHANGES`: + +```sh +$ git status +On branch fix-loadpending-handling-v9_12 +Your branch is ahead of 'gitlab/v9_12' by 4 commits. + (use "git push" to publish your local commits) + +You are currently cherry-picking commit 801dfe8f5d. + (fix conflicts and run "git cherry-pick --continue") + (use "git cherry-pick --abort" to cancel the cherry-pick operation) + +Unmerged paths: + (use "git add ..." to mark resolution) + + both modified: CHANGES + +no changes added to commit (use "git add" and/or "git commit -a") +``` + +Let's fix the conflict using an editor of choice. Once that is done, +cherry-picking can continue: + +```sh +$ $VISUAL CHANGES +$ git add CHANGES +$ git cherry-pick --continue +[fix-loadpending-handling-v9_12 b7a6e602e9] Add CHANGES entry + Date: Thu Feb 15 20:31:55 2018 +0100 + 1 file changed, 6 insertions(+) +``` + +With cherry-picking finished, it is time to poke `git replay-merge` to resume its work: + +```sh +$ git replay-merge --continue +Attempting to merge fix-loadpending-handling-v9_12 into v9_12... +Switched to a new branch 'v9_12' +Merge made by the 'recursive' strategy. + CHANGES | 6 ++++++ + lib/dns/zone.c | 29 +++++++++-------------------- + 2 files changed, 15 insertions(+), 20 deletions(-) + +Replayed fix-loadpending-handling onto v9_12. +To push the replay, use: + + git push gitlab v9_12:v9_12 +``` + +That's it, the replay is complete: + +```sh +$ git log --graph --oneline v9_12 +* 6801ed2c4f (v9_12) Merge branch 'fix-loadpending-handling-v9_12' into 'v9_12' +|\ +| * b7a6e602e9 Add CHANGES entry +| * 87ac04b893 Do not recheck DNS_ZONEFLG_LOADPENDING in zone_asyncload() +| * eb8de80fcd Asynchronous zone load events have no way of getting canceled +| * 8c9de139df Only clear DNS_ZONEFLG_LOADPENDING in zone_asyncload() if zone loading is completed immediately +| * 6b5b0dcb94 Lock zone before checking whether its asynchronous load is already pending +|/ +* 44d995992a (gitlab/v9_12) Merge branch 'fix-cpp-check-errors' into 'v9_12' +... +``` + +The branch is now ready to be pushed using the command suggested by `git replay-merge`. + +### Example: the easy case (no conflicts) + +With the pessimistic scenario sorted out, let's now try backporting !21 to *v9_12*. + +#### Initial situation + +Git setup: + +```sh +$ git remote -v +gitlab git@gitlab.isc.org:isc-projects/bind9.git (fetch) +gitlab git@gitlab.isc.org:isc-projects/bind9.git (push) +... +``` + +Original branch (excerpt): + +```sh +$ git log --no-decorate --graph --oneline gitlab/master +... +* 54823ea037 Merge branch 'fix-dnstap-output-file-rolling' into 'master' +|\ +| * 448eb98797 (gitlab/mr/21) Add CHANGES entry +| * 02063cbae2 Make dns_dt_send() call dns_dt_reopen() asynchronously +| * 8e3c16175a Make dns_dt_reopen() request task-exclusive mode on its own +| * f199a5a9ae Add dns_dt_create2() +|/ +* 522e5dd9bc 4893. [bug] Address various issues reported by cppcheck. [GL #51] +... +``` + +Target branch: + +```sh +$ git log --no-decorate --max-count=1 --oneline gitlab/v9_12 +fba6c2e982 Merge branch 'fix-loadpending-handling-v9_12' into v9_12 +``` + +#### `git replay-merge` session log + +```sh +$ git replay-merge 54823ea037 gitlab v9_12 +Attempting to replay 522e5dd9bc6df64bc2388e4056ff293377ef678c..448eb987970144461b264fe2f238c850a50090e4 on top of gitlab/v9_12 in fix-dnstap-output-file-rolling-v9_12... +Switched to a new branch 'fix-dnstap-output-file-rolling-v9_12' +[fix-dnstap-output-file-rolling-v9_12 4871445b5c] Add dns_dt_create2() + Date: Mon Feb 5 21:19:44 2018 +0100 + 3 files changed, 25 insertions(+), 2 deletions(-) +[fix-dnstap-output-file-rolling-v9_12 9cac22573b] Make dns_dt_reopen() request task-exclusive mode on its own + Date: Mon Feb 5 21:22:53 2018 +0100 + 3 files changed, 15 insertions(+), 6 deletions(-) +[fix-dnstap-output-file-rolling-v9_12 b4ace595e1] Make dns_dt_send() call dns_dt_reopen() asynchronously + Date: Mon Feb 5 21:04:39 2018 +0100 + 1 file changed, 93 insertions(+), 6 deletions(-) +[fix-dnstap-output-file-rolling-v9_12 6529f4d5b5] Add CHANGES entry + Date: Fri Feb 16 09:38:48 2018 +0100 + 1 file changed, 3 insertions(+) +Attempting to merge fix-dnstap-output-file-rolling-v9_12 into v9_12... +Switched to a new branch 'v9_12' +Merge made by the 'recursive' strategy. + CHANGES | 3 ++ + bin/named/server.c | 8 ++--- + lib/dns/dnstap.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- + lib/dns/include/dns/dnstap.h | 17 ++++++++-- + lib/dns/win32/libdns.def.in | 1 + + 5 files changed, 136 insertions(+), 14 deletions(-) + +Replayed fix-dnstap-output-file-rolling onto v9_12. +To push the replay, use: + + git push gitlab v9_12:v9_12 +``` + +That's it, the branch is all set for pushing.