Skip to content
pb-diff Help

Three-way merge

A three-way merge answers the question a source-control merge asks: two developers started from the same object and each changed it. What does the combined version look like? You give it File1, File2 and the Base both came from, and it produces a merged Base. Your first three-way merge walks through one.

Choosing the three files

Choose Compare ▸ New Comparison, then select Three-way merge. New Comparison shows File1, Base and File2. Type the paths, browse for them, or drop three files onto the dialog; the button with the two arrows between two rows swaps them. Dropping three files onto the window opens New Comparison in its three-way mode with the three filled in, so that you can check which is the Base before the merge starts. The command line does the same without the dialog: -Mode ThreeWay -File1 … -Base … -File2 ….

An object that lives in a library is given as container!entry (old.pbl!w_main.srw): Browse to the library and choose it with the Object… button that appears beside the path, as Select PB Object describes, or type or paste the address. A merge therefore does not have to start by exporting three objects. All three inputs must be source files or all three must be objects selected from libraries, and they must be of the same type: three windows, or three DataWindows, not a window and a user object. The dialog says so before anything is parsed.

The files are fixed when the merge opens, as they are in a two-way compare: the tab names them over their three columns, F5 compares the same three again, and other files are a new comparison. When you have decisions that are not saved yet, F5 asks before discarding them, and so does closing the tab.

When the Start-up sheet is set to a three-way merge, pb-diff starts on the three files of your last merge, as long as Automatically load last three-way compare is on in Options. If all three are still where they were, the compare runs straight away. Otherwise New Comparison opens, set to three-way and filled with what was remembered: a path that has since moved or gone is left exactly as it was remembered, the status bar names it, and nothing is compared until you correct it. pb-diff never substitutes another file for one that has gone. Paths you supply yourself, on the command line or in the dialog, always win.

Reading the tab

One hierarchy tree is shared by all three files, and it carries two icon rails: the left rail shows what File1 changed relative to the Base, the right rail what File2 changed. A node with a marker in both rails is one that both sides touched, which is where a conflict may be waiting. A node neither side changed has empty markers, so that names stay in line with their siblings, except the file's row and a group's, whose names start where the markers would.

Beside it, the three versions are shown side by side, each once: File1, the Base and File2, in three columns lined up on the Base. A line one side changed sits on the same row as the Base line it replaced, and lines only one side inserted leave an empty space in the other columns, so the three versions never drift apart. File1 and File2 are coloured by what they changed against the Base, and the Base by the change a side made to it. A row both sides changed differently, which is a conflict, carries a rule down the left edge of all three columns. Selecting a content node, a structural parent or the root follows the same exact-source rule as a File Compare, for both comparisons against the Base.

Underneath, across the full width, is the Merged element: the merged text of the action selected in the list; Save writes the whole object. Above it, a line names the merge target, and below it is the Merge Actions list. Every division here is a splitter you can drag: between File1 and the Base and between the Base and File2, between the three versions and the merged pane, between the merged pane and the actions list, and between the tree and all of them. Dragging the line between two versions moves width only between those two, and the three stay aligned row by row; double-click it, or choose View ▸ Equal Column Widths, to put them back to equal widths, and from the keyboard Ctrl+Shift+← and Ctrl+Shift+→ move the line beside the column the caret is in, as in a File Compare.

pb-diff three-way merge of n_pricing after Auto Merge. The function of_discount is selected and marked in both change rails of the shared tree. File1, the Base and File2 are shown side by side, lined up on the Base, with the conflicting line marked across all three: one side set the rate to 0.06 and the other to 0.07; the merged result below is highlighted as a conflict; and the Merge Actions list, whose rows each carry Take from Left, Keep Base and Take from Right buttons, shows of_discount as a conflict and of_shipping resolved automatically from File2.
Both sides changed the discount rate for orders of 500 or more in n_pricing. One tree serves the three files; its two rails show which side changed what, and the Merge Actions list shows the conflict still open after Auto Merge. Select the image to view it at full size.

The Merge Actions list

The list tracks every tree-level change that must be carried into the Base. Its Kind column holds one of exactly three words:

Kind What it means
To apply Only one side changed this item, or both changed it identically, or both changed it in places that do not overlap. There is no decision to make, so Auto Merge can apply it.
Conflict File1 and File2 both changed the same line or lines, differently; or one side deleted the item, or the control or XML element it is in, and the other changed or added it. There is no correct answer that pb-diff can derive, so this one is yours.
Resolved An action you have since settled. It started as one of the two above and is no longer waiting for you.

Above the list, a line says what to do next and keeps count as you go: how many changes Auto Merge can still apply, how many conflicts wait on their rows, then Save. After every decision the status bar says how many actions are still to decide. When none is left, the line turns green and says All actions are resolved , and only saving remains.

The merge commands

All four live under Compare ▸ Merge, and all four are in the tool bar while a three-way merge is the tab in front, as Auto Merge, Take Left, Keep Base and Take Right. The three decisions are also on every row of the list, as the buttons under Left, Base and Right and on its right-click menu. A row's buttons always decide that row's whole item. Auto Merge is not on a row, because it acts on the whole merge:

Command What it does
Auto Merge Applies every action whose Kind is To apply in one step and leaves the conflicts alone.
Take from Left Brings File1's version of what is selected into the Base.
Take from Right Brings File2's version into the Base.
Keep Base Leaves the region as the Base has it, which resolves a conflict by declining both sides.

On a typical merge, the actions Auto Merge can apply are most of the list, and running it first is the right way to start: run it, then deal with what is left. Everything it inserts is marked with the Edited marker and an edited background, so the merged file tells you which of its parts were produced by the merge rather than inherited from the Base.

A whole item or one block

With a node selected in the hierarchy tree, Take from Left and Take from Right bring that whole item into the Base, as it stands; line-level detail is not consulted. This is what you want for a function only one side touched, or one whose two versions are different enough that merging them line by line makes no sense.

Click a coloured row in the File1 or File2 column and the same two commands work at the level of one change block: take this block from that side into the Base. A click in the Base column points at the side that changed that line. The merge target line names the target, for example Merge target: wf_load — change block 2 of 5, from File1, so you can check what the next command will do before running it. Click a row both sides agree about and it goes back to naming the whole item.

A block belongs to the side it was clicked on, so Take from Left after clicking in the File2 column is a decision about the whole item; the block number means nothing on the other side. Blocks compose from the Base rather than on top of one another, so taking one block from each side is exactly that, and answering the same region twice replaces the first answer instead of inserting the region twice. Use them when both sides changed the same function in different places.

Editing the merged text

The merged pane shows the element selected in the list or the tree. Select the object or a group such as Functions and it shows the merged text of everything under it, read only, so the whole merge can be read before it is saved; select an item under it to edit.

The merged pane of an item is editable at all times. When neither side's version is what you want, which is the usual outcome of a genuine conflict, where the correct code is a combination of both, type it. Every line that differs from the Base uses the edited background and has a marker bar on its left, whether it was taken from a side, applied by Auto Merge or typed by hand, so you can identify the merge's work without another comparison. Edit ▸ Undo and Edit ▸ Redo act on the script that has focus, without changing your work in other scripts.

Conflicts

An unresolved conflict stays marked across the three versions and in the merged pane until you resolve it, so it cannot be lost by scrolling past it. Resolve it by taking one side's block, by taking an item wholesale, by keeping the Base, or by editing the merged text.

An event or a property block belongs to its control, and an XML element to the element it is in. If you keep one while the merge leaves out its control or element, the merged file has no place for it: it is left out, and the save says so among its warnings. Take the control or element as well to keep both.

pb-diff never writes conflict markers such as <<<<<<< into the merged file. Those markers are not valid PowerScript and would stop the export from importing. If you save while conflicts remain, pb-diff asks whether to save a partial result; choose No to return to the merge without writing a file.

pb-diff three-way merge of n_pricing after the conflict in of_discount was resolved by taking File2's version: the merged result shows the 0.07 rate highlighted, both rows of the Merge Actions list read Resolved, a banner above the list says all actions are resolved and the result can be saved, and the tool bar carries a Save button.
The conflict was resolved with the Take from Right button on its row. Every action is resolved, the list says only saving is left, and the merged file has been saved. Select the image to view it at full size.

Filtering and navigation

Only Changed Items and Only Changed Lines work exactly as they do in a two-way File Compare: the first hides unchanged nodes, the second folds unchanged runs of text to a placeholder saying how many lines it hides. They are the same two commands on the same View menu and the same two tick boxes in the tool bar. A merge opens with Only Changed Items on, so the tree holds what a side changed and the nodes above it; three files with nothing changed keep their whole tree. A folded run opens on a click, or move onto the placeholder with ↑ and ↓ and press Enter or Space. Folding never changes what the merge writes.

The four navigation commands on the Navigate menu (Alt+←, Alt+↑, Alt+↓, Alt+→) walk the changes of both sides in order: every change inside the action on show, taken in Base order whichever file made it, and then on to the next changed action. They are also the last four buttons this tab puts in the tool bar, the same group in the same place as in a two-way compare. The status bar shows Changed item 4 of 17 and, beside it, Change 2 of 6, which shows where you are inside the current action.

Compare Current Line (Ctrl+L) sends the line the caret is on to a Line Compare tab, against the Base: File1's version in File1's column, File2's in File2's, and in the Base column the version of the side that changed that line. Double-clicking a line does the same thing.

Saving

Save, in the tool bar or as File ▸ Save (Ctrl+S), writes the merged Base as a PowerBuilder export file, ready to be checked in. The dialog opens in the Base's folder and proposes the Base's name with .merged before the extension: n_pricing.sru becomes n_pricing.merged.sru, so the Base stays as it is unless you choose its name. For a Base inside a library the name is the entry's, and the folder is the library's. When pb-diff was started with -Save, that file is written without asking. Close the tab when you are done.

The file is written the way every merge writes one: UTF-16LE with a byte-order mark and CRLF, the form the Library painter writes and the same one pb-diff-cli merge3 produces, or UTF-8 when the Base is a PowerBuilder 2025 Solution source. A build file, an INI, XML or text file keeps the encoding it was read in. A control merged in brings its create call, its destroy call and its place in the control list with it; its declarations are actions in the list like any other, and yours to merge. See How merging works.

pb-diff does not compile the result. Import it into a scratch target and build it before you rely on it. Importing merged output is supported for PowerBuilder 19 and later; it is unverified for versions 10 to 18.

The headless equivalent is pb-diff-cli merge3; see Automate with pb-diff-cli.