public boolean merge(AddressSetView p1MergeSet, ProgramMergeFilter filter, TaskMonitor monitor)
			throws MemoryAccessException, CancelledException {
		clearMessages();
		merger.clearMessages();
		merger.clearDuplicateSymbols();
		merger.clearDuplicateEquates();
		AddressSet p1CodeUnitSet = DiffUtility.getCodeUnitSet(p1MergeSet, this.program1);
		if (monitor == null) {
			// Create a "do nothing" task monitor that we can pass along.
			monitor = TaskMonitor.DUMMY;
		}

		// Check that the needed memory addresses are available in the merge program.
		if (!hasMergeAddresses(p1MergeSet)) {
			errorMsg.append("The Difference cannot be applied.\n" +
				"The program does not have memory defined\n" +
				"for some of the indicated addresses.\n");
			return false;
		}

		// NOTE: The order in which the following merge methods are called
		//       is important in some cases. For example, calling the
		//       mergeReferences() before mergeLabels() would lead to extra
		//       default labels appearing in the merge program. Also, you
		//       want to apply code unit differences before applying
		//       other merge differences to them.

		mergeBytes(p1MergeSet, filter, monitor);
		mergeProgramContext(p1MergeSet, filter, monitor);
		mergeCodeUnits(p1MergeSet, filter, monitor); // Code Units should  follow program context.
		mergeComments(p1MergeSet, filter, monitor);
		mergeFunctions(p1MergeSet, filter, monitor); // Functions should follow code units.
		// Note: This should follow code units and functions so that we already
		//       have a "FUN..." label since we can't create default labels.
		mergeLabels(p1MergeSet, filter, monitor); // Labels should follow code units & functions.
		mergeReferences(p1MergeSet, filter, monitor); // References should follow labels and code units.
		mergeBookmarks(p1MergeSet, filter, monitor);
		mergeProperties(p1MergeSet, filter, monitor);
		mergeFunctionTags(p1MergeSet, filter, monitor);
		mergeSourceMap(p1MergeSet, filter, monitor);

		merger.reApplyDuplicateEquates();
		String dupEquatesMessage = merger.getDuplicateEquatesInfo();
		if (dupEquatesMessage.length() > 0) {
			infoMsg.append(dupEquatesMessage);
		}

		merger.reApplyDuplicateSymbols();
		String dupSymbolsMessage = merger.getDuplicateSymbolsInfo();
		if (dupSymbolsMessage.length() > 0) {
			infoMsg.append(dupSymbolsMessage);
		}

		programDiff.reDiffSubSet(p1CodeUnitSet, monitor);
		return (errorMsg.length() == 0 && !merger.hasErrorMessage());
	}
Merge the differences from the indicated program on the specified
 address set with the indicated filtering.
@param p1MergeSet the address set to be merged
The addresses in this set should be derived from program1.
@param filter the filter indicating what types of differences to merge.
@param monitor task monitor for reporting merge status to the user.
@return true if merge succeeds

@throws MemoryAccessException if bytes can't be copied.
@throws CancelledException if user cancels via the monitor.
Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramMergeManager.java