public boolean merge(int row, int mergeFields, TaskMonitor monitor) {
		if ((mergeFields & MemoryBlockDiff.ALL) == 0) {
			return false;
		}
		if (row < 0 || row >= diffs.length) {
			return false;
		}
		MemoryBlockDiff blockDiff = diffs[row];
		MemoryBlock block1 = blockDiff.getBlock1();
		MemoryBlock block2 = blockDiff.getBlock2();
		AddressRange range = ranges[row];
		if (shouldMerge(mergeFields, MemoryBlockDiff.START_ADDRESS) &&
			blockDiff.isStartAddressDifferent()) {
			if (block1 == null) {
				// Add all or part of a block.
				Address start2 = block2.getStart();
				Address end2 = block2.getEnd();
				Address startRange = range.getMinAddress();
				Address endRange = range.getMaxAddress();
				int compareStart = start2.compareTo(startRange);
				int compareEnd = end2.compareTo(endRange);
				try {
					memory1.createBlock(block2, block2.getName(), startRange, range.getLength());
					if (compareStart < 0) {
						MemoryBlock firstBlock = memory1.getBlock(start2);
						MemoryBlock secondBlock = memory1.getBlock(startRange);
						memory1.join(firstBlock, secondBlock);
					}
					if (compareEnd > 0) {
						MemoryBlock firstBlock = memory1.getBlock(endRange);
						MemoryBlock secondBlock = memory1.getBlock(end2);
						memory1.join(firstBlock, secondBlock);
					}
					return true;
				}
				catch (Exception e) {
					Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
				}
				return false;
			}
			if (block2 == null) {
				// Remove all or part of a block.
				Address start1 = block1.getStart();
				Address end1 = block1.getEnd();
				Address startRange = range.getMinAddress();
				Address endRange = range.getMaxAddress();
				int compareStart = start1.compareTo(startRange);
				int compareEnd = end1.compareTo(endRange);
				try {
					if (compareEnd > 0) {
						memory1.split(block1, endRange.add(1L));
					}
					if (compareStart < 0) {
						memory1.split(block1, startRange);
					}
					if (compareStart == 0 && compareEnd == 0) {
						MemoryBlock blockToRemove = memory1.getBlock(startRange);
						memory1.removeBlock(blockToRemove, monitor);
					}
					return true;
				}
				catch (LockException e) {
					Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
				}
				catch (NotFoundException e) {
					Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
				}
				catch (AddressOutOfBoundsException e) {
					Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
				}
				catch (MemoryBlockException e) {
					Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
				}
				return false;
			}
		}
		if (shouldMerge(mergeFields, MemoryBlockDiff.END_ADDRESS) &&
			blockDiff.isEndAddressDifferent()) {
			// TODO
		}
		if (shouldMerge(mergeFields, MemoryBlockDiff.SIZE) && blockDiff.isSizeDifferent()) {
			// TODO
		}
		if (shouldMerge(mergeFields, MemoryBlockDiff.TYPE) && blockDiff.isTypeDifferent()) {
			// TODO
		}
		if (shouldMerge(mergeFields, MemoryBlockDiff.INIT) && blockDiff.isInitDifferent()) {
			// TODO
		}
		if (shouldMerge(mergeFields, MemoryBlockDiff.NAME) && blockDiff.isNameDifferent()) {
			try {
				block1.setName(block2.getName());
			}
			catch (LockException e) {
				Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
			}
		}
		if (shouldMerge(mergeFields, MemoryBlockDiff.READ) && blockDiff.isReadDifferent()) {
			block1.setRead(block2.isRead());
		}
		if (shouldMerge(mergeFields, MemoryBlockDiff.WRITE) && blockDiff.isWriteDifferent()) {
			block1.setWrite(block2.isWrite());
		}
		if (shouldMerge(mergeFields, MemoryBlockDiff.EXECUTE) && blockDiff.isExecDifferent()) {
			block1.setExecute(block2.isExecute());
		}
		if (shouldMerge(mergeFields, MemoryBlockDiff.VOLATILE) && blockDiff.isVolatileDifferent()) {
			block1.setVolatile(block2.isVolatile());
		}
		if (shouldMerge(mergeFields, MemoryBlockDiff.ARTIFICIAL) &&
			blockDiff.isArtificialDifferent()) {
			block1.setArtificial(block2.isArtificial());
		}
		if (shouldMerge(mergeFields, MemoryBlockDiff.SOURCE) && blockDiff.isSourceDifferent()) {
			block1.setSourceName(block2.getSourceName());
		}
		if (shouldMerge(mergeFields, MemoryBlockDiff.COMMENT) && blockDiff.isCommentDifferent()) {
			block1.setComment(block2.getComment());
		}
		return true;
	}
Determines whether the two memory blocks are the same.
@param block1 the first program's memory block
@param block2 the second program's memory block
@return true if the memory blocks are the same.
Ghidra/Features/Base/src/main/java/ghidra/program/util/MemoryDiff.java