My partial understanding of DDD was that you shouldn't define any persistence layer logic in your domain models.
The basis for that advice (at least the versions of that advice which I would call good advice) is not that you should design your domain models with persistence in mind, it's about having your ORM make use of your domain models as they are.
Generally speaking in DDD you're working with some kind of oniony/domain-centric approach where the persistence layer has access to your domain, which is the basis for being able to assert that the persistence layer can handle your domain model.
Based on the direction of that relationship, it's not okay for the domain to build itself based on what the persistence layer needs, but it's perfectly okay for the persistence layer to orient itself around handling the domain models - which including any persistence logic centered around the specific structure of the domain model.
However, that advice only applies in as much is possible. Sometimes your domain models simply are not compatible with your chosen persistence method. At that stage, you will have to create separate persistence models that are compatible with the storage device, and you will have to map from your domain models to your persistence models (and vice versa when retrieving).
But that mapping logic is owned by the persistence layer (since the persistence models are private to that layer), which doesn't really change what I said before: the persistence layer is still the layer that handles the incoming domain models and figures out how to store them.
Whether it's possible to put the domain models directly into the ORM or whether you're mapping them to a persistence model and then putting that into storage is an implementation detail (private to the persistence layer) which does not affect how the domain itself is modeled.
Ideally I just want to be able to update my aggregate and save it through my repository.
Let's start higher level.
When dealing with a domain-centric design (I use this terminology to be slightly broader than just DDD, but it does fully include DDD), your domain is designed to be the lingua franca of your codebase. What that means is that when your internal layers (application, domain, persistence) speak to one another, the data objects they use as part of that communication should be domain concepts.
If you have a Person aggregate root, regardless of how many subaggregates it may have, and regardless of how many tables you need to store that aggregate root's data in, the interface with your persistence layer should be talking about Person, nothing more granular than that. Anything more granular has to be handled within a layer, without it being publically visible.
Let's use an example here of a Person aggregate root, notably with some basic data fields and a profile picture, and there's an Address subaggregate involved as part of Person. Something along the lines of:
public class Person
{
    public int ID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string AvatarBase64 { get; set; }
    public Address ResidentialAddress { get; set; }
    public Address PostalAddress { get; set; }
}
There are two classes involved here, but referring back to my earlier point, that granularity is not visible in communication between layers. Therefore, your interaction with the persistence layer (from outside of the persistence layer) should be along the lines of:
public interface IPersonRepository
{
    public void Save(Person p);
    public Person GetById(int personId);
}
Now let's focus on the persistence internals. For storage reasons, you actually want to break this down in three different storage methods: A People table for the person's information, an Addresses table to store all addresses, and a dedicated CDN for the profile picture.
Internally, your persistence layer can break this Person down into smaller parts for the purpose of storing/retrieving the data. The only thing you have to keep in mind is that these deconstructed repositories are never used publically (i.e. from outside of the persistence layer), they should remain a private implementation detail of the persistence layer.
The implementation of IPersonRepository could be something like this:
public class PersonRepository : IPersonRepository
{
    // Omitted the injected dependencies for brevity
    public void Save(Person p)
    {
        var personDetails = new PersonDetails(p.Id, p.FirstName, p.LastName);
        _personDetailRepository.Save(personDetails);
        _addressRepository.Save(p.Id, AddressType.Residential, p.ResidentialAddress);
        _addressRepository.Save(p.Id, AddressType.Postal, p.PostalAddress);
        _profileBlobStore.Save(p.Id, p.AvatarBase64);
    }
    public Person GetById(int personId)
    {
        var personDetails = _personDetailRepository.GetById(personId);
        var residentialAddress = _addressRepository.Get(personId, AddressType.Residential);
        var postalAddress = _addressRepository.Get(personId, AddressType.Postal);
        var avatarBase64 = _profileBlobStore.Get(personId);
        return new Person()
        {
            Id = personId,
            FirstName = personDetails.FirstName,
            LastName = personDetails.LastName,
            ResidentialAddress = residentialAddress,
            PostalAddress = postalAddress,
            AvatarBase64 = avatarBase64
        };
    }
}
The interfaces and implementations of _personDetailRepository, _addressRepository and _profileBlobStore do not need to be visible to anyone outside of the persistence layer, because no one except the persistence layer should ever interact with them directly.
Instead, the PersonRepository is responsible for handling the incoming/outgoing deconstruction of the Person domain model, so the communication with the persistence layer (from outside of it) can center around the Person aggregate root.
Let's explore a second possibility for the persistence layer implementation. Suppose you have an ORM which is actually able to process the Person object in its entirety. This may be the case because you have an advanced ORM, or because you are only using a plain document blob store that requires no specific handling for specific types. In such a case, you would do something along the lines of:
public class PersonRepository : IPersonRepository
{
    // Omitted the injected dependencies for brevity
    public void Save(Person p)
    {
        _myORM.Save<Person>(p.Id, p);
    }
    public Person GetById(int personId)
    {
        return _myORM.Get<Person>(personId);
    }
}
The important take away here is that between these two hypothetical scenarios, only the concrete implementation of the persistence layer changed. The domain was never designed with either option in mind, and does not need to be altered based on any persistence-level design decision.
That is the core premise of the advice that led you to post this question.
Note
I am aware that your question centered around only updating what has changed. I omitted it from the example because there are many different ways of doing this and it would distract from the underlying layer separation that lies at the root of your question which I'm focusing on.
Diffing the current person state and the new person state is a responsibility of the persistence layer (since you're inherently comparing with the stored state), which means that this logic should live within the persistence layer, without the domain models or persistence layer interface being designed around it.
Second note
This is just me pre-empting a very common response to this design: comparing the entire Person when saving, as opposed to actively tracking what changes have been made and directing the persistence layer specifically to perform those operations; indeed does not yield the highest runtime performance possible.
DDD does not prioritize runtime performance, it prioritizes clean layer separation and logical ownership, with the main goal being clean, readable and maintanable codebases. Pure DDD will generally not focus on runtime performance optimizations.
Pragmatically, you rarely want to do pure DDD for that precise reason. Real-world application design generally warrants some performance optimizations that DDD simply does not account for in its theoretical model, and this is the part where you need to start making compromises to your design in a way that gives you the needed optimizations without trading away the cleanliness and maintainability of the code. That is not an easy task and not something an internet stranger can solve for you - it requires a lot of context from your business and dev culture to make the right call.