Repository: rclone/rclone (language: go)

Issue:
bisync: optimize --resync
## Synposis

Clearly explain in documentation whether `--resync` is asymmetrical.
(@cjnaz could you comment?)

Investigate whether `--resync` can be re-implemented by the equivalent of:

```
rclone copy --update Path1 Path2
rclone copy --update Path2 Path1
```

## Prior discussions

## optimize --resync

### https://github.com/cjnaz/rclonesync-V2/issues/66 (eric-void) -> (cjnaz)

> looking at the code there is a lot of work to copy Path2 files not in Path1, and then do an "rclone sync" from Path1 to Path2. Why don't you just do and "rclone copy" from Path1 to Path2, and then an "rclone copy" from Path2 to Path1?
> This is much simpler, there is no need to read 2 times LSL files and to loop for missing Path2 files, and the result should be the same. Am i missing something?

The first-sync optimization is deferred for now since its not broke and should be rarely run.

### https://github.com/rclone/rclone/pull/5164#discussion_r688913159 (ncw)

So `--resync` is asymetrical?

Perhaps it would be better implemented by the equivalent of

```
rclone copy --update Path1 Path2
rclone copy --update Path2 Path1
```

## How to use GitHub

* Please use the 👍 [reaction](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to show that you are affected by the same issue.
* Please don't comment if you have no relevant information to add. It's just extra noise for everyone subscribed to this issue.
* Subscribe to receive notifications on status change and new comments.



Discussion / hints:
I think the core question here is whether rclonesync's asymmetrical --first-sync solves some subtle problem.  I think the answer is _no_, none that I can recall.  When I implemented the current --first-sync method I think I was too embedded in the new algorithm (building file lists for raw copies/deletes) that I missed the simpler picture.  I'd say go for this method...
```
rclone copy --update Path1 Path2
rclone copy --update Path2 Path1
```
Unit tests and documentation will be updated respectively.
I had the same thought recently:

https://github.com/rclone/rclone/blob/156c372cd760460f419708c75506434c48decfc8/cmd/bisync/operations.go#L426-L433

I tend to think it would be better to change it, as in addition to being simpler and more symmetrical, it would also make `--resync` substantially faster for users of `--create-empty-src-dirs`. However, it would be a breaking change, and I'm not sure how concerned we should be about that. It's possible that some users have come to depend on the asymmetry in some way. For instance, imagine a scenario where you're bisyncing one central server with multiple devices, and the server is the source-of-truth. The asymmetry allows you to declare that the server should take priority in the event of a `--resync`, even if the corresponding file on the other path is newer.

Perhaps the best compromise is to make the behavior configurable with a flag?
@nielash I've moved my comments over from #7332 regarding bisync.. 

I agree with both @ivandeex  @cjnaz that the correct implementation for bisync should be:

```
rclone copy --update Path1 Path2 (--create-empty-src-dirs)
rclone copy --update Path2 Path1 (--create-empty-src-dirs)
```

This is what would happen if I was using Dropbox, OneDrive, GDrive, etc (e.g. the newest file will always survive on init and where the local directory already has data). 

As bisync is still experimental I seem no harm in changing this to be the default behavior. Also, I believe this would be inline with the expectations of any new users of bisync and would also benefit existing users. 

This also makes a --resync far less destructive. Currently, Path1 will always take precedent which is the last thing I believe anyone would want from a bisync (existing or new users) rather they are stuck with the current implementation. If there are current users that would like this functionality perhaps either a --legacy flag or simply they can run a sync manually to have the desired effect based of your comments: 

```
rclone copy Path2 Path1 --ignore-existing 
rclone copy Path1 Path2 (--create-empty-src-dirs)
rclone copy Path2 Path1 (--create-empty-src-dirs) 
```

Thanks 🙏
> I agree with both @ivandeex @cjnaz that the correct implementation for bisync should be:
> 
> ```
> rclone copy --update Path1 Path2 (--create-empty-src-dirs)
> rclone copy --update Path2 Path1 (--create-empty-src-dirs)
> ```

I generally agree as well, although I have a slight concern about the use of `--update` for the same reasons articulated in [our other thread](https://github.com/rclone/rclone/issues/7332#issuecomment-1741611077), about the potential dangers of picking winners and losers at the _file_ level instead of the _filesystem_ level. But I think this could be solved by just letting the user choose their desired behavior with a flag.

> This also makes a --resync far less destructive. Currently, Path1 will always take precedent which is the last thing I believe anyone would want from a bisync 

I can think of a few reasons a user might want the asymmetry -- I described one of them above. Imagine, for example, that I pull my dusty old laptop out of the closet which hasn't been synced in a long time, and I want to bring it up to date with my Google Drive which I know is totally up-to-date. In this case, I do in fact want the trusted `drive` side to take precedence over the untrusted `local` side -- even if certain `local` files happen to be newer (intentional reversions do sometimes happen -- maybe I restored something from a backup recently on the `drive` side, and now it's about to get overwritten.) An asymmetrical `--resync` lets you declare one side the source-of-truth; while `--update` prioritizes the newness of individual files, possibly at the expense of consistency at the directory-level.

Another use case (which I've used myself) is safer preservation of metadata that rclone doesn't currently support, such as directory metadata, macOS xattrs, and permissions. An asymmetrical sync allows you to avoid overwriting that stuff on the trusted side, when possible. 

Additionally, it should be noted that bisync's current approximation of `--ignore-existing` does have a performance benefit, because in 1 of the 2 directions it can skip the modtime (or checksum) check for some of the files. (But that performance benefit is negated if using `--create-empty-src-dirs`, which requires a third operation -- unless we change that.)

I tend to think that rclone's default (which is still slightly asymmetrical) should be bisync's default:
```
rclone copy Path2 Path1 (--create-empty-src-dirs)
rclone copy Path1 Path2 (--create-empty-src-dirs)
```

but that this should be overridable with flags for users who think this is madness 😄 

@ncw I think this is ultimately a question for you -- what is your guiding principle for breaking changes such as this, where it's not exactly a bug, but there does seem to be consensus that a different way would be better? Is it ok to change the behavior, provided it's documented clearly? (And is the calculation different because bisync is still in beta?)
The problem here is you are using the wrong tool. Bisync should be bisync not sometimes bisync. Let me explain.

For the below standard means: Dropbox, OneDrive, GDrive, Unison, etc...

- Prior State Available
	- standard - run as normal
	- rclone - run as normal
	
- Prior State NOT Available
	- standard - remove dir and run
	- rclone
		- remove dir and run --resync
		- `rclone sync` (yes sync not bisync) then run `--resync`
		
So in your example you have two options, remove the data or run a `rclone sync` prior.

With regards to directory metadata there is already a ticket raised #6685 to handle this and again would not conflate these two issues as this will be solved once metadata is added to the directory where possible or where not the use of a `.dirmeta` file or similar. Also, using `rclone sync` as above would still keep existing metadata.

As we are talking about a `--resync` here I do not think a slight increase in time is a matter of contention. 

Ultimately, there should be one way for bisync to work which is using --update flag as that would make it bidirectional and inline with expectations e.g. the same as every other bidirectional syncing tool. If someone wants to do another type of sync they should use `copy` or `sync`. Don't take this the wrong way I mean well but in my opinion the general approach by other tools seems logical, well thought out and have yet so see any good reasons to change this. 

Maybe @ncw could give his input on this matter too alongside confirming whether such a change can take place.
> For the below standard means: Dropbox, OneDrive, GDrive, Unison, etc...

I think it is an oversimplification to say that there is one "standard" way of doing this. For example, Unison has the `-prefer xxx` flag which allows `root`, `newer`, and `older`.

Also, the "standard - remove dir and run" that you cite for Dropbox and GDrive would be more equivalent to:

```
rclone sync remote local (--create-empty-src-dirs)
```

which is still different from the `copy --update` that you are suggesting:
```
rclone copy --update Path1 Path2 (--create-empty-src-dirs)
rclone copy --update Path2 Path1 (--create-empty-src-dirs)
```

So it actually seems that you are suggesting a different default than what the above tools use (closest would be Unison with `-prefer newer`, which is not the default.) (And FWIW: I think a different default is ok, if you can make the case that yours is better.)

You are correct that in my example about the laptop, I could have first run `rclone sync drive local` to make the subsequent `--resync` give the desired result. I think the question is: should I have to? (Maybe the answer is yes -- I'm ok with that. I'm just clarifying what the question is.) Alternatively, it would be easy to redesign `--resync` such that `--resync --update` produces your desired result (symmetrical) while keeping the default asymmetrical.

Fair points about the metadata and speed.

> Bisync should be bisync not sometimes bisync.

`--resync` is already a departure from the normal bisync rules (for example: `--resync` never deletes), so I think bisync is already "sometimes bisync" in a sense. It's a design choice that bisync made at the very beginning (and I personally think it's a very good one.)

> Ultimately, there should be one way for bisync to work which is using --update flag

I'm generally wary of forcing a specific flag on users without giving them a way to change it. If we go with `--update` as the default for `--resync`, I think we should at least offer a `--resync --prefer Path1` option. (If ncw thinks it is changeable at all, at this point.)
I disagree there is definitely a default way of doing bidirectional file sync and it is symmetrical based on the tools that most people use day-to-day and in which sys admins maintain e.g. the main three Dropbox, Google Drive, OneDrive then others such as Amazon Drive, NextCloud, Seafile, OwnCloud, etc..

Though you are correct I was wrong to put Unison in this category; it's been a while since I last used. Though it is hard to compare as `--prefer` is a conflict flag and Unison does not use `--resync` so this means Unison is always asymmetrical by default unless using `--prefer newer` which makes it always symmetrical. I must also add that Unison does not have at it's disposal `copy` and `sync` as with rclone so options to change this behavior make a lot more sense. Further Unison does have a `--force` flag which is arguably more what we are talking about here and where I say rclone has this in `copy` and `sync`.

> Also, the "standard - remove dir and run" that you cite for Dropbox and GDrive would be more equivalent to:

This is untrue. Whilst it may give the illusion of a sync command because you are starting with an empty directory in essence you are still doing a `copy --update`.  If I were to add files or change existing files the newest would be kept.

But then there is the argument why use `--resync` at all? 😂 If the tool is always symmetrical (or vice versa) then there seems to be little need. Maybe this is the missing flag? And `--resync` should be removed all together?

So to conclude my original point still stands bidirectional sync should be symmetrical by default if the goal is to be inline with common understanding. Further, I think it's extremely bad practice for a tool to be by default asymmetrical then symmetrical. Unison by default is asymmetrical at all times not a combination of the two. 
@crocinsocks  I took some time today refreshing my memory on how Dropbox handles this scenario. It is documented here: [Why does Dropbox need to “sync my files again”?](https://help.dropbox.com/sync/sync-files-error), and it matches the behavior I observed when I tried it myself. In relevant part:

> To keep your files safe during this process, Dropbox renames your Dropbox folder in File Explorer (Windows) or Finder (Mac) from “Dropbox ([account name])” to “Dropbox (Old).” Then, Dropbox creates a new folder in the same location on your computer and syncs your files there as well.

> **How does this work?**
The result is two folders. This process is just a precaution to ensure that copies of your files are safe on your computer while your files are re-syncing. It’s recommended that you don’t touch the “Dropbox (Old)” folder while this process is happening.

So, it looks like what Dropbox actually does is equivalent to this:
```
rclone move "Dropbox" "Dropbox (Old)"
rclone sync dropbox: "Dropbox" --copy-dest "Dropbox (Old)"
[rclone bisync dropbox: "Dropbox"]
```
The `--copy-dest` part is so that it doesn't have to re-download any files that are already on your computer with a hash that matches the cloud version. Hence the instruction "don’t touch the “Dropbox (Old)” folder while this process is happening".

In other words, Dropbox's equivalent to `--resync` is totally asymmetrical, in favor of the cloud side. It does not attempt to merge or reconcile the two sides in any way -- it simply moves the local side to "Dropbox (Old)", where you can then do whatever you want to with it.

I also tried signing out and doing a fresh install to a location that already had existing files, to see what it would do. Every time, it refused with the following error messages:

![Dropbox Error1](https://github.com/rclone/rclone/assets/31582349/5d02f485-deec-4b1a-b3bb-807ec696ff33) ![Dropbox Error2](https://github.com/rclone/rclone/assets/31582349/414b4b98-6977-473a-a97c-255d58e6892e)

So, not only did it not give precedence to the newer file on my machine, it also didn't even keep files that were _only_ on my machine.

I don't doubt that Dropbox does behave symmetrically after it is fully set-up (as does bisync), but as we are only discussing `--resync` here, I am only looking at its equivalent of `--resync`. Dropbox did not give both sides equal weight -- it always considered the cloud side to be superior (which I guess kind of makes sense, since it is first and foremost a cloud storage service.) This is much closer to the "remove dir and run" that you described earlier, not `copy --update`. If you think I've missed something in my test, please feel free to show me a test of your own where you are able to get dropbox to overwrite a cloud-side file with a local-side file **during a resync scenario** (not just during normal everyday use.)

I also continue to think that what Dropbox does is a little bit beside the point, because we are not obligated to follow exactly what Dropbox does. I use rclone and bisync instead of alternative tools because I like how it works better 🙂 

> But then there is the argument why use `--resync` at all? 😂 If the tool is always symmetrical (or vice versa) then there seems to be little need. Maybe this is the missing flag? And `--resync` should be removed all together?

To back up just slightly: `--resync` performs 3 different important roles for bisync:

1. It brings disagreeing sides into agreement on the first sync, so that each subsequent "normal" (non-resync) bisync run can assume that both sides matched after the prior run
2. It provides a mechanism of ensuring user permission to proceed with destructive changes (such as changes to the `--filters-file`)
3. It provides a way of regenerating a trusted state when the prior state is unknown or untrusted (for example, after a critical error during a bisync run, or a `--check-sync` failure.)

There are various [bisync alternatives](https://rclone.org/bisync/#references) out there that don't have a `--resync` equivalent, but I find that they all take unacceptable (in my opinion) shortcuts on at least one of these points, in exchange. Usually, it is a tradeoff of safety for convenience. Bidirectional sync can never truly be stateless, so any tool that does it without knowing the prior state is guessing in some way. Often that guess is right so much of the time that the convenience tradeoff is worth it -- but it is still a guess. A particularly common strategy is "if we don't know or don't trust the prior state, then we consider everything to be new".

Some tools also have some method of making an educated guess to resolve conflicts between two file versions (such as guessing that the version with the newest modtime is "best"), but a file conflict is not actually required for trouble to arise. Consider the following thought experiment: you're a bidirectional sync tool and you come across a folder you've never seen before. On `Side1`, it contains files `a` and `b`. On `Side2`, it contains only `a`. Which of these statements describes the most recent action?: 

- `b` was added to `Side1`
- `b` was deleted from `Side2`

The answer is that you can't know this with certainty -- you can only guess. Most tools that engage in this type of guessing will guess that `b` was added to `Side1`, so as to err on the side of preserving rather than deleting a file. But this guess could indeed be wrong -- perhaps the user wanted `b` deleted, and now it has suddenly reappeared? 

Bisync, on the other hand, just refuses to guess in such a scenario. It instead requires the user to make the decision, by refusing to run again until the user manually runs `--resync`. This is why it's a tradeoff of convenience for safety. It is _inconvenient_ to the user to have to run `--resync`, but it is the _safer_ option, because the user has assurance that bisync will never make guesses when it's less than 100% sure. 

Personally, I _love_ this about bisync, and it's the only reason I feel comfortable trusting my important files to it. The day that `--resync` is removed from bisync is probably the day that I stop using bisync. 

All of that said, I recognize that different users have different use cases and preferences, and some users may prefer convenience over safety. This could be sensible if, for example, you are just using bisync to sync your movie collection, which you could just re-download from the internet should you ever need to. This user's preference and standard for perfection will naturally be different than the user bisyncing the only surviving photos of his grandmother, or the novel he's been working on for 5 years, or other priceless data. (Yes, they should be making backups too, but the point still stands.) So, while I think bisync should choose "safe" by default, I would not be opposed to adding some optional flags to enable more of the "convenient" behavior. It actually would not be that difficult to add a `-force newer` mode that essentially never needs a `--resync`, and I'm not opposed to doing so. But I personally would never use it. And I'd want to make sure the docs include a big warning like the one Unison includes: 
> This preference should be used only if you are _sure_ you know what you are doing!

There are also some tools that get around this issue by [watching filesystem events](https://github.com/rclone/rclone/issues/249) -- something that rclone [cannot yet do](https://github.com/rclone/rclone/issues/4152) for the `local` backend. And even for such apps, they can still end up missing events that happen while they're not running, and so end up having to still do some small amount of "guessing".

> So to conclude my original point still stands bidirectional sync should be symmetrical by default if the goal is to be inline with common understanding.

I think the goal is to provide the best bidirectional sync tool, and the one that is most consistent with rclone's design principles more generally -- and then make sure that any departures from "common understanding" are clearly articulated in the docs. (I also don't think that there is one standard "common understanding" on this particular issue. As I've pointed out, neither Dropbox nor Unison actually use something like `copy --update` for their default in a situation equivalent to `--resync`.)

> Further, I think it's extremely bad practice for a tool to be by default asymmetrical then symmetrical.

I think we just see this one differently. I love that bisync has two different modes for different purposes -- I think it's one of the genius things about its design, and part of why I prefer it to other bidirectional sync tools. I also think that Dropbox, as far as I can tell, is first asymmetrical and then symmetrical after that. I see no problem with that choice, as long as it's documented clearly. 

> I must also add that Unison does not have at it's disposal copy and sync as with rclone so options to change this behavior make a lot more sense.

If I'm understanding correctly, I think what you are saying is that because `rclone copy` exists, therefore I should have to run it as an extra step before `--resync` if I want that behavior. But wouldn't the reverse argument be just as true? i.e.: because `rclone copy --update` exists, therefore you should have to run it as an extra step before `--resync` if you want that behavior? (And to be clear -- that's not what I'm proposing. What I'm proposing is that `--update` should be supported in `--resync` as an optional non-default flag, the same as it is in `rclone sync`. I also remain open to making it the default, as long as there is a way to disable it, such as `--prefer Path1`.)

To summarize, I think what the decision comes down to is:

- `--update` should be default if symmetry is the most important factor
- `--update` should be non-default if consistency with other rclone commands is the most important factor
- `--update` is best if your priority is newness at the individual file level
- No `--update` is best if your priority is newness or atomicity at the filesystem level, or if one whole side is more trusted than the other
- Either result could be achieved by running a combination of different rclone commands first, before running `--resync`
- Both choices are defensible if documented clearly to users
- IMO, whichever one is chosen as the default, the other should be supported with a flag. (Assuming the default is changeable at all, at this point.)
## Dropbox (+ other sync tools)

Hi @nielash, you are missing why Dropbox does this in the first place. Dropbox has created this feature as an add-on for specifically macos and windows user as they consider these users to be less tech knowledgeable which in general is true. This feature has been added to prevent someone who does not understand Dropbox is always symmetrical and that when syncing an old dropbox folder stuff that may have been deleted will be re-added and any changes where future changes have been made e.g. was changed but not the newest, will be lost. As you can see this does not apply to Linux as they expect power users to understand this. There is a simple workaround which many poweruser and sysadmins use on windows and mac with all these type of sync clients as many make the same assumptions as Dropbox. That is rename the folder or choose another location for "live" and then move the files from "old" into the "live" dropbox folder. As you can see, the newer files from the "old" folder or newer files from the cloud will always be chosen and unchanged files left untouched. This is because dropbox (init) sync is equivalent to `copy --update`. Also, if you were to follow dropbox procedure you could still edit the "live" dropbox folder with new and existing (e.g. made at the same path) files so it's definitely not a `sync` command. Hopefully, that clears up why Dropbox does this and that the (init) sync of their client is always `copy --update` (symmetrical) as with all others in this category. If someone was to restore a folder that for example is older than a few days this could create too many unwanted items and not because the sync asymmetrical.

## Resync

Let's take the most common use case for bisync (unless you disagree?). Multiple devices/users are working on a central drive; without knowing prior state one has to assume the central drive is always correct unless you have a "new" / newer file(s) locally. Of course, for bisync to make more intelligent decisions it needs prior state. I'm struggling to find an example of bisync that is used in production where you would not want this to be the case. Otherwise, by nature you are making a destructive sync and assuming one-side is more important and if so my point is that one should not use bisync but another command of rclone in this case. At the end of the day, most people would be okay with some data they had deleted coming back (non-destructive) but not newer files being overridden with older (destructive) by default. Sure, your argument would be that conflicted files would not get created on first sync rather lost and I agree. But are most users actually going to sit there and go through every file that is different and manually handle conflicts (if they even exist) before sync or simply run with `--resync` or another directional command of rclone. Realistically, in a multi user environment this is not an approachable task and perhaps not even in a single user environment. Bisync will never remove the need for archives regardless of approach and nor should it try. 

I also want to comment on the safety of data, currently bisyncs approach makes me s**t my pants at how destructive it is and I have also seen others comment on this in the forums. Currently, safe is the last word I would use for bisync with regards to --resync.

Perhaps `--resync 'newer' | 'path1' | 'path2'` and then `--auto-resync` flag? I'd be careful repeating flags from Unison that would have different meaning unless you change `-prefer` to also have effect with conflict resolution in future syncs too as well as `force` to always mean force which is why I suggest a param value for resync above.

In my view the only reason for --resync should be if prior state is lost. Filter changes, crashed sync's etc should not require this though appreciate work would have to be done to make this work. Though, I can see the point that if you remove a filter rather than add perhaps a resync would be required but only if you already have said files on both sides and decision has to made and `--auto-resync` isn't present though ideally this should only `--resync` the new paths (if any) so last state for all the other files is still valid.

I think the above answers a lot of your statements as it again relies on the approach that most bisync tools are not symmetrical by default and as I've shown this is not the case; they are symmetrical by default and from first sync. I still would be concerned about a tool having both asymmetrical and symmetrical defaults. In almost all cases the odds that newer is not the "correct" way to handle an initial bidirectional sync is low. It seems unlikely most would want a directional and destructive sync from bisync and why I keep referring to sync or copy in these cases. However, if you believe that people really need a destructive sync under bisync (e.g. destructive because one-side is preferred in what should be a bidirectional sync) then I appreciate we will likely never agree on this and is why I have suggested `--resync 'newer' | 'path1' | 'path2'` to satisfy all needs.
Its good to see some expansive and passionate discussion on this issue.  (And there is a diminishing return on words.)  I've followed this thread at a cursory level, so I'm not prepared to weigh in on the merits and accuracy of the analysis.

As a user, I want a minimum amount of damage.  That's my guiding principle.  So no guessing.  Damage is either loss of files or (sometimes massive) reappearance of previously deleted files.

Are there any problems with the originally proposed change?
```
  rclone copy --update Path1 Path2
  rclone copy --update Path2 Path1
```
An alternate, good-guess resync method could be added with a option switch.  

Whether the resync favors one path or the other is not a critical issue for me.  What matters is to reestablish coherence with minimum damage.

Is the debate about which method should be the default?  My vote is always to alert the user and make it her responsibility to sort it out when there is a problem, so don't change the default resync behavior.
@cjnaz I agree I should be better at shortening my responses (you should see the other thread between @nielash and myself - it's almost biblical 😂 but I believe in a good way and has definitely helped me as I hope @nielash).

The original proposed change makes the most sense to me as by default bidirectional sync should not have a preferred side e.g. symmetrical (the only exception would be when there is no mod time available which has yet to be discussed more generally in this thread).

@nielash thinks that the default should be directional which to me only makes sense under limited circumstances where one can instinctively declare your local copy is always best and all those changes  made on other devices should be ignored. The problem here is this would also take precedent over newer files which is where I get worried for myself and other users of this tool and I believe would be "unusual" and fundamentally destructive. 

Currently, --resync works in this manner e.g. asymmetrical and is the reason for the ticket to be opened e.g. to move to symmetrical 

> As a user, I want a minimum amount of damage. That's my guiding principle. So no guessing. Damage is either loss of files or (sometimes massive) reappearance of previously deleted files. 

Regardless, both have the chance of choosing the wrong files (from the user perspective) and creating already deleted directories though this should be minimized if not --resync'ing a directory that's out-of-date and more importantly contains many files/folders that have already been deleted.

In my view the more destructive tool is the one that deliberately ignores newer files for a older files and therefore `--update` should be used. Though, simply allowing the user to choose with something like `--resync 'newer' | 'path1' | 'path2'` would keep everybody happy and allow for all options including where there is no modtime. Though, I'd still put forward that 'newer' should be the default which would be the same as the original suggestion e.g.:

```
rclone copy --update Path1 Path2
rclone copy --update Path2 Path1
```

And where there is no modtime it would fail without a path being specified.
Hi @cjnaz! Great to finally meet you, and thank you for all of your great work on `rclonesync`! I sometimes feel like I spend a lot of time in your brain these days, as I work on `bisync` 😂 

Bisync does tend to elicit some passionate opinions. 😄 To make sure we're all on the same page: `--resync` is currently asymmetrical in favor of Path1. While cjnaz and ivandeex discussed changing this in 2021, it never actually got changed. The `--resync` code that was actually released is roughly equivalent to:

```
rclone copy Path2 Path1 --ignore-existing
rclone copy Path1 Path2
```

The questions before us now are:

1. Should `--resync` be changed at all at this point, given that it has been one way for 2 years and changing it would be a breaking change? 
- _My opinion: yes it should (if ncw gives his blessing). Bisync is still in beta and there seems to be consensus that the change is worth it._
2. If so, what should be the new default behavior? 
- _My opinion explained below, though I don't feel as strongly about this one, given the good workarounds._
3. Should `--resync` be removed entirely, as proposed recently by @crocinsocks? 
- _I feel strongly that no, `--resync` should not be removed. Instead, we should consider adding a non-default `--auto-resync` mode with lots of warnings._

> As a user, I want a minimum amount of damage. That's my guiding principle. So no guessing. Damage is either loss of files or (sometimes massive) reappearance of previously deleted files.

100% agree on this.

> Are there any problems with the originally proposed change?
> ```
>  rclone copy --update Path1 Path2
>  rclone copy --update Path2 Path1
> ```

From my perspective, there is a slight problem with it, but since there are good workarounds it's ultimately something I could live with. The problem, from my perspective, is that it evaluates each file independently at the _file_ level, without considering the impact on the _directory_ or _filesystem_ level. It could easily cause "damage" for the kind of directory where atomicity matters -- like a source code repo or an audio/video project folder. For users that work with these kinds of directories, it's probably unlikely they'd want a result that is a "merged" directory with some files from both sides -- much more likely they'd want one whole directory from one side to overwrite the whole directory on the other.

In my personal experience of using bisync, I've found that in a scenario where a `--resync` is required, it's uncommon that both sides are partially right. It's much more common that one whole side is right and the other is wrong. A symmetrical `--resync` in this scenario would do more harm than good, because it would pollute the right side with things from the wrong side. (For context: my main use case is keeping my desktop and laptop both in sync with Google Drive as a single-user. I am usually working on only one side at a time, which is why there's usually an entire side that is more "up to date" at any given time.)

Suppose that I've been working on my desktop for awhile, and something goes wrong that requires a `--resync`, and my desktop is "more correct" than `drive` but there are still a few files in `drive` that haven't been synced down yet. @crocinsocks is suggesting that in this scenario, what I should have to do is:
```
rclone copy local: drive: --filter-from /path/to/filters.txt
rclone copy drive: local: --filter-from /path/to/filters.txt
rclone bisync local: drive: --filters-file /path/to/filters.txt --resync
```
This works, but it's more steps, especially with making sure to get the filters right, and the `--resync` step would just be a formality (since the sides would already match.)

It also occurs to me that in more of a "star topology" setup, an asymmetrical `--resync` allows the hub to take priority over the spokes. Whereas with symmetrical, any one spoke could end up being given undue weight over all the other spokes.

I don't think it is as simple as "asymmetrical = destructive", because it depends on context. I've just described some scenarios where the symmetrical option would be the more destructive. I likewise find "newer = better" too simplistic, as it fails to consider intentional rollbacks to older versions, and the damage it could be causing to the repo as a whole by prioritizing the newness of individual files, without regard for their interdependence.

I also don't subscribe to the view that there is anything inherently "unsafe" about an asymmetrical tool, so long as it is clearly documented. Of course, any tool is "unsafe" if used without a full understanding of how it works. 🙂 

All of that said, if there is consensus around the `--resync newer` option as the default, I am fine with that, especially if `--resync path1` and `--resync path2` also exist. (I would also propose that `--resync older` should probably exist too, although I suppose @crocinsocks will think that's heresy 😆 )

Ultimately, all of these concerns are substantially mitigated by the fact that `--resync` is never automatic, and the user always has the ability to perform manual cleanup first to override whatever we decide should be its default. That is the beauty of that design choice (and why I feel strongly that `--resync` should stay.)
Agreed @cjnaz thank you for providing such a brilliant tool which @nielash is now excellently managing/adding to!

> Bisync does tend to elicit some passionate opinions. 😄
> (I would also propose that --resync older should probably exist too, although I suppose @crocinsocks will think that's heresy 😆 ) 

I agree and you're not wrong but I've added to the below anyways 😆

**Points in this thread (heavily generalised)**

1. So  `--resync` can offer all options it would seem nielash and I are in agreement with the structure 

`--resync 'newer' | 'path1' | 'path2' | 'older'`

I agree that for project directories (code, music, video, etc..), and perhaps some single-user environments, a 'path1'/'path2' resync can make a lot of sense otherwise for non-project/multi-user directories 'newer' does.

2. That in an experimental/beta application breaking changes are valid. In theory, this could be implemented without breaking changes (mostly) by keeping the default as `--resync 'path1'` which perhaps at this stage is the preferred option. My reasoning for 'newer' as the default is I believe most coming to this tool will be coming from the usual suspects (Dropbox, OneDrive, etc..). I also agree, that as long as the option exists for 'newer' and is documented this covers all bases.

3. I agree, that having `--resync` is useful and shouldn't be removed from a power-user tool such as this. The reason I mentioned `--auto-resync 'newer' | ...` / removal is bisync can be a little sensitive and requiring a `--resync` is always a little daunting. Short of the prior listing not being present this should be minimised ideally to 0. However, this is perhaps better spoken about in another issue? Things such as filter changes shouldn't require a resync when a filter is added and when removed should try to sync without requiring a resync or perhaps a `--resync-filters` flag so one does not have to run the risk of a complete `--resync`. This can also be seen with a crashed sync - though nielash and I have spoken about this in another issue. Another reason is a user is just going to run a resync with their preferred method anyways as I can't see someone sitting and going through every diff file and manually syncing/merging each one to get back in sync. Ultimately, if  `--resync` can get to a place where it is seldom used then an `--auto-resync` flag seems unnecessary so perhaps should be ignored for now. 

**Decisions**

It would seem everybody agrees that bisync could benefit from being optimised to use existing `rclone copy`. So ignoring point 3 for now the only thing I believe left to decide is should the default:

- continue as asymmetric e.g. `--resync path1`
```
rclone copy Path2 Path1 --ignore-existing
rclone copy Path1 Path2
```
- change to symmetric e.g. `--resync newer`
```
rclone copy --update Path1 Path2
rclone copy --update Path2 Path1
```

And are these changes something @ncw (and everyone else) would be happy with. 

Thanks 🙏

EDIT: to show the commands of asymmetric and symmetric syncs
> 1. So  `--resync` can offer all options it would seem nielash and I are in agreement with the structure
> 
> `--resync 'newer' | 'path1' | 'path2' | 'older'`
> 
> I agree that for project directories (code, music, video, etc..), and perhaps some single-user environments, a 'path1'/'path2' resync can make a lot of sense otherwise for non-project/multi-user directories 'newer' does.

I agree -- this is a sensible approach, and allows each user to choose the best option for their own use case.

> Short of the prior listing not being present this should be minimised ideally to 0. However, this is perhaps better spoken about in another issue? Things such as filter changes shouldn't require a resync when a filter is added and when removed should try to sync without requiring a resync or perhaps a `--resync-filters` flag so one does not have to run the risk of a complete `--resync`. 

I think I understand what you're getting at -- which is that a `--resync` is technically superfluous for certain kinds of session changes, and that requiring a `--resync` when superfluous poses dangers of its own. So, I agree could be beneficial to consider decoupling the "user permission" pillar from the other two `--resync` pillars, when possible (perhaps similar to how `--force` currently serves that role for the `--max-delete` protection.) However, some filter changes really do require a `--resync`, if the change makes the filters more inclusive rather than less. Detecting this could be tricky, as a `--filters-file` can contain a combination of both include and exclude rules. I think we should consider this part of the Sessions project (#5678) and continue discussion about it there, independently from this ticket.

> It would seem everybody agrees that bisync could benefit from being optimised to use existing `rclone copy`.

Just to clarify: it already uses the same underlying function as `rclone copy`, but it does so after doing some unnecessary work to implement its own `--ignore-existing` logic, which also causes [problems with unicode normalization](https://github.com/rclone/rclone/issues/7270) and `--create-empty-src-dirs`, instead of just setting `ci.IgnoreExisting`. There is a way to fix that part of it without breaking anything, so I think that should be done regardless of whatever else we decide here.

> So ignoring point 3 for now the only thing I believe left to decide is should the default

Agree.

Fix patch:
diff --git a/cmd/bisync/bilib/names.go b/cmd/bisync/bilib/names.go
index 3093dff553c69..70d3d61be2cd5 100644
--- a/cmd/bisync/bilib/names.go
+++ b/cmd/bisync/bilib/names.go
@@ -5,6 +5,8 @@ import (
 	"os"
 	"sort"
 	"strconv"
+	"strings"
+	"time"
 )
 
 // Names comprises a set of file names
@@ -83,3 +85,81 @@ func (am AliasMap) Alias(name1 string) string {
 	}
 	return name1
 }
+
+// ParseGlobs determines whether a string contains {brackets}
+// and returns the substring (including both brackets) for replacing
+// substring is first opening bracket to last closing bracket --
+// good for {{this}} but not {this}{this}
+func ParseGlobs(s string) (hasGlobs bool, substring string) {
+	open := strings.Index(s, "{")
+	close := strings.LastIndex(s, "}")
+	if open >= 0 && close > open {
+		return true, s[open : close+1]
+	}
+	return false, ""
+}
+
+// TrimBrackets converts {{this}} to this
+func TrimBrackets(s string) string {
+	return strings.Trim(s, "{}")
+}
+
+// TimeFormat converts a user-supplied string to a Go time constant, if possible
+func TimeFormat(timeFormat string) string {
+	switch timeFormat {
+	case "Layout":
+		timeFormat = time.Layout
+	case "ANSIC":
+		timeFormat = time.ANSIC
+	case "UnixDate":
+		timeFormat = time.UnixDate
+	case "RubyDate":
+		timeFormat = time.RubyDate
+	case "RFC822":
+		timeFormat = time.RFC822
+	case "RFC822Z":
+		timeFormat = time.RFC822Z
+	case "RFC850":
+		timeFormat = time.RFC850
+	case "RFC1123":
+		timeFormat = time.RFC1123
+	case "RFC1123Z":
+		timeFormat = time.RFC1123Z
+	case "RFC3339":
+		timeFormat = time.RFC3339
+	case "RFC3339Nano":
+		timeFormat = time.RFC3339Nano
+	case "Kitchen":
+		timeFormat = time.Kitchen
+	case "Stamp":
+		timeFormat = time.Stamp
+	case "StampMilli":
+		timeFormat = time.StampMilli
+	case "StampMicro":
+		timeFormat = time.StampMicro
+	case "StampNano":
+		timeFormat = time.StampNano
+	case "DateTime":
+		// timeFormat = time.DateTime // missing in go1.19
+		timeFormat = "2006-01-02 15:04:05"
+	case "DateOnly":
+		// timeFormat = time.DateOnly // missing in go1.19
+		timeFormat = "2006-01-02"
+	case "TimeOnly":
+		// timeFormat = time.TimeOnly // missing in go1.19
+		timeFormat = "15:04:05"
+	case "MacFriendlyTime", "macfriendlytime", "mac":
+		timeFormat = "2006-01-02 0304PM" // not actually a Go constant -- but useful as macOS filenames can't have colons
+	}
+	return timeFormat
+}
+
+// AppyTimeGlobs converts "myfile-{DateOnly}.txt" to "myfile-2006-01-02.txt"
+func AppyTimeGlobs(s string, t time.Time) string {
+	hasGlobs, substring := ParseGlobs(s)
+	if !hasGlobs {
+		return s
+	}
+	timeString := t.Local().Format(TimeFormat(TrimBrackets(substring)))
+	return strings.ReplaceAll(s, substring, timeString)
+}
diff --git a/cmd/bisync/checkfn.go b/cmd/bisync/checkfn.go
index c5d5c12b597ed..8cc6e13c4534b 100644
--- a/cmd/bisync/checkfn.go
+++ b/cmd/bisync/checkfn.go
@@ -208,7 +208,14 @@ func (b *bisyncRun) EqualFn(ctx context.Context) context.Context {
 			fs.Debugf(src, "equal skipped")
 		}
 		ctxNoLogger := operations.WithLogger(ctx, noop)
-		if operations.Equal(ctxNoLogger, src, dst) {
+
+		timeSizeEqualFn := func() (equal bool, skipHash bool) { return operations.Equal(ctxNoLogger, src, dst), false } // normally use Equal()
+		if b.opt.ResyncMode == PreferOlder || b.opt.ResyncMode == PreferLarger || b.opt.ResyncMode == PreferSmaller {
+			timeSizeEqualFn = func() (equal bool, skipHash bool) { return b.resyncTimeSizeEqual(ctxNoLogger, src, dst) } // but override for --resync-mode older, larger, smaller
+		}
+		skipHash := false // (note that we might skip it anyway based on compare/ht settings)
+		equal, skipHash = timeSizeEqualFn()
+		if equal && !skipHash {
 			whichHashType := func(f fs.Info) hash.Type {
 				ht := getHashType(f.Name())
 				if ht == hash.None && b.opt.Compare.SlowHashSyncOnly && !b.opt.Resync {
@@ -233,3 +240,32 @@ func (b *bisyncRun) EqualFn(ctx context.Context) context.Context {
 	}
 	return operations.WithEqualFn(ctx, equalFn)
 }
+
+func (b *bisyncRun) resyncTimeSizeEqual(ctxNoLogger context.Context, src fs.ObjectInfo, dst fs.Object) (equal bool, skipHash bool) {
+	switch b.opt.ResyncMode {
+	case PreferLarger, PreferSmaller:
+		// note that arg order is path1, path2, regardless of src/dst
+		path1, path2 := b.resyncWhichIsWhich(src, dst)
+		if sizeDiffers(path1.Size(), path2.Size()) {
+			winningPath := b.resolveLargerSmaller(path1.Size(), path2.Size(), path1.Remote(), path2.Remote(), b.opt.ResyncMode)
+			// don't need to check/update modtime here, as sizes definitely differ and something will be transferred
+			return b.resyncWinningPathToEqual(winningPath), b.resyncWinningPathToEqual(winningPath) // skip hash check if true
+		}
+		// sizes equal or don't know, so continue to checking time/hash, if applicable
+		return operations.Equal(ctxNoLogger, src, dst), false // note we're back to src/dst, not path1/path2
+	case PreferOlder:
+		// note that arg order is path1, path2, regardless of src/dst
+		path1, path2 := b.resyncWhichIsWhich(src, dst)
+		if timeDiffers(ctxNoLogger, path1.ModTime(ctxNoLogger), path2.ModTime(ctxNoLogger), path1.Fs(), path2.Fs()) {
+			winningPath := b.resolveNewerOlder(path1.ModTime(ctxNoLogger), path2.ModTime(ctxNoLogger), path1.Remote(), path2.Remote(), b.opt.ResyncMode)
+			// if src is winner, proceed with equal to check size/hash and possibly just update dest modtime instead of transferring
+			if !b.resyncWinningPathToEqual(winningPath) {
+				return operations.Equal(ctxNoLogger, src, dst), false // note we're back to src/dst, not path1/path2
+			}
+			// if dst is winner (and definitely unequal), do not proceed further as we want dst to overwrite src regardless of size difference, and we do not want dest modtime updated
+			return true, true
+		}
+		// times equal or don't know, so continue to checking size/hash, if applicable
+	}
+	return operations.Equal(ctxNoLogger, src, dst), false // note we're back to src/dst, not path1/path2
+}
diff --git a/cmd/bisync/cmd.go b/cmd/bisync/cmd.go
index 6e5b95912bca5..b57bbf1ee8ca6 100644
--- a/cmd/bisync/cmd.go
+++ b/cmd/bisync/cmd.go
@@ -30,7 +30,8 @@ type TestFunc func()
 
 // Options keep bisync options
 type Options struct {
-	Resync                bool
+	Resync                bool   // whether or not this is a resync
+	ResyncMode            Prefer // which mode to use for resync
 	CheckAccess           bool
 	CheckFilename         string
 	CheckSync             CheckSyncMode
@@ -55,6 +56,11 @@ type Options struct {
 	CompareFlag           string
 	DebugName             string
 	MaxLock               time.Duration
+	ConflictResolve       Prefer
+	ConflictLoser         ConflictLoserAction
+	ConflictSuffixFlag    string
+	ConflictSuffix1       string
+	ConflictSuffix2       string
 }
 
 // Default values
@@ -118,7 +124,8 @@ func init() {
 	cmdFlags := commandDefinition.Flags()
 	// when adding new flags, remember to also update the rc params:
 	// cmd/bisync/rc.go cmd/bisync/help.go (not docs/content/rc.md)
-	flags.BoolVarP(cmdFlags, &Opt.Resync, "resync", "1", Opt.Resync, "Performs the resync run. Path1 files may overwrite Path2 versions. Consider using --verbose or --dry-run first.", "")
+	flags.BoolVarP(cmdFlags, &Opt.Resync, "resync", "1", Opt.Resync, "Performs the resync run. Equivalent to --resync-mode path1. Consider using --verbose or --dry-run first.", "")
+	flags.FVarP(cmdFlags, &Opt.ResyncMode, "resync-mode", "", "During resync, prefer the version that is: path1, path2, newer, older, larger, smaller (default: path1 if --resync, otherwise none for no resync.)", "")
 	flags.BoolVarP(cmdFlags, &Opt.CheckAccess, "check-access", "", Opt.CheckAccess, makeHelp("Ensure expected {CHECKFILE} files are found on both Path1 and Path2 filesystems, else abort."), "")
 	flags.StringVarP(cmdFlags, &Opt.CheckFilename, "check-filename", "", Opt.CheckFilename, makeHelp("Filename for --check-access (default: {CHECKFILE})"), "")
 	flags.BoolVarP(cmdFlags, &Opt.Force, "force", "", Opt.Force, "Bypass --max-delete safety check and run the sync. Consider using with --verbose", "")
@@ -141,6 +148,11 @@ func init() {
 	flags.BoolVarP(cmdFlags, &Opt.Compare.SlowHashSyncOnly, "slow-hash-sync-only", "", Opt.Compare.SlowHashSyncOnly, "Ignore slow checksums for listings and deltas, but still consider them during sync calls.", "")
 	flags.BoolVarP(cmdFlags, &Opt.Compare.DownloadHash, "download-hash", "", Opt.Compare.DownloadHash, "Compute hash by downloading when otherwise unavailable. (warning: may be slow and use lots of data!)", "")
 	flags.DurationVarP(cmdFlags, &Opt.MaxLock, "max-lock", "", Opt.MaxLock, "Consider lock files older than this to be expired (default: 0 (never expire)) (minimum: 2m)", "")
+	flags.FVarP(cmdFlags, &Opt.ConflictResolve, "conflict-resolve", "", "Automatically resolve conflicts by preferring the version that is: "+ConflictResolveList+" (default: none)", "")
+	flags.FVarP(cmdFlags, &Opt.ConflictLoser, "conflict-loser", "", "Action to take on the loser of a sync conflict (when there is a winner) or on both files (when there is no winner): "+ConflictLoserList+" (default: num)", "")
+	flags.StringVarP(cmdFlags, &Opt.ConflictSuffixFlag, "conflict-suffix", "", Opt.ConflictSuffixFlag, "Suffix to use when renaming a --conflict-loser. Can be either one string or two comma-separated strings to assign different suffixes to Path1/Path2. (default: 'conflict')", "")
+	_ = cmdFlags.MarkHidden("debugname")
+	_ = cmdFlags.MarkHidden("localtime")
 }
 
 // bisync command definition
@@ -154,6 +166,8 @@ var commandDefinition = &cobra.Command{
 		"status":            "Beta",
 	},
 	RunE: func(command *cobra.Command, args []string) error {
+		// NOTE: avoid putting too much handling here, as it won't apply to the rc.
+		// Generally it's best to put init-type stuff in Bisync() (operations.go)
 		cmd.CheckArgs(2, 2, command, args)
 		fs1, file1, fs2, file2 := cmd.NewFsSrcDstFiles(args)
 		if file1 != "" || file2 != "" {
diff --git a/cmd/bisync/deltas.go b/cmd/bisync/deltas.go
index 323d1c799fb70..167bd70fdc1c1 100644
--- a/cmd/bisync/deltas.go
+++ b/cmd/bisync/deltas.go
@@ -8,11 +8,11 @@ import (
 	"path/filepath"
 	"sort"
 	"strings"
+	"time"
 
 	"github.com/rclone/rclone/cmd/bisync/bilib"
 	"github.com/rclone/rclone/fs"
 	"github.com/rclone/rclone/fs/filter"
-	"github.com/rclone/rclone/fs/operations"
 	"github.com/rclone/rclone/lib/terminal"
 	"golang.org/x/text/unicode/norm"
 )
@@ -46,6 +46,7 @@ func (d delta) is(cond delta) bool {
 type deltaSet struct {
 	deltas     map[string]delta
 	size       map[string]int64
+	time       map[string]time.Time
 	hash       map[string]string
 	opt        *Options
 	fs         fs.Fs  // base filesystem
@@ -170,6 +171,7 @@ func (b *bisyncRun) findDeltas(fctx context.Context, f fs.Fs, oldListing string,
 	ds = &deltaSet{
 		deltas:     map[string]delta{},
 		size:       map[string]int64{},
+		time:       map[string]time.Time{},
 		hash:       map[string]string{},
 		fs:         f,
 		msg:        msg,
@@ -183,6 +185,7 @@ func (b *bisyncRun) findDeltas(fctx context.Context, f fs.Fs, oldListing string,
 		d := deltaZero
 		s := int64(0)
 		h := ""
+		var t time.Time
 		if !now.has(file) {
 			b.indent(msg, file, Color(terminal.RedFg, "File was deleted"))
 			ds.deleted++
@@ -215,6 +218,7 @@ func (b *bisyncRun) findDeltas(fctx context.Context, f fs.Fs, oldListing string,
 							whatchanged = append(whatchanged, Color(terminal.MagentaFg, "time (older)"))
 							d |= deltaOlder
 						}
+						t = now.getTime(file)
 					}
 				}
 				if b.opt.Compare.Checksum {
@@ -238,6 +242,9 @@ func (b *bisyncRun) findDeltas(fctx context.Context, f fs.Fs, oldListing string,
 			if b.opt.Compare.Size {
 				ds.size[file] = s
 			}
+			if b.opt.Compare.Modtime {
+				ds.time[file] = t
+			}
 			if b.opt.Compare.Checksum {
 				ds.hash[file] = h
 			}
@@ -258,6 +265,9 @@ func (b *bisyncRun) findDeltas(fctx context.Context, f fs.Fs, oldListing string,
 			if b.opt.Compare.Size {
 				ds.size[file] = now.getSize(file)
 			}
+			if b.opt.Compare.Modtime {
+				ds.time[file] = now.getTime(file)
+			}
 			if b.opt.Compare.Checksum {
 				ds.hash[file] = now.getHash(file)
 			}
@@ -287,12 +297,11 @@ func (b *bisyncRun) applyDeltas(ctx context.Context, ds1, ds2 *deltaSet) (change
 	delete1 := bilib.Names{}
 	delete2 := bilib.Names{}
 	handled := bilib.Names{}
-	renamed1 := bilib.Names{}
-	renamed2 := bilib.Names{}
 	renameSkipped := bilib.Names{}
 	deletedonboth := bilib.Names{}
 	skippedDirs1 := newFileList()
 	skippedDirs2 := newFileList()
+	b.renames = renames{}
 
 	ctxMove := b.opt.setDryRun(ctx)
 
@@ -422,34 +431,10 @@ func (b *bisyncRun) applyDeltas(ctx context.Context, ds1, ds2 *deltaSet) (change
 						}
 					} else {
 						fs.Debugf(nil, "Files are NOT equal: %s", file)
-						b.indent("!Path1", p1+"..path1", "Renaming Path1 copy")
-						ctxMove = b.setBackupDir(ctxMove, 1) // in case already a file with new name
-						if err = operations.MoveFile(ctxMove, b.fs1, b.fs1, file+"..path1", file); err != nil {
-							err = fmt.Errorf("path1 rename failed for %s: %w", p1, err)
-							b.critical = true
+						err = b.resolve(ctxMove, path1, path2, file, alias, &renameSkipped, &copy1to2, &copy2to1, ds1, ds2)
+						if err != nil {
 							return
 						}
-						if b.opt.DryRun {
-							renameSkipped.Add(file)
-						} else {
-							renamed1.Add(file)
-						}
-						b.indent("!Path1", p2+"..path1", "Queue copy to Path2")
-						copy1to2.Add(file + "..path1")
-
-						b.indent("!Path2", p2+"..path2", "Renaming Path2 copy")
-						ctxMove = b.setBackupDir(ctxMove, 2) // in case already a file with new name
-						if err = operations.MoveFile(ctxMove, b.fs2, b.fs2, alias+"..path2", alias); err != nil {
-							err = fmt.Errorf("path2 rename failed for %s: %w", alias, err)
-							return
-						}
-						if b.opt.DryRun {
-							renameSkipped.Add(alias)
-						} else {
-							renamed2.Add(alias)
-						}
-						b.indent("!Path2", p1+"..path2", "Queue copy to Path1")
-						copy2to1.Add(alias + "..path2")
 					}
 				}
 				handled.Add(file)
@@ -554,8 +539,6 @@ func (b *bisyncRun) applyDeltas(ctx context.Context, ds1, ds2 *deltaSet) (change
 
 	queues.copy1to2 = copy1to2
 	queues.copy2to1 = copy2to1
-	queues.renamed1 = renamed1
-	queues.renamed2 = renamed2
 	queues.renameSkipped = renameSkipped
 	queues.deletedonboth = deletedonboth
 	queues.skippedDirs1 = skippedDirs1
diff --git a/cmd/bisync/listing.go b/cmd/bisync/listing.go
index 827a2e14ca2cb..8f6d8eb194a45 100644
--- a/cmd/bisync/listing.go
+++ b/cmd/bisync/listing.go
@@ -77,6 +77,10 @@ func (ls *fileList) empty() bool {
 }
 
 func (ls *fileList) has(file string) bool {
+	if file == "" {
+		fs.Debugf(nil, "called ls.has() with blank string")
+		return false
+	}
 	_, found := ls.info[file]
 	if !found {
 		//try unquoting
@@ -467,11 +471,9 @@ func ConvertPrecision(Modtime time.Time, dst fs.Fs) time.Time {
 // modifyListing will modify the listing based on the results of the sync
 func (b *bisyncRun) modifyListing(ctx context.Context, src fs.Fs, dst fs.Fs, results []Results, queues queues, is1to2 bool) (err error) {
 	queue := queues.copy2to1
-	renames := queues.renamed2
 	direction := "2to1"
 	if is1to2 {
 		queue = queues.copy1to2
-		renames = queues.renamed1
 		direction = "1to2"
 	}
 
@@ -596,37 +598,39 @@ func (b *bisyncRun) modifyListing(ctx context.Context, src fs.Fs, dst fs.Fs, res
 			dstList.remove(file)
 		}
 	}
-	if renames.NotEmpty() && !b.opt.DryRun {
+	if b.renames.NotEmpty() && !b.opt.DryRun {
 		// renamed on src and copied to dst
-		renamesList := renames.ToList()
-		for _, file := range renamesList {
+		for _, rename := range b.renames {
+			srcOldName, srcNewName, dstOldName, dstNewName := rename.getNames(is1to2)
+			fs.Debugf(nil, "%s: srcOldName: %v srcNewName: %v dstOldName: %v dstNewName: %v", direction, srcOldName, srcNewName, dstOldName, dstNewName)
 			// we'll handle the other side when we go the other direction
-			newName := file + "..path2"
-			oppositeName := file + "..path1"
-			if is1to2 {
-				newName = file + "..path1"
-				oppositeName = file + "..path2"
-			}
 			var new *fileInfo
-			// we prefer to get the info from the ..path1 / ..path2 versions
+			// we prefer to get the info from the newNamed versions
 			// since they were actually copied as opposed to operations.MoveFile()'d.
 			// the size/time/hash info is therefore fresher on the renames
 			// but we'll settle for the original if we have to.
-			if srcList.has(newName) {
-				new = srcList.get(newName)
-			} else if srcList.has(oppositeName) {
-				new = srcList.get(oppositeName)
-			} else if srcList.has(file) {
-				new = srcList.get(file)
+			if srcList.has(srcNewName) {
+				new = srcList.get(srcNewName)
+			} else if srcList.has(dstNewName) {
+				new = srcList.get(dstNewName)
+			} else if srcList.has(srcOldName) {
+				new = srcList.get(srcOldName)
 			} else {
-				if err := filterRecheck.AddFile(file); err != nil {
-					fs.Debugf(file, "error adding file to recheck filter: %v", err)
+				// something's odd, so let's recheck
+				if err := filterRecheck.AddFile(srcOldName); err != nil {
+					fs.Debugf(srcOldName, "error adding file to recheck filter: %v", err)
 				}
 			}
-			srcList.put(newName, new.size, new.time, new.hash, new.id, new.flags)
-			dstList.put(newName, new.size, ConvertPrecision(new.time, src), new.hash, new.id, new.flags)
-			srcList.remove(file)
-			dstList.remove(file)
+			if srcNewName != "" { // if it was renamed and not deleted
+				srcList.put(srcNewName, new.size, new.time, new.hash, new.id, new.flags)
+				dstList.put(srcNewName, new.size, ConvertPrecision(new.time, src), new.hash, new.id, new.flags)
+			}
+			if srcNewName != srcOldName {
+				srcList.remove(srcOldName)
+			}
+			if srcNewName != dstOldName {
+				dstList.remove(dstOldName)
+			}
 		}
 	}
 
diff --git a/cmd/bisync/log.go b/cmd/bisync/log.go
index efc91eaed0c37..9d2e5b046bcb5 100644
--- a/cmd/bisync/log.go
+++ b/cmd/bisync/log.go
@@ -62,8 +62,13 @@ func quotePath(path string) string {
 	return escapePath(path, true)
 }
 
+var Colors bool // Colors controls whether terminal colors are enabled
+
 // Color handles terminal colors for bisync
 func Color(style string, s string) string {
+	if !Colors {
+		return s
+	}
 	terminal.Start()
 	return style + s + terminal.Reset
 }
diff --git a/cmd/bisync/operations.go b/cmd/bisync/operations.go
index 15c9e32ffc57a..432ceaee4fe64 100644
--- a/cmd/bisync/operations.go
+++ b/cmd/bisync/operations.go
@@ -17,7 +17,7 @@ import (
 	"github.com/rclone/rclone/cmd/bisync/bilib"
 	"github.com/rclone/rclone/fs"
 	"github.com/rclone/rclone/fs/accounting"
-	"github.com/rclone/rclone/fs/filter"
+	"github.com/rclone/rclone/fs/log"
 	"github.com/rclone/rclone/fs/operations"
 	"github.com/rclone/rclone/lib/atexit"
 	"github.com/rclone/rclone/lib/terminal"
@@ -49,13 +49,13 @@ type bisyncRun struct {
 	CancelSync         context.CancelFunc
 	DebugName          string
 	lockFile           string
+	renames            renames
+	resyncIs1to2       bool
 }
 
 type queues struct {
 	copy1to2      bilib.Names
 	copy2to1      bilib.Names
-	renamed1      bilib.Names // renamed on 1 and copied to 2
-	renamed2      bilib.Names // renamed on 2 and copied to 1
 	renameSkipped bilib.Names // not renamed because it was equal
 	skippedDirs1  *fileList
 	skippedDirs2  *fileList
@@ -82,11 +82,22 @@ func Bisync(ctx context.Context, fs1, fs2 fs.Fs, optArg *Options) (err error) {
 	ci := fs.GetConfig(ctx)
 	opt.OrigBackupDir = ci.BackupDir
 
+	if ci.TerminalColorMode == fs.TerminalColorModeAlways || (ci.TerminalColorMode == fs.TerminalColorModeAuto && !log.Redirected()) {
+		Colors = true
+	}
+
 	err = b.setCompareDefaults(ctx)
 	if err != nil {
 		return err
 	}
 
+	b.setResyncDefaults()
+
+	err = b.setResolveDefaults(ctx)
+	if err != nil {
+		return err
+	}
+
 	if b.workDir, err = filepath.Abs(opt.Workdir); err != nil {
 		return fmt.Errorf("failed to make workdir absolute: %w", err)
 	}
@@ -462,133 +473,6 @@ func (b *bisyncRun) runLocked(octx context.Context) (err error) {
 	return nil
 }
 
-// resync implements the --resync mode.
-// It will generate path1 and path2 listings
-// and copy any unique path2 files to path1.
-func (b *bisyncRun) resync(octx, fctx context.Context) error {
-	fs.Infof(nil, "Copying unique Path2 files to Path1")
-
-	// Save blank filelists (will be filled from sync results)
-	var ls1 = newFileList()
-	var ls2 = newFileList()
-	err = ls1.save(fctx, b.newListing1)
-	if err != nil {
-		b.handleErr(ls1, "error saving ls1 from resync", err, true, true)
-		b.abort = true
-	}
-	err = ls2.save(fctx, b.newListing2)
-	if err != nil {
-		b.handleErr(ls2, "error saving ls2 from resync", err, true, true)
-		b.abort = true
-	}
-
-	// Check access health on the Path1 and Path2 filesystems
-	// enforce even though this is --resync
-	if b.opt.CheckAccess {
-		fs.Infof(nil, "Checking access health")
-
-		filesNow1, filesNow2, err := b.findCheckFiles(fctx)
-		if err != nil {
-			b.critical = true
-			b.retryable = true
-			return err
-		}
-
-		ds1 := &deltaSet{
-			checkFiles: bilib.Names{},
-		}
-
-		ds2 := &deltaSet{
-			checkFiles: bilib.Names{},
-		}
-
-		for _, file := range filesNow1.list {
-			if filepath.Base(file) == b.opt.CheckFilename {
-				ds1.checkFiles.Add(file)
-			}
-		}
-
-		for _, file := range filesNow2.list {
-			if filepath.Base(file) == b.opt.CheckFilename {
-				ds2.checkFiles.Add(file)
-			}
-		}
-
-		err = b.checkAccess(ds1.checkFiles, ds2.checkFiles)
-		if err != nil {
-			b.critical = true
-			b.retryable = true
-			return err
-		}
-	}
-
-	var results2to1 []Results
-	var results1to2 []Results
-	queues := queues{}
-
-	b.indent("Path2", "Path1", "Resync is copying UNIQUE files to")
-	ctxRun := b.opt.setDryRun(fctx)
-	// fctx has our extra filters added!
-	ctxSync, filterSync := filter.AddConfig(ctxRun)
-	if filterSync.Opt.MinSize == -1 {
-		fs.Debugf(nil, "filterSync.Opt.MinSize: %v", filterSync.Opt.MinSize)
-	}
-	ci := fs.GetConfig(ctxSync)
-	ci.IgnoreExisting = true
-	ctxSync = b.setBackupDir(ctxSync, 1)
-	// 2 to 1
-	if results2to1, err = b.resyncDir(ctxSync, b.fs2, b.fs1); err != nil {
-		b.critical = true
-		return err
-	}
-
-	b.indent("Path1", "Path2", "Resync is copying UNIQUE OR DIFFERING files to")
-	ci.IgnoreExisting = false
-	ctxSync = b.setBackupDir(ctxSync, 2)
-	// 1 to 2
-	if results1to2, err = b.resyncDir(ctxSync, b.fs1, b.fs2); err != nil {
-		b.critical = true
-		return err
-	}
-
-	fs.Infof(nil, "Resync updating listings")
-	b.saveOldListings() // may not exist, as this is --resync
-	b.replaceCurrentListings()
-
-	resultsToQueue := func(results []Results) bilib.Names {
-		names := bilib.Names{}
-		for _, result := range results {
-			if result.Name != "" &&
-				(result.Flags != "d" || b.opt.CreateEmptySrcDirs) &&
-				result.IsSrc && result.Src != "" &&
-				(result.Winner.Err == nil || result.Flags == "d") {
-				names.Add(result.Name)
-			}
-		}
-		return names
-	}
-
-	// resync 2to1
-	queues.copy2to1 = resultsToQueue(results2to1)
-	if err = b.modifyListing(fctx, b.fs2, b.fs1, results2to1, queues, false); err != nil {
-		b.critical = true
-		return err
-	}
-
-	// resync 1to2
-	queues.copy1to2 = resultsToQueue(results1to2)
-	if err = b.modifyListing(fctx, b.fs1, b.fs2, results1to2, queues, true); err != nil {
-		b.critical = true
-		return err
-	}
-
-	if !b.opt.NoCleanup {
-		_ = os.Remove(b.newListing1)
-		_ = os.Remove(b.newListing2)
-	}
-	return nil
-}
-
 // checkSync validates listings
 func (b *bisyncRun) checkSync(listing1, listing2 string) error {
 	files1, err := b.loadListing(listing1)
diff --git a/cmd/bisync/queue.go b/cmd/bisync/queue.go
index 120b9e9bd2963..8b5cd0801bdeb 100644
--- a/cmd/bisync/queue.go
+++ b/cmd/bisync/queue.go
@@ -202,6 +202,11 @@ func (b *bisyncRun) preCopy(ctx context.Context) context.Context {
 		// otherwise impossible in Sync, so override Equal
 		ctx = b.EqualFn(ctx)
 	}
+	if b.opt.ResyncMode == PreferOlder || b.opt.ResyncMode == PreferLarger || b.opt.ResyncMode == PreferSmaller {
+		overridingEqual = true
+		fs.Debugf(nil, "overriding equal")
+		ctx = b.EqualFn(ctx)
+	}
 	ctxCopyLogger := operations.WithSyncLogger(ctx, logger)
 	if b.opt.Compare.Checksum && (b.opt.Compare.NoSlowHash || b.opt.Compare.SlowHashSyncOnly) && b.opt.Compare.SlowHashDetected {
 		// set here in case !b.opt.Compare.Modtime
diff --git a/cmd/bisync/resolve.go b/cmd/bisync/resolve.go
new file mode 100644
index 0000000000000..e9c57a7d0034b
--- /dev/null
+++ b/cmd/bisync/resolve.go
@@ -0,0 +1,450 @@
+package bisync
+
+import (
+	"context"
+	"fmt"
+	"math"
+	"mime"
+	"path"
+	"strings"
+	"time"
+
+	"github.com/rclone/rclone/cmd/bisync/bilib"
+	"github.com/rclone/rclone/fs"
+	"github.com/rclone/rclone/fs/operations"
+	"github.com/rclone/rclone/lib/terminal"
+)
+
+// Prefer describes strategies for resolving sync conflicts
+type Prefer = fs.Enum[preferChoices]
+
+// Supported --conflict-resolve strategies
+const (
+	PreferNone Prefer = iota
+	PreferPath1
+	PreferPath2
+	PreferNewer
+	PreferOlder
+	PreferLarger
+	PreferSmaller
+)
+
+type preferChoices struct{}
+
+func (preferChoices) Choices() []string {
+	return []string{
+		PreferNone:    "none",
+		PreferNewer:   "newer",
+		PreferOlder:   "older",
+		PreferLarger:  "larger",
+		PreferSmaller: "smaller",
+		PreferPath1:   "path1",
+		PreferPath2:   "path2",
+	}
+}
+
+func (preferChoices) Type() string {
+	return "string"
+}
+
+// ConflictResolveList is a list of --conflict-resolve flag choices used in the help
+var ConflictResolveList = Opt.ConflictResolve.Help()
+
+// ConflictLoserAction describes possible actions to take on the loser of a sync conflict
+type ConflictLoserAction = fs.Enum[conflictLoserChoices]
+
+// Supported --conflict-loser actions
+const (
+	ConflictLoserSkip     ConflictLoserAction = iota // Reserved as zero but currently unused
+	ConflictLoserNumber                              // file.conflict1, file.conflict2, file.conflict3, etc.
+	ConflictLoserPathname                            // file.path1, file.path2
+	ConflictLoserDelete                              // delete the loser, keep winner only
+)
+
+type conflictLoserChoices struct{}
+
+func (conflictLoserChoices) Choices() []string {
+	return []string{
+		ConflictLoserNumber:   "num",
+		ConflictLoserPathname: "pathname",
+		ConflictLoserDelete:   "delete",
+	}
+}
+
+func (conflictLoserChoices) Type() string {
+	return "ConflictLoserAction"
+}
+
+// ConflictLoserList is a list of --conflict-loser flag choices used in the help
+var ConflictLoserList = Opt.ConflictLoser.Help()
+
+func (b *bisyncRun) setResolveDefaults(ctx context.Context) error {
+	if b.opt.ConflictLoser == ConflictLoserSkip {
+		b.opt.ConflictLoser = ConflictLoserNumber
+	}
+	if b.opt.ConflictSuffixFlag == "" {
+		b.opt.ConflictSuffixFlag = "conflict"
+	}
+	suffixes := strings.Split(b.opt.ConflictSuffixFlag, ",")
+	if len(suffixes) == 1 {
+		b.opt.ConflictSuffix1 = suffixes[0]
+		b.opt.ConflictSuffix2 = suffixes[0]
+	} else if len(suffixes) == 2 {
+		b.opt.ConflictSuffix1 = suffixes[0]
+		b.opt.ConflictSuffix2 = suffixes[1]
+	} else {
+		return fmt.Errorf("--conflict-suffix cannot have more than 2 comma-separated values. Received %v: %v", len(suffixes), suffixes)
+	}
+	// replace glob variables, if any
+	t := time.Now() // capture static time here so it is the same for all files throughout this run
+	b.opt.ConflictSuffix1 = bilib.AppyTimeGlobs(b.opt.ConflictSuffix1, t)
+	b.opt.ConflictSuffix2 = bilib.AppyTimeGlobs(b.opt.ConflictSuffix2, t)
+
+	// append dot (intentionally allow more than one)
+	b.opt.ConflictSuffix1 = "." + b.opt.ConflictSuffix1
+	b.opt.ConflictSuffix2 = "." + b.opt.ConflictSuffix2
+
+	// checks and warnings
+	if (b.opt.ConflictResolve == PreferNewer || b.opt.ConflictResolve == PreferOlder) && (b.fs1.Precision() == fs.ModTimeNotSupported || b.fs2.Precision() == fs.ModTimeNotSupported) {
+		fs.Logf(nil, Color(terminal.YellowFg, "WARNING: ignoring --conflict-resolve %s as at least one remote does not support modtimes."), b.opt.ConflictResolve.String())
+		b.opt.ConflictResolve = PreferNone
+	} else if (b.opt.ConflictResolve == PreferNewer || b.opt.ConflictResolve == PreferOlder) && !b.opt.Compare.Modtime {
+		fs.Logf(nil, Color(terminal.YellowFg, "WARNING: ignoring --conflict-resolve %s as --compare does not include modtime."), b.opt.ConflictResolve.String())
+		b.opt.ConflictResolve = PreferNone
+	}
+	if (b.opt.ConflictResolve == PreferLarger || b.opt.ConflictResolve == PreferSmaller) && !b.opt.Compare.Size {
+		fs.Logf(nil, Color(terminal.YellowFg, "WARNING: ignoring --conflict-resolve %s as --compare does not include size."), b.opt.ConflictResolve.String())
+		b.opt.ConflictResolve = PreferNone
+	}
+
+	return nil
+}
+
+type renames map[string]renamesInfo // [originalName]newName (remember the originalName may have an alias)
+// the newName may be the same as the old name (if winner), but should not be blank, unless we're deleting.
+// the oldNames may not match each other, if we're normalizing case or unicode
+// all names should be "remotes" (relative names, without base path)
+type renamesInfo struct {
+	path1 namePair
+	path2 namePair
+}
+type namePair struct {
+	oldName string
+	newName string
+}
+
+func (b *bisyncRun) resolve(ctxMove context.Context, path1, path2, file, alias string, renameSkipped, copy1to2, copy2to1 *bilib.Names, ds1, ds2 *deltaSet) error {
+	winningPath := 0
+	if b.opt.ConflictResolve != PreferNone {
+		winningPath = b.conflictWinner(ds1, ds2, file, alias)
+		if winningPath > 0 {
+			fs.Infof(file, Color(terminal.GreenFg, "The winner is: Path%d"), winningPath)
+		} else {
+			fs.Infof(file, Color(terminal.RedFg, "A winner could not be determined."))
+		}
+	}
+
+	suff1 := b.opt.ConflictSuffix1 // copy to new var to make sure our changes here don't persist
+	suff2 := b.opt.ConflictSuffix2
+	if b.opt.ConflictLoser == ConflictLoserPathname && b.opt.ConflictSuffix1 == b.opt.ConflictSuffix2 {
+		// numerate, but not if user supplied two different suffixes
+		suff1 += "1"
+		suff2 += "2"
+	}
+
+	r := renamesInfo{
+		path1: namePair{
+			oldName: file,
+			newName: SuffixName(ctxMove, file, suff1),
+		},
+		path2: namePair{
+			oldName: alias,
+			newName: SuffixName(ctxMove, alias, suff2),
+		},
+	}
+
+	// handle auto-numbering
+	// note that we still queue copies for both files, whether or not we renamed
+	// we also set these for ConflictLoserDelete in case there is no winner.
+	if b.opt.ConflictLoser == ConflictLoserNumber || b.opt.ConflictLoser == ConflictLoserDelete {
+		num := b.numerate(ctxMove, 1, file, alias)
+		switch winningPath {
+		case 1: // keep path1, rename path2
+			r.path1.newName = r.path1.oldName
+			r.path2.newName = SuffixName(ctxMove, r.path2.oldName, b.opt.ConflictSuffix2+fmt.Sprint(num))
+		case 2: // keep path2, rename path1
+			r.path1.newName = SuffixName(ctxMove, r.path1.oldName, b.opt.ConflictSuffix1+fmt.Sprint(num))
+			r.path2.newName = r.path2.oldName
+		default: // no winner, so rename both to different numbers (unless suffixes are already different)
+			if b.opt.ConflictSuffix1 == b.opt.ConflictSuffix2 {
+				r.path1.newName = SuffixName(ctxMove, r.path1.oldName, b.opt.ConflictSuffix1+fmt.Sprint(num))
+				// let's just make sure num + 1 is available...
+				num2 := b.numerate(ctxMove, num+1, file, alias)
+				r.path2.newName = SuffixName(ctxMove, r.path2.oldName, b.opt.ConflictSuffix2+fmt.Sprint(num2))
+			} else {
+				// suffixes are different, so numerate independently
+				num = b.numerateSingle(ctxMove, 1, file, alias, 1)
+				r.path1.newName = SuffixName(ctxMove, r.path1.oldName, b.opt.ConflictSuffix1+fmt.Sprint(num))
+				num = b.numerateSingle(ctxMove, 1, file, alias, 2)
+				r.path2.newName = SuffixName(ctxMove, r.path2.oldName, b.opt.ConflictSuffix2+fmt.Sprint(num))
+			}
+		}
+	}
+
+	// when winningPath == 0 (no winner), we ignore settings and rename both, do not delete
+	// note also that deletes and renames are mutually exclusive -- we never delete one path and rename the other.
+	if b.opt.ConflictLoser == ConflictLoserDelete && winningPath == 1 {
+		// delete 2, copy 1 to 2
+		err = b.delete(ctxMove, r.path2, path2, path1, b.fs2, 2, 1, renameSkipped)
+		if err != nil {
+			return err
+		}
+		r.path2.newName = ""
+		// copy the one that wasn't deleted
+		b.indent("Path1", r.path1.oldName, "Queue copy to Path2")
+		copy1to2.Add(r.path1.oldName)
+	} else if b.opt.ConflictLoser == ConflictLoserDelete && winningPath == 2 {
+		// delete 1, copy 2 to 1
+		err = b.delete(ctxMove, r.path1, path1, path2, b.fs1, 1, 2, renameSkipped)
+		if err != nil {
+			return err
+		}
+		r.path1.newName = ""
+		// copy the one that wasn't deleted
+		b.indent("Path2", r.path2.oldName, "Queue copy to Path1")
+		copy2to1.Add(r.path2.oldName)
+	} else {
+		err = b.rename(ctxMove, r.path1, path1, path2, b.fs1, 1, 2, winningPath, copy1to2, renameSkipped)
+		if err != nil {
+			return err
+		}
+		err = b.rename(ctxMove, r.path2, path2, path1, b.fs2, 2, 1, winningPath, copy2to1, renameSkipped)
+		if err != nil {
+			return err
+		}
+	}
+
+	b.renames[r.path1.oldName] = r // note map index is path1's oldName, which may be different from path2 if aliases
+	return nil
+}
+
+// SuffixName adds the current --conflict-suffix to the remote, obeying
+// --suffix-keep-extension if set
+// It is a close cousin of operations.SuffixName, but we don't want to
+// use ci.Suffix for this because it might be used for --backup-dir.
+func SuffixName(ctx context.Context, remote, suffix string) string {
+	if suffix == "" {
+		return remote
+	}
+	ci := fs.GetConfig(ctx)
+	if ci.SuffixKeepExtension {
+		var (
+			base  = remote
+			exts  = ""
+			first = true
+			ext   = path.Ext(remote)
+		)
+		for ext != "" {
+			// Look second and subsequent extensions in mime types.
+			// If they aren't found then don't keep it as an extension.
+			if !first && mime.TypeByExtension(ext) == "" {
+				break
+			}
+			base = base[:len(base)-len(ext)]
+			exts = ext + exts
+			first = false
+			ext = path.Ext(base)
+		}
+		return base + suffix + exts
+	}
+	return remote + suffix
+}
+
+// NotEmpty checks whether set is not empty
+func (r renames) NotEmpty() bool {
+	return len(r) > 0
+}
+
+func (ri *renamesInfo) getNames(is1to2 bool) (srcOldName, srcNewName, dstOldName, dstNewName string) {
+	if is1to2 {
+		return ri.path1.oldName, ri.path1.newName, ri.path2.oldName, ri.path2.newName
+	}
+	return ri.path2.oldName, ri.path2.newName, ri.path1.oldName, ri.path1.newName
+}
+
+// work out the lowest number that niether side has, return it for suffix
+func (b *bisyncRun) numerate(ctx context.Context, startnum int, file, alias string) int {
+	for i := startnum; i < math.MaxInt; i++ {
+		iStr := fmt.Sprint(i)
+		if !ls1.has(SuffixName(ctx, file, b.opt.ConflictSuffix1+iStr)) &&
+			!ls1.has(SuffixName(ctx, alias, b.opt.ConflictSuffix1+iStr)) &&
+			!ls2.has(SuffixName(ctx, file, b.opt.ConflictSuffix2+iStr)) &&
+			!ls2.has(SuffixName(ctx, alias, b.opt.ConflictSuffix2+iStr)) {
+			// make sure it still holds true with suffixes switched (it should)
+			if !ls1.has(SuffixName(ctx, file, b.opt.ConflictSuffix2+iStr)) &&
+				!ls1.has(SuffixName(ctx, alias, b.opt.ConflictSuffix2+iStr)) &&
+				!ls2.has(SuffixName(ctx, file, b.opt.ConflictSuffix1+iStr)) &&
+				!ls2.has(SuffixName(ctx, alias, b.opt.ConflictSuffix1+iStr)) {
+				fs.Debugf(file, "The first available suffix is: %s", iStr)
+				return i
+			}
+		}
+	}
+	return 0 // not really possible, as no one has 9223372036854775807 conflicts, and if they do, they have bigger problems
+}
+
+// like numerate, but consider only one side's suffix (for when suffixes are different)
+func (b *bisyncRun) numerateSingle(ctx context.Context, startnum int, file, alias string, path int) int {
+	lsA, lsB := ls1, ls2
+	suffix := b.opt.ConflictSuffix1
+	if path == 2 {
+		lsA, lsB = ls2, ls1
+		suffix = b.opt.ConflictSuffix2
+	}
+	for i := startnum; i < math.MaxInt; i++ {
+		iStr := fmt.Sprint(i)
+		if !lsA.has(SuffixName(ctx, file, suffix+iStr)) &&
+			!lsA.has(SuffixName(ctx, alias, suffix+iStr)) &&
+			!lsB.has(SuffixName(ctx, file, suffix+iStr)) &&
+			!lsB.has(SuffixName(ctx, alias, suffix+iStr)) {
+			fs.Debugf(file, "The first available suffix is: %s", iStr)
+			return i
+		}
+	}
+	return 0 // not really possible, as no one has 9223372036854775807 conflicts, and if they do, they have bigger problems
+}
+
+func (b *bisyncRun) rename(ctx context.Context, thisNamePair namePair, thisPath, thatPath string, thisFs fs.Fs, thisPathNum, thatPathNum, winningPath int, q, renameSkipped *bilib.Names) error {
+	if winningPath == thisPathNum {
+		b.indent(fmt.Sprintf("!Path%d", thisPathNum), thisPath+thisNamePair.newName, fmt.Sprintf("Not renaming Path%d copy, as it was determined the winner", thisPathNum))
+	} else {
+		skip := operations.SkipDestructive(ctx, thisNamePair.oldName, "rename")
+		if !skip {
+			b.indent(fmt.Sprintf("!Path%d", thisPathNum), thisPath+thisNamePair.newName, fmt.Sprintf("Renaming Path%d copy", thisPathNum))
+			ctx = b.setBackupDir(ctx, thisPathNum) // in case already a file with new name
+			if err = operations.MoveFile(ctx, thisFs, thisFs, thisNamePair.newName, thisNamePair.oldName); err != nil {
+				err = fmt.Errorf("%s rename failed for %s: %w", thisPath, thisPath+thisNamePair.oldName, err)
+				b.critical = true
+				return err
+			}
+		} else {
+			renameSkipped.Add(thisNamePair.oldName) // (due to dry-run, not equality)
+		}
+	}
+	b.indent(fmt.Sprintf("!Path%d", thisPathNum), thatPath+thisNamePair.newName, fmt.Sprintf("Queue copy to Path%d", thatPathNum))
+	q.Add(thisNamePair.newName)
+	return nil
+}
+
+func (b *bisyncRun) delete(ctx context.Context, thisNamePair namePair, thisPath, thatPath string, thisFs fs.Fs, thisPathNum, thatPathNum int, renameSkipped *bilib.Names) error {
+	skip := operations.SkipDestructive(ctx, thisNamePair.oldName, "delete")
+	if !skip {
+		b.indent(fmt.Sprintf("!Path%d", thisPathNum), thisPath+thisNamePair.oldName, fmt.Sprintf("Deleting Path%d copy", thisPathNum))
+		ctx = b.setBackupDir(ctx, thisPathNum)
+		ci := fs.GetConfig(ctx)
+		var backupDir fs.Fs
+		if ci.BackupDir != "" {
+			backupDir, err = operations.BackupDir(ctx, thisFs, thisFs, thisNamePair.oldName)
+			if err != nil {
+				b.critical = true
+				return err
+			}
+		}
+		obj, err := thisFs.NewObject(ctx, thisNamePair.oldName)
+		if err != nil {
+			b.critical = true
+			return err
+		}
+		if err = operations.DeleteFileWithBackupDir(ctx, obj, backupDir); err != nil {
+			err = fmt.Errorf("%s delete failed for %s: %w", thisPath, thisPath+thisNamePair.oldName, err)
+			b.critical = true
+			return err
+		}
+	} else {
+		renameSkipped.Add(thisNamePair.oldName) // (due to dry-run, not equality)
+	}
+	return nil
+}
+
+func (b *bisyncRun) conflictWinner(ds1, ds2 *deltaSet, remote1, remote2 string) int {
+	switch b.opt.ConflictResolve {
+	case PreferPath1:
+		return 1
+	case PreferPath2:
+		return 2
+	case PreferNewer, PreferOlder:
+		t1, t2 := ds1.time[remote1], ds2.time[remote2]
+		return b.resolveNewerOlder(t1, t2, remote1, remote2, b.opt.ConflictResolve)
+	case PreferLarger, PreferSmaller:
+		s1, s2 := ds1.size[remote1], ds2.size[remote2]
+		return b.resolveLargerSmaller(s1, s2, remote1, remote2, b.opt.ConflictResolve)
+	default:
+		return 0
+	}
+}
+
+// returns the winning path number, or 0 if winner can't be determined
+func (b *bisyncRun) resolveNewerOlder(t1, t2 time.Time, remote1, remote2 string, prefer Prefer) int {
+	if fs.GetModifyWindow(b.octx, b.fs1, b.fs2) == fs.ModTimeNotSupported {
+		fs.Infof(remote1, "Winner cannot be determined as at least one path lacks modtime support.")
+		return 0
+	}
+	if t1.IsZero() || t2.IsZero() {
+		fs.Infof(remote1, "Winner cannot be determined as at least one modtime is missing. Path1: %v, Path2: %v", t1, t2)
+		return 0
+	}
+	if t1.After(t2) {
+		if prefer == PreferNewer {
+			fs.Infof(remote1, "Path1 is newer. Path1: %v, Path2: %v, Difference: %s", t1, t2, t1.Sub(t2))
+			return 1
+		} else if prefer == PreferOlder {
+			fs.Infof(remote1, "Path2 is older. Path1: %v, Path2: %v, Difference: %s", t1, t2, t1.Sub(t2))
+			return 2
+		}
+	} else if t1.Before(t2) {
+		if prefer == PreferNewer {
+			fs.Infof(remote1, "Path2 is newer. Path1: %v, Path2: %v, Difference: %s", t1, t2, t2.Sub(t1))
+			return 2
+		} else if prefer == PreferOlder {
+			fs.Infof(remote1, "Path1 is older. Path1: %v, Path2: %v, Difference: %s", t1, t2, t2.Sub(t1))
+			return 1
+		}
+	}
+	if t1.Equal(t2) {
+		fs.Infof(remote1, "Winner cannot be determined as times are equal. Path1: %v, Path2: %v, Difference: %s", t1, t2, t2.Sub(t1))
+		return 0
+	}
+	fs.Errorf(remote1, "Winner cannot be determined. Path1: %v, Path2: %v", t1, t2) // shouldn't happen unless prefer is of wrong type
+	return 0
+}
+
+// returns the winning path number, or 0 if winner can't be determined
+func (b *bisyncRun) resolveLargerSmaller(s1, s2 int64, remote1, remote2 string, prefer Prefer) int {
+	if s1 < 0 || s2 < 0 {
+		fs.Infof(remote1, "Winner cannot be determined as at least one size is unknown. Path1: %v, Path2: %v", s1, s2)
+		return 0
+	}
+	if s1 > s2 {
+		if prefer == PreferLarger {
+			fs.Infof(remote1, "Path1 is larger. Path1: %v, Path2: %v, Difference: %v", s1, s2, s1-s2)
+			return 1
+		} else if prefer == PreferSmaller {
+			fs.Infof(remote1, "Path2 is smaller. Path1: %v, Path2: %v, Difference: %v", s1, s2, s1-s2)
+			return 2
+		}
+	} else if s1 < s2 {
+		if prefer == PreferLarger {
+			fs.Infof(remote1, "Path2 is larger. Path1: %v, Path2: %v, Difference: %v", s1, s2, s2-s1)
+			return 2
+		} else if prefer == PreferSmaller {
+			fs.Infof(remote1, "Path1 is smaller. Path1: %v, Path2: %v, Difference: %v", s1, s2, s2-s1)
+			return 1
+		}
+	}
+	if s1 == s2 {
+		fs.Infof(remote1, "Winner cannot be determined as sizes are equal. Path1: %v, Path2: %v, Difference: %v", s1, s2, s1-s2)
+		return 0
+	}
+	fs.Errorf(remote1, "Winner cannot be determined. Path1: %v, Path2: %v", s1, s2) // shouldn't happen unless prefer is of wrong type
+	return 0
+}
diff --git a/cmd/bisync/resync.go b/cmd/bisync/resync.go
new file mode 100644
index 0000000000000..b3fc7ed8d134b
--- /dev/null
+++ b/cmd/bisync/resync.go
@@ -0,0 +1,226 @@
+package bisync
+
+import (
+	"context"
+	"os"
+	"path/filepath"
+
+	"github.com/rclone/rclone/cmd/bisync/bilib"
+	"github.com/rclone/rclone/fs"
+	"github.com/rclone/rclone/fs/filter"
+	"github.com/rclone/rclone/lib/terminal"
+)
+
+// for backward compatibility, --resync is now equivalent to --resync-mode path1
+// and either flag is sufficient without the other.
+func (b *bisyncRun) setResyncDefaults() {
+	if b.opt.Resync && b.opt.ResyncMode == PreferNone {
+		fs.Debugf(nil, Color(terminal.Dim, "defaulting to --resync-mode path1 as --resync is set"))
+		b.opt.ResyncMode = PreferPath1
+	}
+	if b.opt.ResyncMode != PreferNone {
+		b.opt.Resync = true
+		Opt.Resync = true // shouldn't be using this one, but set to be safe
+	}
+
+	// checks and warnings
+	if (b.opt.ResyncMode == PreferNewer || b.opt.ResyncMode == PreferOlder) && (b.fs1.Precision() == fs.ModTimeNotSupported || b.fs2.Precision() == fs.ModTimeNotSupported) {
+		fs.Logf(nil, Color(terminal.YellowFg, "WARNING: ignoring --resync-mode %s as at least one remote does not support modtimes."), b.opt.ResyncMode.String())
+		b.opt.ResyncMode = PreferPath1
+	} else if (b.opt.ResyncMode == PreferNewer || b.opt.ResyncMode == PreferOlder) && !b.opt.Compare.Modtime {
+		fs.Logf(nil, Color(terminal.YellowFg, "WARNING: ignoring --resync-mode %s as --compare does not include modtime."), b.opt.ResyncMode.String())
+		b.opt.ResyncMode = PreferPath1
+	}
+	if (b.opt.ResyncMode == PreferLarger || b.opt.ResyncMode == PreferSmaller) && !b.opt.Compare.Size {
+		fs.Logf(nil, Color(terminal.YellowFg, "WARNING: ignoring --resync-mode %s as --compare does not include size."), b.opt.ResyncMode.String())
+		b.opt.ResyncMode = PreferPath1
+	}
+}
+
+// resync implements the --resync mode.
+// It will generate path1 and path2 listings,
+// copy any unique files to the opposite path,
+// and resolve any differing files according to the --resync-mode.
+func (b *bisyncRun) resync(octx, fctx context.Context) error {
+	fs.Infof(nil, "Copying Path2 files to Path1")
+
+	// Save blank filelists (will be filled from sync results)
+	var ls1 = newFileList()
+	var ls2 = newFileList()
+	err = ls1.save(fctx, b.newListing1)
+	if err != nil {
+		b.handleErr(ls1, "error saving ls1 from resync", err, true, true)
+		b.abort = true
+	}
+	err = ls2.save(fctx, b.newListing2)
+	if err != nil {
+		b.handleErr(ls2, "error saving ls2 from resync", err, true, true)
+		b.abort = true
+	}
+
+	// Check access health on the Path1 and Path2 filesystems
+	// enforce even though this is --resync
+	if b.opt.CheckAccess {
+		fs.Infof(nil, "Checking access health")
+
+		filesNow1, filesNow2, err := b.findCheckFiles(fctx)
+		if err != nil {
+			b.critical = true
+			b.retryable = true
+			return err
+		}
+
+		ds1 := &deltaSet{
+			checkFiles: bilib.Names{},
+		}
+
+		ds2 := &deltaSet{
+			checkFiles: bilib.Names{},
+		}
+
+		for _, file := range filesNow1.list {
+			if filepath.Base(file) == b.opt.CheckFilename {
+				ds1.checkFiles.Add(file)
+			}
+		}
+
+		for _, file := range filesNow2.list {
+			if filepath.Base(file) == b.opt.CheckFilename {
+				ds2.checkFiles.Add(file)
+			}
+		}
+
+		err = b.checkAccess(ds1.checkFiles, ds2.checkFiles)
+		if err != nil {
+			b.critical = true
+			b.retryable = true
+			return err
+		}
+	}
+
+	var results2to1 []Results
+	var results1to2 []Results
+	queues := queues{}
+
+	b.indent("Path2", "Path1", "Resync is copying files to")
+	ctxRun := b.opt.setDryRun(fctx)
+	// fctx has our extra filters added!
+	ctxSync, filterSync := filter.AddConfig(ctxRun)
+	if filterSync.Opt.MinSize == -1 {
+		fs.Debugf(nil, "filterSync.Opt.MinSize: %v", filterSync.Opt.MinSize)
+	}
+	b.resyncIs1to2 = false
+	ctxSync = b.setResyncConfig(ctxSync)
+	ctxSync = b.setBackupDir(ctxSync, 1)
+	// 2 to 1
+	if results2to1, err = b.resyncDir(ctxSync, b.fs2, b.fs1); err != nil {
+		b.critical = true
+		return err
+	}
+
+	b.indent("Path1", "Path2", "Resync is copying files to")
+	b.resyncIs1to2 = true
+	ctxSync = b.setResyncConfig(ctxSync)
+	ctxSync = b.setBackupDir(ctxSync, 2)
+	// 1 to 2
+	if results1to2, err = b.resyncDir(ctxSync, b.fs1, b.fs2); err != nil {
+		b.critical = true
+		return err
+	}
+
+	fs.Infof(nil, "Resync updating listings")
+	b.saveOldListings() // may not exist, as this is --resync
+	b.replaceCurrentListings()
+
+	resultsToQueue := func(results []Results) bilib.Names {
+		names := bilib.Names{}
+		for _, result := range results {
+			if result.Name != "" &&
+				(result.Flags != "d" || b.opt.CreateEmptySrcDirs) &&
+				result.IsSrc && result.Src != "" &&
+				(result.Winner.Err == nil || result.Flags == "d") {
+				names.Add(result.Name)
+			}
+		}
+		return names
+	}
+
+	// resync 2to1
+	queues.copy2to1 = resultsToQueue(results2to1)
+	if err = b.modifyListing(fctx, b.fs2, b.fs1, results2to1, queues, false); err != nil {
+		b.critical = true
+		return err
+	}
+
+	// resync 1to2
+	queues.copy1to2 = resultsToQueue(results1to2)
+	if err = b.modifyListing(fctx, b.fs1, b.fs2, results1to2, queues, true); err != nil {
+		b.critical = true
+		return err
+	}
+
+	if b.opt.CheckSync == CheckSyncTrue && !b.opt.DryRun {
+		path1 := bilib.FsPath(b.fs1)
+		path2 := bilib.FsPath(b.fs2)
+		fs.Infof(nil, "Validating listings for Path1 %s vs Path2 %s", quotePath(path1), quotePath(path2))
+		if err := b.checkSync(b.listing1, b.listing2); err != nil {
+			b.critical = true
+			return err
+		}
+	}
+
+	if !b.opt.NoCleanup {
+		_ = os.Remove(b.newListing1)
+		_ = os.Remove(b.newListing2)
+	}
+	return nil
+}
+
+/*
+	 --resync-mode implementation:
+		PreferPath1: set ci.IgnoreExisting true, then false
+		PreferPath2: set ci.IgnoreExisting false, then true
+		PreferNewer: set ci.UpdateOlder in both directions
+		PreferOlder: override EqualFn to implement custom logic
+		PreferLarger: override EqualFn to implement custom logic
+		PreferSmaller: override EqualFn to implement custom logic
+*/
+func (b *bisyncRun) setResyncConfig(ctx context.Context) context.Context {
+	ci := fs.GetConfig(ctx)
+	switch b.opt.ResyncMode {
+	case PreferPath1:
+		if !b.resyncIs1to2 { // 2to1 (remember 2to1 is first)
+			ci.IgnoreExisting = true
+		} else { // 1to2
+			ci.IgnoreExisting = false
+		}
+	case PreferPath2:
+		if !b.resyncIs1to2 { // 2to1 (remember 2to1 is first)
+			ci.IgnoreExisting = false
+		} else { // 1to2
+			ci.IgnoreExisting = true
+		}
+	case PreferNewer:
+		ci.UpdateOlder = true
+	}
+	// for older, larger, and smaller, we return it unchanged and handle it later
+	return ctx
+}
+
+func (b *bisyncRun) resyncWhichIsWhich(src, dst fs.ObjectInfo) (path1, path2 fs.ObjectInfo) {
+	if b.resyncIs1to2 {
+		return src, dst
+	}
+	return dst, src
+}
+
+// equal in this context really means "don't transfer", so we should
+// return true if the files are actually equal or if dest is winner,
+// false if src is winner
+// When can't determine, we end up running the normal Equal() to tie-break (due to our differ functions).
+func (b *bisyncRun) resyncWinningPathToEqual(winningPath int) bool {
+	if b.resyncIs1to2 {
+		return winningPath != 1
+	}
+	return winningPath != 2
+}
diff --git a/docs/content/bisync.md b/docs/content/bisync.md
index 84b4a8735524c..461ac604fc77e 100644
--- a/docs/content/bisync.md
+++ b/docs/content/bisync.md
@@ -159,10 +159,10 @@ as the last step in the process.
 ### --resync
 
 This will effectively make both Path1 and Path2 filesystems contain a
-matching superset of all files. Path2 files that do not exist in Path1 will
+matching superset of all files. By default, Path2 files that do not exist in Path1 will
 be copied to Path1, and the process will then copy the Path1 tree to Path2.
 
-The `--resync` sequence is roughly equivalent to:
+The `--resync` sequence is roughly equivalent to the following (but see [`--resync-mode`](#resync-mode) for other options):
 ```
 rclone copy Path2 Path1 --ignore-existing [--create-empty-src-dirs]
 rclone copy Path1 Path2 [--create-empty-src-dirs]
@@ -173,8 +173,8 @@ or bisync will fail. This is required for safety - that bisync can verify
 that both paths are valid.
 
 When using `--resync`, a newer version of a file on the Path2 filesystem
-will be overwritten by the Path1 filesystem version. 
-(Note that this is [NOT entirely symmetrical](https://github.com/rclone/rclone/issues/5681#issuecomment-938761815).)
+will (by default) be overwritten by the Path1 filesystem version.
+(Note that this is [NOT entirely symmetrical](https://github.com/rclone/rclone/issues/5681#issuecomment-938761815), and more symmetrical options can be specified with the [`--resync-mode`](#resync-mode) flag.)
 Carefully evaluate deltas using [--dry-run](/flags/#non-backend-flags).
 
 For a resync run, one of the paths may be empty (no files in the path tree).
@@ -186,7 +186,12 @@ For a non-resync run, either path being empty (no files in the tree) fails with
 This is a safety check that an unexpected empty path does not result in
 deleting **everything** in the other path.
 
-**Note:** `--resync` should only be used under three specific (rare) circumstances:
+Note that `--resync` implies `--resync-mode path1` unless a different
+[`--resync-mode`](#resync-mode)  is explicitly specified.
+It is not necessary to use both the `--resync` and `--resync-mode` flags --
+either one is sufficient without the other.
+
+**Note:** `--resync` (including `--resync-mode`) should only be used under three specific (rare) circumstances:
 1. It is your _first_ bisync run (between these two paths)
 2. You've just made changes to your bisync settings (such as editing the contents of your `--filters-file`)
 3. There was an error on the prior run, and as a result, bisync now requires `--resync` to recover
@@ -196,6 +201,84 @@ Therefore, if you included `--resync` for every bisync run, it would never be po
 the deleted file would always keep reappearing at the end of every run (because it's being copied from the other side where it still exists).
 Similarly, renaming a file would always result in a duplicate copy (both old and new name) on both sides.
 
+If you find that frequent interruptions from #3 are an issue, rather than
+automatically running `--resync`, the recommended alternative is to use the
+[`--resilient`](#resilient), [`--recover`](#recover), and
+[`--conflict-resolve`](#conflict-resolve) flags, (along with [Graceful
+Shutdown](#graceful-shutdown) mode, when needed) for a very robust
+"set-it-and-forget-it" bisync setup that can automatically bounce back from
+almost any interruption it might encounter. Consider adding something like the
+following:
+
+```
+--resilient --recover --max-lock 2m --conflict-resolve newer
+```
+
+### --resync-mode CHOICE {#resync-mode}
+
+In the event that a file differs on both sides during a `--resync`,
+`--resync-mode` controls which version will overwrite the other. The supported
+options are similar to [`--conflict-resolve`](#conflict-resolve). For all of
+the following options, the version that is kept is referred to as the "winner",
+and the version that is overwritten (deleted) is referred to as the "loser".
+The options are named after the "winner":
+
+- `path1` - (the default) - the version from Path1 is unconditionally
+considered the winner (regardless of `modtime` and `size`, if any). This can be
+useful if one side is more trusted or up-to-date than the other, at the time of
+the `--resync`.
+- `path2` - same as `path1`, except the path2 version is considered the winner.
+- `newer` - the newer file (by `modtime`) is considered the winner, regardless
+of which side it came from. This may result in having a mix of some winners
+from Path1, and some winners from Path2. (The implementation is analagous to
+running `rclone copy --update` in both directions.)
+- `older` - same as `newer`, except the older file is considered the winner,
+and the newer file is considered the loser.
+- `larger` - the larger file (by `size`) is considered the winner (regardless
+of `modtime`, if any). This can be a useful option for remotes without
+`modtime` support, or with the kinds of files (such as logs) that tend to grow
+but not shrink, over time.
+- `smaller` - the smaller file (by `size`) is considered the winner (regardless
+of `modtime`, if any).
+
+For all of the above options, note the following:
+- If either of the underlying remotes lacks support for the chosen method, it
+will be ignored and will fall back to the default of `path1`. (For example, if
+`--resync-mode newer` is set, but one of the paths uses a remote that doesn't
+support `modtime`.)
+- If a winner can't be determined because the chosen method's attribute is
+missing or equal, it will be ignored, and bisync will instead try to determine
+whether the files differ by looking at the other `--compare` methods in effect.
+(For example, if `--resync-mode newer` is set, but the Path1 and Path2 modtimes
+are identical, bisync will compare the sizes.) If bisync concludes that they
+differ, preference is given to whichever is the "source" at that moment. (In
+practice, this gives a slight advantage to Path2, as the 2to1 copy comes before
+the 1to2 copy.) If the files _do not_ differ, nothing is copied (as both sides
+are already correct).
+- These options apply only to files that exist on both sides (with the same
+name and relative path). Files that exist *only* on one side and not the other
+are *always* copied to the other, during `--resync` (this is one of the main
+differences between resync and non-resync runs.).
+- `--conflict-resolve`, `--conflict-loser`, and `--conflict-suffix` do not
+apply during `--resync`, and unlike these flags, nothing is renamed during
+`--resync`. When a file differs on both sides during `--resync`, one version
+always overwrites the other (much like in `rclone copy`.) (Consider using
+[`--backup-dir`](#backup-dir1-and-backup-dir2) to retain a backup of the losing
+version.)
+- Unlike for `--conflict-resolve`, `--resync-mode none` is not a valid option
+(or rather, it will be interpreted as "no resync", unless `--resync` has also
+been specified, in which case it will be ignored.)
+- Winners and losers are decided at the individual file-level only (there is
+not currently an option to pick an entire winning directory atomically,
+although the `path1` and `path2` options typically produce a similar result.)
+- To maintain backward-compatibility, the `--resync` flag implies
+`--resync-mode path1` unless a different `--resync-mode` is explicitly
+specified. Similarly, all `--resync-mode` options (except `none`) imply
+`--resync`, so it is not necessary to use both the `--resync` and
+`--resync-mode` flags simultaneously -- either one is sufficient without the
+other.
+
+
 ### --check-access
 
 Access check files are an additional safety measure against data loss.
@@ -422,6 +505,152 @@ of the current filters file and compares it to the hash stored in the `.md5` fil
 If they don't match, the run aborts with a critical error and thus forces you
 to do a `--resync`, likely avoiding a disaster.
 
+### --conflict-resolve CHOICE {#conflict-resolve}
+
+In bisync, a "conflict" is a file that is *new* or *changed* on *both sides*
+(relative to the prior run) AND is *not currently identical* on both sides.
+`--conflict-resolve` controls how bisync handles such a scenario. The currently
+supported options are:
+
+- `none` - (the default) - do not attempt to pick a winner, keep and rename
+both files according to [`--conflict-loser`](#conflict-loser) and
+[`--conflict-suffix`](#conflict-suffix) settings. For example, with the default
+settings, `file.txt` on Path1 is renamed `file.txt.conflict1` and `file.txt` on
+Path2 is renamed `file.txt.conflict2`. Both are copied to the opposite path
+during the run, so both sides end up with a copy of both files. (As `none` is
+the default, it is not necessary to specify `--conflict-resolve none` -- you
+can just omit the flag.)
+- `newer` - the newer file (by `modtime`) is considered the winner and is
+copied without renaming. The older file (the "loser") is handled according to
+`--conflict-loser` and `--conflict-suffix` settings (either renamed or
+deleted.) For example, if `file.txt` on Path1 is newer than `file.txt` on
+Path2, the result on both sides (with other default settings) will be `file.txt`
+(winner from Path1) and `file.txt.conflict1` (loser from Path2).
+- `older` - same as `newer`, except the older file is considered the winner,
+and the newer file is considered the loser.
+- `larger` - the larger file (by `size`) is considered the winner (regardless
+of `modtime`, if any).
+- `smaller` - the smaller file (by `size`) is considered the winner (regardless
+of `modtime`, if any).
+- `path1` - the version from Path1 is unconditionally considered the winner
+(regardless of `modtime` and `size`, if any). This can be useful if one side is
+usually more trusted or up-to-date than the other.
+- `path2` - same as `path1`, except the path2 version is considered the
+winner.
+
+For all of the above options, note the following:
+- If either of the underlying remotes lacks support for the chosen method, it
+will be ignored and fall back to `none`. (For example, if `--conflict-resolve
+newer` is set, but one of the paths uses a remote that doesn't support
+`modtime`.)
+- If a winner can't be determined because the chosen method's attribute is
+missing or equal, it will be ignored and fall back to `none`. (For example, if
+`--conflict-resolve newer` is set, but the Path1 and Path2 modtimes are
+identical, even if the sizes may differ.)
+- If the file's content is currently identical on both sides, it is not
+considered a "conflict", even if new or changed on both sides since the prior
+sync. (For example, if you made a change on one side and then synced it to the
+other side by other means.) Therefore, none of the conflict resolution flags
+apply in this scenario.
+- The conflict resolution flags do not apply during a `--resync`, as there is
+no "prior run" to speak of (but see [`--resync-mode`](#resync-mode) for similar
+options.)
+
+### --conflict-loser CHOICE {#conflict-loser}
+
+`--conflict-loser` determines what happens to the "loser" of a sync conflict
+(when [`--conflict-resolve`](#conflict-resolve) determines a winner) or to both
+files (when there is no winner.) The currently supported options are:
+
+- `num` - (the default) - auto-number the conflicts by automatically appending
+the next available number to the `--conflict-suffix`, in chronological order.
+For example, with the default settings, the first conflict for `file.txt` will
+be renamed `file.txt.conflict1`. If `file.txt.conflict1` already exists,
+`file.txt.conflict2` will be used instead (etc., up to a maximum of
+9223372036854775807 conflicts.)
+- `pathname` - rename the conflicts according to which side they came from,
+which was the default behavior prior to `v1.66`. For example, with
+`--conflict-suffix path`, `file.txt` from Path1 will be renamed
+`file.txt.path1`, and `file.txt` from Path2 will be renamed `file.txt.path2`.
+If two non-identical suffixes are provided (ex. `--conflict-suffix
+cloud,local`), the trailing digit is omitted. Importantly, note that with
+`pathname`, there is no auto-numbering beyond `2`, so if `file.txt.path2`
+somehow already exists, it will be overwritten. Using a dynamic date variable
+in your `--conflict-suffix` (see below) is one possible way to avoid this. Note
+also that conflicts-of-conflicts are possible, if the original conflict is not
+manually resolved -- for example, if for some reason you edited
+`file.txt.path1` on both sides, and those edits were different, the result
+would be `file.txt.path1.path1` and `file.txt.path1.path2` (in addition to
+`file.txt.path2`.)
+- `delete` - keep the winner only and delete the loser, instead of renaming it.
+If a winner cannot be determined (see `--conflict-resolve` for details on how
+this could happen), `delete` is ignored and the default `num` is used instead
+(i.e. both versions are kept and renamed, and neither is deleted.) `delete` is
+inherently the most destructive option, so use it only with care.
+
+For all of the above options, note that if a winner cannot be determined (see
+`--conflict-resolve` for details on how this could happen), or if
+`--conflict-resolve` is not in use, *both* files will be renamed.
+
+### --conflict-suffix STRING[,STRING] {#conflict-suffix}
+
+`--conflict-suffix` controls the suffix that is appended when bisync renames a
+[`--conflict-loser`](#conflict-loser) (default: `conflict`).
+`--conflict-suffix` will accept either one string or two comma-separated
+strings to assign different suffixes to Path1 vs. Path2. This may be helpful
+later in identifying the source of the conflict. (For example,
+`--conflict-suffix dropboxconflict,laptopconflict`)
+
+With `--conflict-loser num`, a number is always appended to the suffix. With
+`--conflict-loser pathname`, a number is appended only when one suffix is
+specified (or when two identical suffixes are specified.) i.e. with
+`--conflict-loser pathname`, all of the following would produce exactly the
+same result:
+
+```
+--conflict-suffix path
+--conflict-suffix path,path
+--conflict-suffix path1,path2
+```
+
+Suffixes may be as short as 1 character. By default, the suffix is appended
+after any other extensions (ex. `file.jpg.conflict1`), however, this can be
+changed with the [`--suffix-keep-extension`](/docs/#suffix-keep-extension) flag
+(i.e. to instead result in `file.conflict1.jpg`).
+
+`--conflict-suffix` supports several *dynamic date variables* when enclosed in
+curly braces as globs. This can be helpful to track the date and/or time that
+each conflict was handled by bisync. For example:
+
+```
+--conflict-suffix {DateOnly}-conflict
+// result: myfile.txt.2006-01-02-conflict1
+```
+
+All of the formats described [here](https://pkg.go.dev/time#pkg-constants) and
+[here](https://pkg.go.dev/time#example-Time.Format) are supported, but take
+care to ensure that your chosen format does not use any characters that are
+illegal on your remotes (for example, macOS does not allow colons in
+filenames, and slashes are also best avoided as they are often interpreted as
+directory separators.) To address this particular issue, an additional
+`{MacFriendlyTime}` (or just `{mac}`) option is supported, which results in
+`2006-01-02 0304PM`.
+
+Note that `--conflict-suffix` is entirely separate from rclone's main
+[`--sufix`](/docs/#suffix-suffix) flag. This is intentional, as users may wish
+to use both flags simultaneously, if also using
+[`--backup-dir`](#backup-dir1-and-backup-dir2).
+
+Finally, note that the default in bisync prior to `v1.66` was to rename
+conflicts with `..path1` and `..path2` (with two periods, and `path` instead of
+`conflict`.) Bisync now defaults to a single dot instead of a double dot, but
+additional dots can be added by including them in the specified suffix string.
+For example, for behavior equivalent to the previous default, use:
+
+```
+[--conflict-resolve none] --conflict-loser pathname --conflict-suffix .path
+```
+
 ### --check-sync
 
 Enabled by default, the check-sync function checks that all of the same
@@ -610,7 +839,7 @@ the other side by moving the corresponding file from `gdrive:Bisync` to
 moves it from `/Users/someuser/some/local/path/Bisync` to
 `/Users/someuser/some/local/path/BackupDir`.
 
-In the event of a `..path1` / `..path2` rename due to a sync conflict, the
+In the event of a [rename due to a sync conflict](#conflict-loser), the
 rename is not considered a delete, unless a previous conflict with the same
 name already exists and would get overwritten.
 
@@ -634,7 +863,8 @@ On each successive run it will:
 - Lock file prevents multiple simultaneous runs when taking a while.
   This can be particularly useful if bisync is run by cron scheduler.
 - Handle change conflicts non-destructively by creating
-  `..path1` and `..path2` file versions.
+  `.conflict1`, `.conflict2`, etc. file versions, according to
+  [`--conflict-resolve`](#conflict-resolve), [`--conflict-loser`](#conflict-loser), and [`--conflict-suffix`](#conflict-suffix) settings.
 - File system access health check using `RCLONE_TEST` files
   (see the `--check-access` flag).
 - Abort on excessive deletes - protects against a failed listing
@@ -661,8 +891,8 @@ Path1 deleted | File no longer exists on Path1                | File is deleted
  Type                           | Description                           | Result                             | Implementation
 --------------------------------|---------------------------------------|------------------------------------|-----------------------
 Path1 new/changed AND Path2 new/changed AND Path1 == Path2       | File is new/changed on Path1 AND new/changed on Path2 AND Path1 version is currently identical to Path2 | No change | None
-Path1 new AND Path2 new         | File is new on Path1 AND new on Path2 (and Path1 version is NOT identical to Path2) | Files renamed to _Path1 and _Path2 | `rclone copy` _Path2 file to Path1, `rclone copy` _Path1 file to Path2
-Path2 newer AND Path1 changed   | File is newer on Path2 AND also changed (newer/older/size) on Path1 (and Path1 version is NOT identical to Path2) | Files renamed to _Path1 and _Path2 | `rclone copy` _Path2 file to Path1, `rclone copy` _Path1 file to Path2
+Path1 new AND Path2 new         | File is new on Path1 AND new on Path2 (and Path1 version is NOT identical to Path2) | Conflicts handled according to [`--conflict-resolve`](#conflict-resolve) & [`--conflict-loser`](#conflict-loser) settings | default: `rclone copy` renamed `Path2.conflict2` file to Path1, `rclone copy` renamed `Path1.conflict1` file to Path2
+Path2 newer AND Path1 changed   | File is newer on Path2 AND also changed (newer/older/size) on Path1 (and Path1 version is NOT identical to Path2) | Conflicts handled according to [`--conflict-resolve`](#conflict-resolve) & [`--conflict-loser`](#conflict-loser) settings | default: `rclone copy` renamed `Path2.conflict2` file to Path1, `rclone copy` renamed `Path1.conflict1` file to Path2
 Path2 newer AND Path1 deleted   | File is newer on Path2 AND also deleted on Path1 | Path2 version survives  | `rclone copy` Path2 to Path1
 Path2 deleted AND Path1 changed | File is deleted on Path2 AND changed (newer/older/size) on Path1 | Path1 version survives |`rclone copy` Path1 to Path2
 Path1 deleted AND Path2 changed | File is deleted on Path1 AND changed (newer/older/size) on Path2 | Path2 version survives  | `rclone copy` Path2 to Path1
@@ -673,7 +903,7 @@ Now, when bisync comes to a file that it wants to rename (because it is new/chan
 it first checks whether the Path1 and Path2 versions are currently *identical* 
 (using the same underlying function as [`check`](commands/rclone_check/).) 
 If bisync concludes that the files are identical, it will skip them and move on. 
-Otherwise, it will create renamed `..Path1` and `..Path2` duplicates, as before. 
+Otherwise, it will create renamed duplicates, as before.
 This behavior also [improves the experience of renaming directories](https://forum.rclone.org/t/bisync-bugs-and-feature-requests/37636#:~:text=Renamed%20directories), 
 as a `--resync` is no longer required, so long as the same change has been made on both sides.
 
@@ -1604,6 +1834,8 @@ instead of of `--size-only`, when `check` is not available.
 * Bisync now supports a "Graceful Shutdown" mode to cleanly cancel a run early without requiring `--resync`.
 * New `--recover` flag allows robust recovery in the event of interruptions, without requiring `--resync`.
 * A new `--max-lock` setting allows lock files to automatically renew and expire, for better automatic recovery when a run is interrupted.
+* Bisync now supports auto-resolving sync conflicts and customizing rename behavior with new [`--conflict-resolve`](#conflict-resolve), [`--conflict-loser`](#conflict-loser), and [`--conflict-suffix`](#conflict-suffix) flags.
+* A new [`--resync-mode`](#resync-mode) flag allows more control over which version of a file gets kept during a `--resync`.
 
 ### `v1.64`
 * Fixed an [issue](https://forum.rclone.org/t/bisync-bugs-and-feature-requests/37636#:~:text=1.%20Dry%20runs%20are%20not%20completely%20dry) 


Test patch:
diff --git a/cmd/bisync/bisync_test.go b/cmd/bisync/bisync_test.go
index 68df9683896d3..288371b7f4790 100644
--- a/cmd/bisync/bisync_test.go
+++ b/cmd/bisync/bisync_test.go
@@ -118,6 +118,9 @@ var logHoppers = []string{
 
 	// Test case `normalization` can have random order of fix-case files.
 	`(?:INFO  |NOTICE): .*: Fixed case by renaming to: .*`,
+
+	// order of files re-checked prior to a conflict rename
+	`ERROR : .*: md5 differ.*`,
 }
 
 // Some log lines can contain Windows path separator that must be
@@ -186,8 +189,6 @@ type bisyncTest struct {
 	TestFn     bisync.TestFunc
 }
 
-const TerminalColorMode = fs.TerminalColorModeAlways
-
 var color = bisync.Color
 
 // TestBisync is a test engine for bisync test cases.
@@ -203,6 +204,8 @@ func TestBisync(t *testing.T) {
 	if *argRefreshTimes {
 		ci.RefreshTimes = true
 	}
+	bisync.Colors = true
+	time.Local, _ = time.LoadLocation("America/New_York")
 
 	baseDir, err := os.Getwd()
 	require.NoError(t, err, "get current directory")
@@ -257,6 +260,10 @@ func TestBisync(t *testing.T) {
 		testList = nil
 		for _, testCase := range b.listDir(b.dataRoot) {
 			if strings.HasPrefix(testCase, "test_") {
+				// if dir is empty, skip it (can happen due to gitignored files/dirs when checking out branch)
+				if len(b.listDir(filepath.Join(b.dataRoot, testCase))) == 0 {
+					continue
+				}
 				testList = append(testList, testCase)
 			}
 		}
@@ -853,6 +860,14 @@ func (b *bisyncTest) runBisync(ctx context.Context, args []string) (err error) {
 			ci.NoUnicodeNormalization = false
 			ci.IgnoreCaseSync = true
 			ci.FixCase = true
+		case "conflict-resolve":
+			_ = opt.ConflictResolve.Set(val)
+		case "conflict-loser":
+			_ = opt.ConflictLoser.Set(val)
+		case "conflict-suffix":
+			opt.ConflictSuffixFlag = val
+		case "resync-mode":
+			_ = opt.ResyncMode.Set(val)
 		default:
 			return fmt.Errorf("invalid bisync option %q", arg)
 		}
diff --git a/cmd/bisync/testdata/test_all_changed/golden/test.log b/cmd/bisync/testdata/test_all_changed/golden/test.log
index f340d12c25d11..cb74904c907b5 100644
--- a/cmd/bisync/testdata/test_all_changed/golden/test.log
+++ b/cmd/bisync/testdata/test_all_changed/golden/test.log
@@ -14,10 +14,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 
 [36m(04)  :[0m [34mtest change timestamp on all files except RCLONE_TEST[0m
diff --git a/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.copy1to2.que b/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.copy1to2.que
index 5725b81842f15..74c4ff68a0f0f 100644
--- a/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.copy1to2.que
+++ b/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.copy1to2.que
@@ -1,5 +1,5 @@
 "file11.txt"
 "file2.txt"
 "file4.txt"
-"file5.txt..path1"
+"file5.txt.conflict1"
 "file7.txt"
diff --git a/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.copy2to1.que b/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.copy2to1.que
index 3b79e78bd1166..8097bfd9d80ca 100644
--- a/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.copy2to1.que
+++ b/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.copy2to1.que
@@ -1,5 +1,5 @@
 "file1.txt"
 "file10.txt"
 "file3.txt"
-"file5.txt..path2"
+"file5.txt.conflict2"
 "file6.txt"
diff --git a/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path1.lst-err b/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path1.lst-err
index 19e9623a54214..28bcb7af77d12 100644
--- a/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path1.lst-err
+++ b/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path1.lst-err
@@ -4,7 +4,7 @@
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file10.txt"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file11.txt"
 -       13 - - 2001-01-02T00:00:00.000000000+0000 "file2.txt"
--       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1"
--       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2"
+-       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1"
+-       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file6.txt"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file7.txt"
diff --git a/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path1.lst-new b/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path1.lst-new
index 19e9623a54214..28bcb7af77d12 100644
--- a/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path1.lst-new
+++ b/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path1.lst-new
@@ -4,7 +4,7 @@
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file10.txt"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file11.txt"
 -       13 - - 2001-01-02T00:00:00.000000000+0000 "file2.txt"
--       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1"
--       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2"
+-       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1"
+-       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file6.txt"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file7.txt"
diff --git a/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path1.lst-old b/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path1.lst-old
index 19e9623a54214..28bcb7af77d12 100644
--- a/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path1.lst-old
+++ b/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path1.lst-old
@@ -4,7 +4,7 @@
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file10.txt"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file11.txt"
 -       13 - - 2001-01-02T00:00:00.000000000+0000 "file2.txt"
--       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1"
--       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2"
+-       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1"
+-       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file6.txt"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file7.txt"
diff --git a/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path2.lst-err b/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path2.lst-err
index 19e9623a54214..28bcb7af77d12 100644
--- a/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path2.lst-err
+++ b/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path2.lst-err
@@ -4,7 +4,7 @@
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file10.txt"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file11.txt"
 -       13 - - 2001-01-02T00:00:00.000000000+0000 "file2.txt"
--       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1"
--       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2"
+-       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1"
+-       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file6.txt"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file7.txt"
diff --git a/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path2.lst-new b/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path2.lst-new
index 19e9623a54214..28bcb7af77d12 100644
--- a/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path2.lst-new
+++ b/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path2.lst-new
@@ -4,7 +4,7 @@
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file10.txt"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file11.txt"
 -       13 - - 2001-01-02T00:00:00.000000000+0000 "file2.txt"
--       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1"
--       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2"
+-       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1"
+-       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file6.txt"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file7.txt"
diff --git a/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path2.lst-old b/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path2.lst-old
index 19e9623a54214..28bcb7af77d12 100644
--- a/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path2.lst-old
+++ b/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path2.lst-old
@@ -4,7 +4,7 @@
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file10.txt"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file11.txt"
 -       13 - - 2001-01-02T00:00:00.000000000+0000 "file2.txt"
--       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1"
--       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2"
+-       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1"
+-       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file6.txt"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file7.txt"
diff --git a/cmd/bisync/testdata/test_backupdir/golden/test.log b/cmd/bisync/testdata/test_backupdir/golden/test.log
index ab8170d50ec27..cfd85b692b736 100644
--- a/cmd/bisync/testdata/test_backupdir/golden/test.log
+++ b/cmd/bisync/testdata/test_backupdir/golden/test.log
@@ -14,10 +14,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 
 [36m(04)  :[0m [34mtest make modifications on both paths[0m
@@ -101,10 +102,10 @@ INFO  : - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{
 INFO  : - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file2.txt[0m
 INFO  : - [34mPath2[0m    [35m[31mQueue delete[0m[0m              - [36m{path2/}file4.txt[0m
 NOTICE: - [34mWARNING[0m  [35mNew or changed in both paths[0m       - [36mfile5.txt[0m
-NOTICE: - [36mPath1[0m    [35mRenaming Path1 copy[0m                - [36m{path1/}file5.txt..path1[0m
-NOTICE: - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file5.txt..path1[0m
-NOTICE: - [34mPath2[0m    [35mRenaming Path2 copy[0m                - [36m{path2/}file5.txt..path2[0m
-NOTICE: - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}file5.txt..path2[0m
+NOTICE: - [36mPath1[0m    [35mRenaming Path1 copy[0m                - [36m{path1/}file5.txt.conflict1[0m
+NOTICE: - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file5.txt.conflict1[0m
+NOTICE: - [34mPath2[0m    [35mRenaming Path2 copy[0m                - [36m{path2/}file5.txt.conflict2[0m
+NOTICE: - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}file5.txt.conflict2[0m
 INFO  : - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}file6.txt[0m
 INFO  : - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file7.txt[0m
 INFO  : - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}file1.txt[0m
diff --git a/cmd/bisync/testdata/test_basic/golden/test.log b/cmd/bisync/testdata/test_basic/golden/test.log
index d5f63b679ad4c..d3086e7904ec2 100644
--- a/cmd/bisync/testdata/test_basic/golden/test.log
+++ b/cmd/bisync/testdata/test_basic/golden/test.log
@@ -14,10 +14,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 
 [36m(04)  :[0m [34mtest place newer files on both paths[0m
diff --git a/cmd/bisync/testdata/test_changes/golden/_testdir_path1.._testdir_path2.copy1to2.que b/cmd/bisync/testdata/test_changes/golden/_testdir_path1.._testdir_path2.copy1to2.que
index 5725b81842f15..74c4ff68a0f0f 100644
--- a/cmd/bisync/testdata/test_changes/golden/_testdir_path1.._testdir_path2.copy1to2.que
+++ b/cmd/bisync/testdata/test_changes/golden/_testdir_path1.._testdir_path2.copy1to2.que
@@ -1,5 +1,5 @@
 "file11.txt"
 "file2.txt"
 "file4.txt"
-"file5.txt..path1"
+"file5.txt.conflict1"
 "file7.txt"
diff --git a/cmd/bisync/testdata/test_changes/golden/_testdir_path1.._testdir_path2.copy2to1.que b/cmd/bisync/testdata/test_changes/golden/_testdir_path1.._testdir_path2.copy2to1.que
index 3b79e78bd1166..8097bfd9d80ca 100644
--- a/cmd/bisync/testdata/test_changes/golden/_testdir_path1.._testdir_path2.copy2to1.que
+++ b/cmd/bisync/testdata/test_changes/golden/_testdir_path1.._testdir_path2.copy2to1.que
@@ -1,5 +1,5 @@
 "file1.txt"
 "file10.txt"
 "file3.txt"
-"file5.txt..path2"
+"file5.txt.conflict2"
 "file6.txt"
diff --git a/cmd/bisync/testdata/test_changes/golden/_testdir_path1.._testdir_path2.path1.lst b/cmd/bisync/testdata/test_changes/golden/_testdir_path1.._testdir_path2.path1.lst
index 19e9623a54214..28bcb7af77d12 100644
--- a/cmd/bisync/testdata/test_changes/golden/_testdir_path1.._testdir_path2.path1.lst
+++ b/cmd/bisync/testdata/test_changes/golden/_testdir_path1.._testdir_path2.path1.lst
@@ -4,7 +4,7 @@
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file10.txt"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file11.txt"
 -       13 - - 2001-01-02T00:00:00.000000000+0000 "file2.txt"
--       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1"
--       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2"
+-       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1"
+-       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file6.txt"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file7.txt"
diff --git a/cmd/bisync/testdata/test_changes/golden/_testdir_path1.._testdir_path2.path2.lst b/cmd/bisync/testdata/test_changes/golden/_testdir_path1.._testdir_path2.path2.lst
index 19e9623a54214..28bcb7af77d12 100644
--- a/cmd/bisync/testdata/test_changes/golden/_testdir_path1.._testdir_path2.path2.lst
+++ b/cmd/bisync/testdata/test_changes/golden/_testdir_path1.._testdir_path2.path2.lst
@@ -4,7 +4,7 @@
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file10.txt"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file11.txt"
 -       13 - - 2001-01-02T00:00:00.000000000+0000 "file2.txt"
--       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1"
--       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2"
+-       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1"
+-       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file6.txt"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file7.txt"
diff --git a/cmd/bisync/testdata/test_changes/golden/test.log b/cmd/bisync/testdata/test_changes/golden/test.log
index 3d678b67a6de4..36aa3257c7aa2 100644
--- a/cmd/bisync/testdata/test_changes/golden/test.log
+++ b/cmd/bisync/testdata/test_changes/golden/test.log
@@ -14,10 +14,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 
 [36m(04)  :[0m [34mtest make modifications on both paths[0m
@@ -101,10 +102,10 @@ INFO  : - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{
 INFO  : - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file2.txt[0m
 INFO  : - [34mPath2[0m    [35m[31mQueue delete[0m[0m              - [36m{path2/}file4.txt[0m
 NOTICE: - [34mWARNING[0m  [35mNew or changed in both paths[0m       - [36mfile5.txt[0m
-NOTICE: - [36mPath1[0m    [35mRenaming Path1 copy[0m                - [36m{path1/}file5.txt..path1[0m
-NOTICE: - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file5.txt..path1[0m
-NOTICE: - [34mPath2[0m    [35mRenaming Path2 copy[0m                - [36m{path2/}file5.txt..path2[0m
-NOTICE: - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}file5.txt..path2[0m
+NOTICE: - [36mPath1[0m    [35mRenaming Path1 copy[0m                - [36m{path1/}file5.txt.conflict1[0m
+NOTICE: - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file5.txt.conflict1[0m
+NOTICE: - [34mPath2[0m    [35mRenaming Path2 copy[0m                - [36m{path2/}file5.txt.conflict2[0m
+NOTICE: - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}file5.txt.conflict2[0m
 INFO  : - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}file6.txt[0m
 INFO  : - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file7.txt[0m
 INFO  : - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}file1.txt[0m
diff --git a/cmd/bisync/testdata/test_check_access/golden/test.log b/cmd/bisync/testdata/test_check_access/golden/test.log
index 7b6e19e88a4ed..4184a0f305159 100644
--- a/cmd/bisync/testdata/test_check_access/golden/test.log
+++ b/cmd/bisync/testdata/test_check_access/golden/test.log
@@ -14,10 +14,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 
 [36m(04)  :[0m [34mtest 1. see that check-access passes with the initial setup[0m
@@ -84,10 +85,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 
 [36m(13)  :[0m [34mtest 4. run sync with check-access. should pass.[0m
@@ -176,10 +178,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 
 [36m(24)  :[0m [34mtest 8. run sync with --check-access. should pass.[0m
diff --git a/cmd/bisync/testdata/test_check_access_filters/golden/test.log b/cmd/bisync/testdata/test_check_access_filters/golden/test.log
index b9724a84feaa4..eeb34743857a4 100644
--- a/cmd/bisync/testdata/test_check_access_filters/golden/test.log
+++ b/cmd/bisync/testdata/test_check_access_filters/golden/test.log
@@ -19,10 +19,11 @@ INFO  : Bisyncing with Comparison Settings:
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
 INFO  : Using filters file {workdir/}exclude-other-filtersfile.txt
 INFO  : Storing filters file hash to {workdir/}exclude-other-filtersfile.txt.md5
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 
 [36m(06)  :[0m [34mtest EXCLUDE - test filters for check access[0m
@@ -133,10 +134,11 @@ INFO  : Bisyncing with Comparison Settings:
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
 INFO  : Using filters file {workdir/}include-other-filtersfile.txt
 INFO  : Storing filters file hash to {workdir/}include-other-filtersfile.txt.md5
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 
 [36m(29)  :[0m [34mtest INCLUDE - test include/exclude filters for check access[0m
diff --git a/cmd/bisync/testdata/test_check_filename/golden/test.log b/cmd/bisync/testdata/test_check_filename/golden/test.log
index 59728701eac36..573976edeff68 100644
--- a/cmd/bisync/testdata/test_check_filename/golden/test.log
+++ b/cmd/bisync/testdata/test_check_filename/golden/test.log
@@ -14,10 +14,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 
 [36m(04)  :[0m [34mtest 1. see that check-access passes with the initial setup[0m
@@ -85,12 +86,13 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
+INFO  : Copying Path2 files to Path1
 INFO  : Checking access health
 INFO  : Found 2 matching ".chk_file" files on both paths
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 
 [36m(14)  :[0m [34mtest 4. run sync with check-access. should pass.[0m
diff --git a/cmd/bisync/testdata/test_check_sync/golden/test.log b/cmd/bisync/testdata/test_check_sync/golden/test.log
index 35246882d60ee..46a5f0ffcc9f0 100644
--- a/cmd/bisync/testdata/test_check_sync/golden/test.log
+++ b/cmd/bisync/testdata/test_check_sync/golden/test.log
@@ -14,10 +14,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 
 [36m(04)  :[0m [34mtest 1. run check-sync-only on a clean sync[0m
@@ -99,10 +100,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 
 [36m(20)  :[0m [34mtest 7. run normal sync with check-sync enabled (default)[0m
diff --git a/cmd/bisync/testdata/test_compare_all/golden/_testdir_path1.._testdir_path2.copy1to2.que b/cmd/bisync/testdata/test_compare_all/golden/_testdir_path1.._testdir_path2.copy1to2.que
index 5725b81842f15..74c4ff68a0f0f 100644
--- a/cmd/bisync/testdata/test_compare_all/golden/_testdir_path1.._testdir_path2.copy1to2.que
+++ b/cmd/bisync/testdata/test_compare_all/golden/_testdir_path1.._testdir_path2.copy1to2.que
@@ -1,5 +1,5 @@
 "file11.txt"
 "file2.txt"
 "file4.txt"
-"file5.txt..path1"
+"file5.txt.conflict1"
 "file7.txt"
diff --git a/cmd/bisync/testdata/test_compare_all/golden/_testdir_path1.._testdir_path2.copy2to1.que b/cmd/bisync/testdata/test_compare_all/golden/_testdir_path1.._testdir_path2.copy2to1.que
index 3b79e78bd1166..8097bfd9d80ca 100644
--- a/cmd/bisync/testdata/test_compare_all/golden/_testdir_path1.._testdir_path2.copy2to1.que
+++ b/cmd/bisync/testdata/test_compare_all/golden/_testdir_path1.._testdir_path2.copy2to1.que
@@ -1,5 +1,5 @@
 "file1.txt"
 "file10.txt"
 "file3.txt"
-"file5.txt..path2"
+"file5.txt.conflict2"
 "file6.txt"
diff --git a/cmd/bisync/testdata/test_compare_all/golden/_testdir_path1.._testdir_path2.path1.lst b/cmd/bisync/testdata/test_compare_all/golden/_testdir_path1.._testdir_path2.path1.lst
index ddb01f4a77fe2..c691a789b1977 100644
--- a/cmd/bisync/testdata/test_compare_all/golden/_testdir_path1.._testdir_path2.path1.lst
+++ b/cmd/bisync/testdata/test_compare_all/golden/_testdir_path1.._testdir_path2.path1.lst
@@ -4,7 +4,7 @@
 -       19 md5:7fe98ed88552b828777d8630900346b8 - 2001-01-02T00:00:00.000000000+0000 "file10.txt"
 -       19 md5:7fe98ed88552b828777d8630900346b8 - 2001-01-02T00:00:00.000000000+0000 "file11.txt"
 -       13 md5:fb3ecfb2800400fb01b0bfd39903e9fb - 2001-01-02T00:00:00.000000000+0000 "file2.txt"
--       39 md5:0860a03592626642f8fd6c8bfb447d2a - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1"
--       39 md5:979a803b15d27df0c31ad7d29006d10b - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2"
+-       39 md5:0860a03592626642f8fd6c8bfb447d2a - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1"
+-       39 md5:979a803b15d27df0c31ad7d29006d10b - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2"
 -       19 md5:7fe98ed88552b828777d8630900346b8 - 2001-01-02T00:00:00.000000000+0000 "file6.txt"
 -       19 md5:7fe98ed88552b828777d8630900346b8 - 2001-01-02T00:00:00.000000000+0000 "file7.txt"
diff --git a/cmd/bisync/testdata/test_compare_all/golden/_testdir_path1.._testdir_path2.path2.lst b/cmd/bisync/testdata/test_compare_all/golden/_testdir_path1.._testdir_path2.path2.lst
index ddb01f4a77fe2..c691a789b1977 100644
--- a/cmd/bisync/testdata/test_compare_all/golden/_testdir_path1.._testdir_path2.path2.lst
+++ b/cmd/bisync/testdata/test_compare_all/golden/_testdir_path1.._testdir_path2.path2.lst
@@ -4,7 +4,7 @@
 -       19 md5:7fe98ed88552b828777d8630900346b8 - 2001-01-02T00:00:00.000000000+0000 "file10.txt"
 -       19 md5:7fe98ed88552b828777d8630900346b8 - 2001-01-02T00:00:00.000000000+0000 "file11.txt"
 -       13 md5:fb3ecfb2800400fb01b0bfd39903e9fb - 2001-01-02T00:00:00.000000000+0000 "file2.txt"
--       39 md5:0860a03592626642f8fd6c8bfb447d2a - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1"
--       39 md5:979a803b15d27df0c31ad7d29006d10b - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2"
+-       39 md5:0860a03592626642f8fd6c8bfb447d2a - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1"
+-       39 md5:979a803b15d27df0c31ad7d29006d10b - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2"
 -       19 md5:7fe98ed88552b828777d8630900346b8 - 2001-01-02T00:00:00.000000000+0000 "file6.txt"
 -       19 md5:7fe98ed88552b828777d8630900346b8 - 2001-01-02T00:00:00.000000000+0000 "file7.txt"
diff --git a/cmd/bisync/testdata/test_compare_all/golden/test.log b/cmd/bisync/testdata/test_compare_all/golden/test.log
index fc2674d7953d9..9f78dbf820999 100644
--- a/cmd/bisync/testdata/test_compare_all/golden/test.log
+++ b/cmd/bisync/testdata/test_compare_all/golden/test.log
@@ -13,10 +13,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": true
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 
 [36m(04)  :[0m [34mtest make modifications on both paths[0m
@@ -94,10 +95,10 @@ INFO  : - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{
 INFO  : - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file2.txt[0m
 INFO  : - [34mPath2[0m    [35m[31mQueue delete[0m[0m              - [36m{path2/}file4.txt[0m
 NOTICE: - [34mWARNING[0m  [35mNew or changed in both paths[0m       - [36mfile5.txt[0m
-NOTICE: - [36mPath1[0m    [35mRenaming Path1 copy[0m                - [36m{path1/}file5.txt..path1[0m
-NOTICE: - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file5.txt..path1[0m
-NOTICE: - [34mPath2[0m    [35mRenaming Path2 copy[0m                - [36m{path2/}file5.txt..path2[0m
-NOTICE: - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}file5.txt..path2[0m
+NOTICE: - [36mPath1[0m    [35mRenaming Path1 copy[0m                - [36m{path1/}file5.txt.conflict1[0m
+NOTICE: - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file5.txt.conflict1[0m
+NOTICE: - [34mPath2[0m    [35mRenaming Path2 copy[0m                - [36m{path2/}file5.txt.conflict2[0m
+NOTICE: - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}file5.txt.conflict2[0m
 INFO  : - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}file6.txt[0m
 INFO  : - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file7.txt[0m
 INFO  : - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}file1.txt[0m
diff --git a/cmd/bisync/testdata/test_createemptysrcdirs/golden/test.log b/cmd/bisync/testdata/test_createemptysrcdirs/golden/test.log
index 06dd5f2c686d9..096c5f0c5d4c5 100644
--- a/cmd/bisync/testdata/test_createemptysrcdirs/golden/test.log
+++ b/cmd/bisync/testdata/test_createemptysrcdirs/golden/test.log
@@ -21,10 +21,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 
 [36m(11)  :[0m [34mtest 1. Create an empty dir on Path1 by creating subdir/placeholder.txt and then deleting the placeholder[0m
@@ -144,10 +145,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 [36m(40)  :[0m [34mlist-dirs {path1/}[0m
 subdir/ - filename hash: 86ae37b338459868804e9697025ba4c2
diff --git a/cmd/bisync/testdata/test_dry_run/golden/_testdir_path1.._testdir_path2.copy1to2.que b/cmd/bisync/testdata/test_dry_run/golden/_testdir_path1.._testdir_path2.copy1to2.que
index 5725b81842f15..74c4ff68a0f0f 100644
--- a/cmd/bisync/testdata/test_dry_run/golden/_testdir_path1.._testdir_path2.copy1to2.que
+++ b/cmd/bisync/testdata/test_dry_run/golden/_testdir_path1.._testdir_path2.copy1to2.que
@@ -1,5 +1,5 @@
 "file11.txt"
 "file2.txt"
 "file4.txt"
-"file5.txt..path1"
+"file5.txt.conflict1"
 "file7.txt"
diff --git a/cmd/bisync/testdata/test_dry_run/golden/_testdir_path1.._testdir_path2.copy2to1.que b/cmd/bisync/testdata/test_dry_run/golden/_testdir_path1.._testdir_path2.copy2to1.que
index 3b79e78bd1166..8097bfd9d80ca 100644
--- a/cmd/bisync/testdata/test_dry_run/golden/_testdir_path1.._testdir_path2.copy2to1.que
+++ b/cmd/bisync/testdata/test_dry_run/golden/_testdir_path1.._testdir_path2.copy2to1.que
@@ -1,5 +1,5 @@
 "file1.txt"
 "file10.txt"
 "file3.txt"
-"file5.txt..path2"
+"file5.txt.conflict2"
 "file6.txt"
diff --git a/cmd/bisync/testdata/test_dry_run/golden/_testdir_path1.._testdir_path2.path1.lst b/cmd/bisync/testdata/test_dry_run/golden/_testdir_path1.._testdir_path2.path1.lst
index 19e9623a54214..28bcb7af77d12 100644
--- a/cmd/bisync/testdata/test_dry_run/golden/_testdir_path1.._testdir_path2.path1.lst
+++ b/cmd/bisync/testdata/test_dry_run/golden/_testdir_path1.._testdir_path2.path1.lst
@@ -4,7 +4,7 @@
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file10.txt"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file11.txt"
 -       13 - - 2001-01-02T00:00:00.000000000+0000 "file2.txt"
--       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1"
--       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2"
+-       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1"
+-       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file6.txt"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file7.txt"
diff --git a/cmd/bisync/testdata/test_dry_run/golden/_testdir_path1.._testdir_path2.path2.lst b/cmd/bisync/testdata/test_dry_run/golden/_testdir_path1.._testdir_path2.path2.lst
index 19e9623a54214..28bcb7af77d12 100644
--- a/cmd/bisync/testdata/test_dry_run/golden/_testdir_path1.._testdir_path2.path2.lst
+++ b/cmd/bisync/testdata/test_dry_run/golden/_testdir_path1.._testdir_path2.path2.lst
@@ -4,7 +4,7 @@
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file10.txt"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file11.txt"
 -       13 - - 2001-01-02T00:00:00.000000000+0000 "file2.txt"
--       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1"
--       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2"
+-       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1"
+-       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file6.txt"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "file7.txt"
diff --git a/cmd/bisync/testdata/test_dry_run/golden/dryrun._testdir_path1.._testdir_path2.copy1to2.que b/cmd/bisync/testdata/test_dry_run/golden/dryrun._testdir_path1.._testdir_path2.copy1to2.que
index 5725b81842f15..74c4ff68a0f0f 100644
--- a/cmd/bisync/testdata/test_dry_run/golden/dryrun._testdir_path1.._testdir_path2.copy1to2.que
+++ b/cmd/bisync/testdata/test_dry_run/golden/dryrun._testdir_path1.._testdir_path2.copy1to2.que
@@ -1,5 +1,5 @@
 "file11.txt"
 "file2.txt"
 "file4.txt"
-"file5.txt..path1"
+"file5.txt.conflict1"
 "file7.txt"
diff --git a/cmd/bisync/testdata/test_dry_run/golden/dryrun._testdir_path1.._testdir_path2.copy2to1.que b/cmd/bisync/testdata/test_dry_run/golden/dryrun._testdir_path1.._testdir_path2.copy2to1.que
index 3b79e78bd1166..8097bfd9d80ca 100644
--- a/cmd/bisync/testdata/test_dry_run/golden/dryrun._testdir_path1.._testdir_path2.copy2to1.que
+++ b/cmd/bisync/testdata/test_dry_run/golden/dryrun._testdir_path1.._testdir_path2.copy2to1.que
@@ -1,5 +1,5 @@
 "file1.txt"
 "file10.txt"
 "file3.txt"
-"file5.txt..path2"
+"file5.txt.conflict2"
 "file6.txt"
diff --git a/cmd/bisync/testdata/test_dry_run/golden/test.log b/cmd/bisync/testdata/test_dry_run/golden/test.log
index 1736942d44418..0eca08d1c386d 100644
--- a/cmd/bisync/testdata/test_dry_run/golden/test.log
+++ b/cmd/bisync/testdata/test_dry_run/golden/test.log
@@ -14,10 +14,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 
 [36m(04)  :[0m [34mtest new on path2 - file10[0m
@@ -65,12 +66,12 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
 NOTICE: file10.txt: Skipped copy as --dry-run is set (size 19)
 NOTICE: file4.txt: Skipped copy as --dry-run is set (size 0)
 NOTICE: file6.txt: Skipped copy as --dry-run is set (size 19)
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 NOTICE: file1.txt: Skipped copy as --dry-run is set (size 0)
 NOTICE: file11.txt: Skipped copy as --dry-run is set (size 19)
 NOTICE: file2.txt: Skipped copy as --dry-run is set (size 13)
@@ -123,12 +124,10 @@ INFO  : - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{
 INFO  : - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file2.txt[0m
 INFO  : - [34mPath2[0m    [35m[31mQueue delete[0m[0m              - [36m{path2/}file4.txt[0m
 NOTICE: - [34mWARNING[0m  [35mNew or changed in both paths[0m       - [36mfile5.txt[0m
-NOTICE: - [36mPath1[0m    [35mRenaming Path1 copy[0m                - [36m{path1/}file5.txt..path1[0m
-NOTICE: file5.txt: Skipped move as --dry-run is set (size 39)
-NOTICE: - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file5.txt..path1[0m
-NOTICE: - [34mPath2[0m    [35mRenaming Path2 copy[0m                - [36m{path2/}file5.txt..path2[0m
-NOTICE: file5.txt: Skipped move as --dry-run is set (size 39)
-NOTICE: - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}file5.txt..path2[0m
+NOTICE: file5.txt: Skipped rename as --dry-run is set
+NOTICE: - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file5.txt.conflict1[0m
+NOTICE: file5.txt: Skipped rename as --dry-run is set
+NOTICE: - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}file5.txt.conflict2[0m
 INFO  : - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}file6.txt[0m
 INFO  : - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file7.txt[0m
 INFO  : - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}file1.txt[0m
@@ -190,10 +189,10 @@ INFO  : - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{
 INFO  : - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file2.txt[0m
 INFO  : - [34mPath2[0m    [35m[31mQueue delete[0m[0m              - [36m{path2/}file4.txt[0m
 NOTICE: - [34mWARNING[0m  [35mNew or changed in both paths[0m       - [36mfile5.txt[0m
-NOTICE: - [36mPath1[0m    [35mRenaming Path1 copy[0m                - [36m{path1/}file5.txt..path1[0m
-NOTICE: - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file5.txt..path1[0m
-NOTICE: - [34mPath2[0m    [35mRenaming Path2 copy[0m                - [36m{path2/}file5.txt..path2[0m
-NOTICE: - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}file5.txt..path2[0m
+NOTICE: - [36mPath1[0m    [35mRenaming Path1 copy[0m                - [36m{path1/}file5.txt.conflict1[0m
+NOTICE: - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file5.txt.conflict1[0m
+NOTICE: - [34mPath2[0m    [35mRenaming Path2 copy[0m                - [36m{path2/}file5.txt.conflict2[0m
+NOTICE: - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}file5.txt.conflict2[0m
 INFO  : - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}file6.txt[0m
 INFO  : - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file7.txt[0m
 INFO  : - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}file1.txt[0m
diff --git a/cmd/bisync/testdata/test_equal/golden/_testdir_path1.._testdir_path2.copy1to2.que b/cmd/bisync/testdata/test_equal/golden/_testdir_path1.._testdir_path2.copy1to2.que
index d988a5ab11a82..91974e0092235 100644
--- a/cmd/bisync/testdata/test_equal/golden/_testdir_path1.._testdir_path2.copy1to2.que
+++ b/cmd/bisync/testdata/test_equal/golden/_testdir_path1.._testdir_path2.copy1to2.que
@@ -1,1 +1,1 @@
-"file1.txt..path1"
+"file1.txt.conflict1"
diff --git a/cmd/bisync/testdata/test_equal/golden/_testdir_path1.._testdir_path2.copy2to1.que b/cmd/bisync/testdata/test_equal/golden/_testdir_path1.._testdir_path2.copy2to1.que
index 7f99cd1cee80d..172a192aae4cf 100644
--- a/cmd/bisync/testdata/test_equal/golden/_testdir_path1.._testdir_path2.copy2to1.que
+++ b/cmd/bisync/testdata/test_equal/golden/_testdir_path1.._testdir_path2.copy2to1.que
@@ -1,1 +1,1 @@
-"file1.txt..path2"
+"file1.txt.conflict2"
diff --git a/cmd/bisync/testdata/test_equal/golden/_testdir_path1.._testdir_path2.path1.lst b/cmd/bisync/testdata/test_equal/golden/_testdir_path1.._testdir_path2.path1.lst
index 3e93d92de35c4..2e181c871cff8 100644
--- a/cmd/bisync/testdata/test_equal/golden/_testdir_path1.._testdir_path2.path1.lst
+++ b/cmd/bisync/testdata/test_equal/golden/_testdir_path1.._testdir_path2.path1.lst
@@ -1,5 +1,5 @@
 # bisync listing v1 from test
 -      109 - - 2000-01-01T00:00:00.000000000+0000 "RCLONE_TEST"
--       33 - - 2001-03-04T00:00:00.000000000+0000 "file1.txt..path1"
--       33 - - 2001-01-02T00:00:00.000000000+0000 "file1.txt..path2"
+-       33 - - 2001-03-04T00:00:00.000000000+0000 "file1.txt.conflict1"
+-       33 - - 2001-01-02T00:00:00.000000000+0000 "file1.txt.conflict2"
 -       37 - - 2001-01-02T00:00:00.000000000+0000 "file2.txt"
diff --git a/cmd/bisync/testdata/test_equal/golden/_testdir_path1.._testdir_path2.path2.lst b/cmd/bisync/testdata/test_equal/golden/_testdir_path1.._testdir_path2.path2.lst
index 3e93d92de35c4..2e181c871cff8 100644
--- a/cmd/bisync/testdata/test_equal/golden/_testdir_path1.._testdir_path2.path2.lst
+++ b/cmd/bisync/testdata/test_equal/golden/_testdir_path1.._testdir_path2.path2.lst
@@ -1,5 +1,5 @@
 # bisync listing v1 from test
 -      109 - - 2000-01-01T00:00:00.000000000+0000 "RCLONE_TEST"
--       33 - - 2001-03-04T00:00:00.000000000+0000 "file1.txt..path1"
--       33 - - 2001-01-02T00:00:00.000000000+0000 "file1.txt..path2"
+-       33 - - 2001-03-04T00:00:00.000000000+0000 "file1.txt.conflict1"
+-       33 - - 2001-01-02T00:00:00.000000000+0000 "file1.txt.conflict2"
 -       37 - - 2001-01-02T00:00:00.000000000+0000 "file2.txt"
diff --git a/cmd/bisync/testdata/test_equal/golden/test.log b/cmd/bisync/testdata/test_equal/golden/test.log
index e496bc95e391d..0a7f9ab34dca4 100644
--- a/cmd/bisync/testdata/test_equal/golden/test.log
+++ b/cmd/bisync/testdata/test_equal/golden/test.log
@@ -14,10 +14,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 
 [36m(04)  :[0m [34mtest changed on both paths and NOT identical - file1 (file1R, file1L)[0m
@@ -63,10 +64,10 @@ NOTICE: {path2String}: 1 errors while checking
 NOTICE: {path2String}: 1 matching files
 INFO  : Finished checking the potential conflicts. 1 differences found
 NOTICE: - [34mWARNING[0m  [35mNew or changed in both paths[0m       - [36mfile1.txt[0m
-NOTICE: - [36mPath1[0m    [35mRenaming Path1 copy[0m                - [36m{path1/}file1.txt..path1[0m
-NOTICE: - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file1.txt..path1[0m
-NOTICE: - [34mPath2[0m    [35mRenaming Path2 copy[0m                - [36m{path2/}file1.txt..path2[0m
-NOTICE: - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}file1.txt..path2[0m
+NOTICE: - [36mPath1[0m    [35mRenaming Path1 copy[0m                - [36m{path1/}file1.txt.conflict1[0m
+NOTICE: - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file1.txt.conflict1[0m
+NOTICE: - [34mPath2[0m    [35mRenaming Path2 copy[0m                - [36m{path2/}file1.txt.conflict2[0m
+NOTICE: - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}file1.txt.conflict2[0m
 NOTICE: - [34mWARNING[0m  [35mNew or changed in both paths[0m       - [36mfile2.txt[0m
 INFO  : Files are equal! Skipping: file2.txt
 INFO  : - [34mPath2[0m    [35mDo queued copies to[0m                - [36mPath1[0m
diff --git a/cmd/bisync/testdata/test_extended_char_paths/golden/test.log b/cmd/bisync/testdata/test_extended_char_paths/golden/test.log
index ede7e180702ad..463e8e9671f09 100644
--- a/cmd/bisync/testdata/test_extended_char_paths/golden/test.log
+++ b/cmd/bisync/testdata/test_extended_char_paths/golden/test.log
@@ -25,10 +25,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}測試_Русский_ _ _ě_áñ/" with Path2 "{path2/}測試_Русский_ _ _ě_áñ/"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}測試_Русский_ _ _ě_áñ/" vs Path2 "{path2/}測試_Русский_ _ _ě_áñ/"
 INFO  : [32mBisync successful[0m
 [36m(14)  :[0m [34mcopy-listings resync[0m
 
@@ -81,10 +82,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 [36m(24)  :[0m [34mdelete-file {path1/}測試_Русский_{spc}_{spc}_ě_áñ/測試_check{spc}file[0m
 [36m(25)  :[0m [34mbisync check-access check-filename=測試_check{spc}file[0m
@@ -125,10 +127,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 [36m(29)  :[0m [34mbisync check-access check-filename=測試_check{spc}file[0m
 INFO  : [2mSetting --ignore-listing-checksum as neither --checksum nor --compare checksum are set.[0m
@@ -169,10 +172,11 @@ INFO  : Bisyncing with Comparison Settings:
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
 INFO  : Using filters file {workdir/}測試_filtersfile.txt
 INFO  : Storing filters file hash to {workdir/}測試_filtersfile.txt.md5
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 [36m(34)  :[0m [34mcopy-as {datadir/}file1.txt {path1/} fileZ.txt[0m
 [36m(35)  :[0m [34mbisync filters-file={workdir/}測試_filtersfile.txt[0m
diff --git a/cmd/bisync/testdata/test_extended_filenames/golden/_testdir_path1.._testdir_path2.copy1to2.que b/cmd/bisync/testdata/test_extended_filenames/golden/_testdir_path1.._testdir_path2.copy1to2.que
index 75c663f86291e..390061065fe11 100644
--- a/cmd/bisync/testdata/test_extended_filenames/golden/_testdir_path1.._testdir_path2.copy1to2.que
+++ b/cmd/bisync/testdata/test_extended_filenames/golden/_testdir_path1.._testdir_path2.copy1to2.que
@@ -1,6 +1,6 @@
 "file1_with white space.txt"
 "filename_contains_ࢺ_p1m.txt"
 "subdir_with_ࢺ_/file_with_測試_.txt"
-"subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt..path1"
+"subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt.conflict1"
 "subdir_with_ࢺ_/mañana_funcionará.txt"
 "subdir_with_ࢺ_/test.txt"
diff --git a/cmd/bisync/testdata/test_extended_filenames/golden/_testdir_path1.._testdir_path2.copy2to1.que b/cmd/bisync/testdata/test_extended_filenames/golden/_testdir_path1.._testdir_path2.copy2to1.que
index 5c39d3955d4ca..cd49320196ff8 100644
--- a/cmd/bisync/testdata/test_extended_filenames/golden/_testdir_path1.._testdir_path2.copy2to1.que
+++ b/cmd/bisync/testdata/test_extended_filenames/golden/_testdir_path1.._testdir_path2.copy2to1.que
@@ -3,7 +3,7 @@
 "filename_contains_ࢺ_.txt"
 "subdir with␊white space.txt/file2 with␊white space.txt"
 "subdir_rawchars_␙_\x81_\xfe/file3_␙_\x81_\xfe"
-"subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt..path2"
+"subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt.conflict2"
 "subdir_with_ࢺ_/filename_contains_ě_.txt"
 "subdir_with_ࢺ_/filename_contains_ࢺ_p2s.txt"
 "Русский.txt"
diff --git a/cmd/bisync/testdata/test_extended_filenames/golden/_testdir_path1.._testdir_path2.path1.lst b/cmd/bisync/testdata/test_extended_filenames/golden/_testdir_path1.._testdir_path2.path1.lst
index 348c62c3d9d56..619c3a8a2f91f 100644
--- a/cmd/bisync/testdata/test_extended_filenames/golden/_testdir_path1.._testdir_path2.path1.lst
+++ b/cmd/bisync/testdata/test_extended_filenames/golden/_testdir_path1.._testdir_path2.path1.lst
@@ -11,8 +11,8 @@
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "subdir with␊white space.txt/file2 with␊white space.txt"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "subdir_rawchars_␙_\x81_\xfe/file3_␙_\x81_\xfe"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "subdir_with_ࢺ_/file_with_測試_.txt"
--       19 - - 2001-01-03T00:00:00.000000000+0000 "subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt..path1"
--       42 - - 2001-01-02T00:00:00.000000000+0000 "subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt..path2"
+-       19 - - 2001-01-03T00:00:00.000000000+0000 "subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt.conflict1"
+-       42 - - 2001-01-02T00:00:00.000000000+0000 "subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt.conflict2"
 -      272 - - 2000-01-01T00:00:00.000000000+0000 "subdir_with_ࢺ_/filename_contains_ࢺ_.txt"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "subdir_with_ࢺ_/filename_contains_ࢺ_p2s.txt"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "subdir_with_ࢺ_/mañana_funcionará.txt"
diff --git a/cmd/bisync/testdata/test_extended_filenames/golden/_testdir_path1.._testdir_path2.path2.lst b/cmd/bisync/testdata/test_extended_filenames/golden/_testdir_path1.._testdir_path2.path2.lst
index 348c62c3d9d56..619c3a8a2f91f 100644
--- a/cmd/bisync/testdata/test_extended_filenames/golden/_testdir_path1.._testdir_path2.path2.lst
+++ b/cmd/bisync/testdata/test_extended_filenames/golden/_testdir_path1.._testdir_path2.path2.lst
@@ -11,8 +11,8 @@
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "subdir with␊white space.txt/file2 with␊white space.txt"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "subdir_rawchars_␙_\x81_\xfe/file3_␙_\x81_\xfe"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "subdir_with_ࢺ_/file_with_測試_.txt"
--       19 - - 2001-01-03T00:00:00.000000000+0000 "subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt..path1"
--       42 - - 2001-01-02T00:00:00.000000000+0000 "subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt..path2"
+-       19 - - 2001-01-03T00:00:00.000000000+0000 "subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt.conflict1"
+-       42 - - 2001-01-02T00:00:00.000000000+0000 "subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt.conflict2"
 -      272 - - 2000-01-01T00:00:00.000000000+0000 "subdir_with_ࢺ_/filename_contains_ࢺ_.txt"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "subdir_with_ࢺ_/filename_contains_ࢺ_p2s.txt"
 -       19 - - 2001-01-02T00:00:00.000000000+0000 "subdir_with_ࢺ_/mañana_funcionará.txt"
diff --git a/cmd/bisync/testdata/test_extended_filenames/golden/test.log b/cmd/bisync/testdata/test_extended_filenames/golden/test.log
index 5f5e319592397..eda13848c0f59 100644
--- a/cmd/bisync/testdata/test_extended_filenames/golden/test.log
+++ b/cmd/bisync/testdata/test_extended_filenames/golden/test.log
@@ -23,10 +23,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 
 [36m(12)  :[0m [34mtest place a newer files on both paths[0m
@@ -96,10 +97,10 @@ INFO  : - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{
 INFO  : - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}filename_contains_ࢺ_p1m.txt[0m
 INFO  : - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}subdir_with_ࢺ_/file_with_測試_.txt[0m
 NOTICE: - [34mWARNING[0m  [35mNew or changed in both paths[0m       - [36msubdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt[0m
-NOTICE: - [36mPath1[0m    [35mRenaming Path1 copy[0m                - [36m{path1/}subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt..path1[0m
-NOTICE: - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt..path1[0m
-NOTICE: - [34mPath2[0m    [35mRenaming Path2 copy[0m                - [36m{path2/}subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt..path2[0m
-NOTICE: - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt..path2[0m
+NOTICE: - [36mPath1[0m    [35mRenaming Path1 copy[0m                - [36m{path1/}subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt.conflict1[0m
+NOTICE: - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt.conflict1[0m
+NOTICE: - [34mPath2[0m    [35mRenaming Path2 copy[0m                - [36m{path2/}subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt.conflict2[0m
+NOTICE: - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt.conflict2[0m
 INFO  : - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}subdir_with_ࢺ_/mañana_funcionará.txt[0m
 INFO  : - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}subdir_with_ࢺ_/test.txt[0m
 INFO  : - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}Русский.txt[0m
diff --git a/cmd/bisync/testdata/test_filters/golden/test.log b/cmd/bisync/testdata/test_filters/golden/test.log
index c43a9beb5562f..9da9b21305acc 100644
--- a/cmd/bisync/testdata/test_filters/golden/test.log
+++ b/cmd/bisync/testdata/test_filters/golden/test.log
@@ -18,10 +18,11 @@ INFO  : Bisyncing with Comparison Settings:
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
 INFO  : Using filters file {workdir/}filtersfile.flt
 INFO  : Storing filters file hash to {workdir/}filtersfile.flt.md5
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 
 [36m(05)  :[0m [34mcopy-listings resync[0m
diff --git a/cmd/bisync/testdata/test_filtersfile_checks/golden/test.log b/cmd/bisync/testdata/test_filtersfile_checks/golden/test.log
index 5d15dbe36f47e..a60aa5d494762 100644
--- a/cmd/bisync/testdata/test_filtersfile_checks/golden/test.log
+++ b/cmd/bisync/testdata/test_filtersfile_checks/golden/test.log
@@ -14,10 +14,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 
 [36m(04)  :[0m [34mtest 1. inject filters file in workdir.[0m
@@ -78,10 +79,11 @@ INFO  : Bisyncing with Comparison Settings:
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
 INFO  : Using filters file {workdir/}filtersfile.txt
 INFO  : Storing filters file hash to {workdir/}filtersfile.txt.md5
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 
 [36m(12)  :[0m [34mtest 5. run with filters-file alone. should run.[0m
@@ -142,9 +144,9 @@ INFO  : Bisyncing with Comparison Settings:
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
 INFO  : Using filters file {workdir/}filtersfile.txt
 INFO  : Skipped storing filters file hash to {workdir/}filtersfile.txt.md5 as --dry-run is set
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
 INFO  : [32mBisync successful[0m
 
diff --git a/cmd/bisync/testdata/test_ignorelistingchecksum/golden/test.log b/cmd/bisync/testdata/test_ignorelistingchecksum/golden/test.log
index fc6fc4e8f719b..f54cd7baf8526 100644
--- a/cmd/bisync/testdata/test_ignorelistingchecksum/golden/test.log
+++ b/cmd/bisync/testdata/test_ignorelistingchecksum/golden/test.log
@@ -14,10 +14,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 [36m(04)  :[0m [34mbisync resync ignore-listing-checksum[0m
 INFO  : Bisyncing with Comparison Settings:
@@ -30,10 +31,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 
 [36m(05)  :[0m [34mtest place newer files on both paths[0m
diff --git a/cmd/bisync/testdata/test_max_delete_path1/golden/test.log b/cmd/bisync/testdata/test_max_delete_path1/golden/test.log
index 877b48f0a5ed1..42aff09c0808c 100644
--- a/cmd/bisync/testdata/test_max_delete_path1/golden/test.log
+++ b/cmd/bisync/testdata/test_max_delete_path1/golden/test.log
@@ -14,10 +14,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 
 [36m(04)  :[0m [34mtest delete >50% of local files[0m
diff --git a/cmd/bisync/testdata/test_max_delete_path2_force/golden/test.log b/cmd/bisync/testdata/test_max_delete_path2_force/golden/test.log
index d6efc59816536..1cc290994505c 100644
--- a/cmd/bisync/testdata/test_max_delete_path2_force/golden/test.log
+++ b/cmd/bisync/testdata/test_max_delete_path2_force/golden/test.log
@@ -14,10 +14,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 
 [36m(04)  :[0m [34mtest delete >50% of remote files[0m
diff --git a/cmd/bisync/testdata/test_normalization/golden/test.log b/cmd/bisync/testdata/test_normalization/golden/test.log
index c8c0f2a6d96cc..5e4cbbccfc152 100644
--- a/cmd/bisync/testdata/test_normalization/golden/test.log
+++ b/cmd/bisync/testdata/test_normalization/golden/test.log
@@ -15,10 +15,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 
 
@@ -93,10 +94,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 
 
@@ -166,10 +168,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 
 [36m(29)  :[0m [34mtest changed on one path[0m
diff --git a/cmd/bisync/testdata/test_rclone_args/golden/test.log b/cmd/bisync/testdata/test_rclone_args/golden/test.log
index 10819ff05cab3..73ede1e69d112 100644
--- a/cmd/bisync/testdata/test_rclone_args/golden/test.log
+++ b/cmd/bisync/testdata/test_rclone_args/golden/test.log
@@ -13,10 +13,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": true
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 
 [36m(04)  :[0m [34mtest place newer files on both paths[0m
@@ -104,10 +105,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 
 [36m(19)  :[0m [34mcopy-file {datadir/}file1.txt {path1/}[0m
@@ -154,10 +156,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": true
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 
 [36m(25)  :[0m [34mcopy-as {datadir/}file21.txt {path2/} file2.txt[0m
diff --git a/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.copy1to2.que b/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.copy1to2.que
new file mode 100644
index 0000000000000..029f3e190ed2c
--- /dev/null
+++ b/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.copy1to2.que
@@ -0,0 +1,1 @@
+"file1.txt"
diff --git a/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.copy2to1.que b/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.copy2to1.que
new file mode 100644
index 0000000000000..9ed593ba3ffff
--- /dev/null
+++ b/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.copy2to1.que
@@ -0,0 +1,1 @@
+"file2.txt"
diff --git a/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path1.lst b/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path1.lst
new file mode 100644
index 0000000000000..57872a02756ec
--- /dev/null
+++ b/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path1.lst
@@ -0,0 +1,10 @@
+# bisync listing v1 from test
+-      109 - - 2000-01-01T00:00:00.000000000+0000 "RCLONE_TEST"
+-       33 - - 2006-03-04T00:00:00.000000000+0000 "file1.txt"
+-       33 - - 2004-07-23T00:00:00.000000000+0000 "file1.txt..path1"
+-       33 - - 2004-07-23T00:00:00.000000000+0000 "file1.txt..path2"
+-       33 - - 2002-08-26T00:00:00.000000000+0000 "file1.txt.apple1"
+-       33 - - 2002-07-23T00:00:00.000000000+0000 "file1.txt.apple2"
+-       33 - - 2003-07-23T00:00:00.000000000+0000 "file1.txt.cloud1"
+-       33 - - 2001-08-26T00:00:00.000000000+0000 "file1.txt.dinosaur1"
+-       33 - - 2003-07-23T00:00:00.000000000+0000 "file1.txt.local1"
diff --git a/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path1.lst-new b/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path1.lst-new
new file mode 100644
index 0000000000000..454d9344c69bb
--- /dev/null
+++ b/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path1.lst-new
@@ -0,0 +1,11 @@
+# bisync listing v1 from test
+-      109 - - 2000-01-01T00:00:00.000000000+0000 "RCLONE_TEST"
+-       33 - - 2006-03-04T00:00:00.000000000+0000 "file1.txt"
+-       33 - - 2004-07-23T00:00:00.000000000+0000 "file1.txt..path1"
+-       33 - - 2004-07-23T00:00:00.000000000+0000 "file1.txt..path2"
+-       33 - - 2002-08-26T00:00:00.000000000+0000 "file1.txt.apple1"
+-       33 - - 2002-07-23T00:00:00.000000000+0000 "file1.txt.apple2"
+-       33 - - 2003-07-23T00:00:00.000000000+0000 "file1.txt.cloud1"
+-       33 - - 2001-08-26T00:00:00.000000000+0000 "file1.txt.dinosaur1"
+-       33 - - 2003-07-23T00:00:00.000000000+0000 "file1.txt.local1"
+-       33 - - 2005-01-02T00:00:00.000000000+0000 "file2.txt"
diff --git a/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path1.lst-old b/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path1.lst-old
new file mode 100644
index 0000000000000..2779be7abae84
--- /dev/null
+++ b/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path1.lst-old
@@ -0,0 +1,10 @@
+# bisync listing v1 from test
+-      109 - - 2000-01-01T00:00:00.000000000+0000 "RCLONE_TEST"
+-       33 - - 2004-07-23T00:00:00.000000000+0000 "file1.txt..path1"
+-       33 - - 2004-07-23T00:00:00.000000000+0000 "file1.txt..path2"
+-       33 - - 2002-08-26T00:00:00.000000000+0000 "file1.txt.apple1"
+-       33 - - 2002-07-23T00:00:00.000000000+0000 "file1.txt.apple2"
+-       33 - - 2003-07-23T00:00:00.000000000+0000 "file1.txt.cloud1"
+-       33 - - 2001-08-26T00:00:00.000000000+0000 "file1.txt.dinosaur1"
+-       33 - - 2003-07-23T00:00:00.000000000+0000 "file1.txt.local1"
+-        0 - - 2000-01-01T00:00:00.000000000+0000 "file2.txt"
diff --git a/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path2.lst b/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path2.lst
new file mode 100644
index 0000000000000..57872a02756ec
--- /dev/null
+++ b/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path2.lst
@@ -0,0 +1,10 @@
+# bisync listing v1 from test
+-      109 - - 2000-01-01T00:00:00.000000000+0000 "RCLONE_TEST"
+-       33 - - 2006-03-04T00:00:00.000000000+0000 "file1.txt"
+-       33 - - 2004-07-23T00:00:00.000000000+0000 "file1.txt..path1"
+-       33 - - 2004-07-23T00:00:00.000000000+0000 "file1.txt..path2"
+-       33 - - 2002-08-26T00:00:00.000000000+0000 "file1.txt.apple1"
+-       33 - - 2002-07-23T00:00:00.000000000+0000 "file1.txt.apple2"
+-       33 - - 2003-07-23T00:00:00.000000000+0000 "file1.txt.cloud1"
+-       33 - - 2001-08-26T00:00:00.000000000+0000 "file1.txt.dinosaur1"
+-       33 - - 2003-07-23T00:00:00.000000000+0000 "file1.txt.local1"
diff --git a/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path2.lst-new b/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path2.lst-new
new file mode 100644
index 0000000000000..8b02b6d6a1c2e
--- /dev/null
+++ b/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path2.lst-new
@@ -0,0 +1,11 @@
+# bisync listing v1 from test
+-      109 - - 2000-01-01T00:00:00.000000000+0000 "RCLONE_TEST"
+-       33 - - 2005-01-02T00:00:00.000000000+0000 "file1.txt"
+-       33 - - 2004-07-23T00:00:00.000000000+0000 "file1.txt..path1"
+-       33 - - 2004-07-23T00:00:00.000000000+0000 "file1.txt..path2"
+-       33 - - 2002-08-26T00:00:00.000000000+0000 "file1.txt.apple1"
+-       33 - - 2002-07-23T00:00:00.000000000+0000 "file1.txt.apple2"
+-       33 - - 2003-07-23T00:00:00.000000000+0000 "file1.txt.cloud1"
+-       33 - - 2001-08-26T00:00:00.000000000+0000 "file1.txt.dinosaur1"
+-       33 - - 2003-07-23T00:00:00.000000000+0000 "file1.txt.local1"
+-       33 - - 2006-03-04T00:00:00.000000000+0000 "file2.txt"
diff --git a/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path2.lst-old b/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path2.lst-old
new file mode 100644
index 0000000000000..2779be7abae84
--- /dev/null
+++ b/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path2.lst-old
@@ -0,0 +1,10 @@
+# bisync listing v1 from test
+-      109 - - 2000-01-01T00:00:00.000000000+0000 "RCLONE_TEST"
+-       33 - - 2004-07-23T00:00:00.000000000+0000 "file1.txt..path1"
+-       33 - - 2004-07-23T00:00:00.000000000+0000 "file1.txt..path2"
+-       33 - - 2002-08-26T00:00:00.000000000+0000 "file1.txt.apple1"
+-       33 - - 2002-07-23T00:00:00.000000000+0000 "file1.txt.apple2"
+-       33 - - 2003-07-23T00:00:00.000000000+0000 "file1.txt.cloud1"
+-       33 - - 2001-08-26T00:00:00.000000000+0000 "file1.txt.dinosaur1"
+-       33 - - 2003-07-23T00:00:00.000000000+0000 "file1.txt.local1"
+-        0 - - 2000-01-01T00:00:00.000000000+0000 "file2.txt"
diff --git a/cmd/bisync/testdata/test_resolve/golden/test.log b/cmd/bisync/testdata/test_resolve/golden/test.log
new file mode 100644
index 0000000000000..9223c3f6a59b4
--- /dev/null
+++ b/cmd/bisync/testdata/test_resolve/golden/test.log
@@ -0,0 +1,305 @@
+[36m(01)  :[0m [34mtest resolve[0m
+
+
+[36m(02)  :[0m [34mtest initial bisync[0m
+[36m(03)  :[0m [34mbisync resync[0m
+INFO  : [2mSetting --ignore-listing-checksum as neither --checksum nor --compare checksum are set.[0m
+INFO  : Bisyncing with Comparison Settings:
+{
+"Modtime": true,
+"Size": true,
+"Checksum": false,
+"NoSlowHash": false,
+"SlowHashSyncOnly": false,
+"DownloadHash": false
+}
+INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
+INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
+INFO  : [32mBisync successful[0m
+
+[36m(04)  :[0m [34mtest changed on both paths and NOT identical - file1 (file1R, file1L)[0m
+[36m(05)  :[0m [34mtouch-glob 2001-01-02 {datadir/} file1R.txt[0m
+[36m(06)  :[0m [34mcopy-as {datadir/}file1R.txt {path2/} file1.txt[0m
+[36m(07)  :[0m [34mtouch-glob 2001-03-04 {datadir/} file1L.txt[0m
+[36m(08)  :[0m [34mcopy-as {datadir/}file1L.txt {path1/} file1.txt[0m
+
+[36m(09)  :[0m [34mtest bisync run with --conflict-resolve=newer --conflict-loser=delete --conflict-suffix=potato[0m
+
+[36m(10)  :[0m [34mbisync conflict-resolve=newer conflict-loser=delete conflict-suffix=potato[0m
+INFO  : [2mSetting --ignore-listing-checksum as neither --checksum nor --compare checksum are set.[0m
+INFO  : Bisyncing with Comparison Settings:
+{
+"Modtime": true,
+"Size": true,
+"Checksum": false,
+"NoSlowHash": false,
+"SlowHashSyncOnly": false,
+"DownloadHash": false
+}
+INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
+INFO  : Building Path1 and Path2 listings
+INFO  : Path1 checking for diffs
+INFO  : - [36mPath1[0m    [35m[33mFile changed: [35msize (larger)[0m, [35mtime (newer)[0m[0m[0m - [36mfile1.txt[0m
+INFO  : Path1:    1 changes: [32m   0 new[0m, [33m   1 modified[0m, [31m   0 deleted[0m
+INFO  : ([33mModified[0m: [36m   1 newer[0m, [34m   0 older[0m, [36m   1 larger[0m, [34m   0 smaller[0m)
+INFO  : Path2 checking for diffs
+INFO  : - [34mPath2[0m    [35m[33mFile changed: [35msize (larger)[0m, [35mtime (newer)[0m[0m[0m - [36mfile1.txt[0m
+INFO  : Path2:    1 changes: [32m   0 new[0m, [33m   1 modified[0m, [31m   0 deleted[0m
+INFO  : ([33mModified[0m: [36m   1 newer[0m, [34m   0 older[0m, [36m   1 larger[0m, [34m   0 smaller[0m)
+INFO  : Applying changes
+INFO  : Checking potential conflicts...
+ERROR : file1.txt: md5 differ
+NOTICE: {path2String}: 1 differences found
+NOTICE: {path2String}: 1 errors while checking
+INFO  : Finished checking the potential conflicts. 1 differences found
+NOTICE: - [34mWARNING[0m  [35mNew or changed in both paths[0m       - [36mfile1.txt[0m
+INFO  : file1.txt: Path1 is newer. Path1: 2001-03-04 00:00:00 +0000 UTC, Path2: 2001-01-02 00:00:00 +0000 UTC, Difference: 1464h0m0s
+INFO  : file1.txt: [32mThe winner is: Path1[0m
+NOTICE: - [34mPath2[0m    [35mDeleting Path2 copy[0m                - [36m{path2/}file1.txt[0m
+INFO  : - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36mfile1.txt[0m
+INFO  : - [36mPath1[0m    [35mDo queued copies to[0m                - [36mPath2[0m
+INFO  : Updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
+INFO  : [32mBisync successful[0m
+
+[36m(11)  :[0m [34mtest changed on both paths and NOT identical - file1 (file1R, file1L)[0m
+[36m(12)  :[0m [34mtouch-glob 2001-07-23 {datadir/} file1R.txt[0m
+[36m(13)  :[0m [34mcopy-as {datadir/}file1R.txt {path2/} file1.txt[0m
+[36m(14)  :[0m [34mtouch-glob 2001-08-26 {datadir/} file1L.txt[0m
+[36m(15)  :[0m [34mcopy-as {datadir/}file1L.txt {path1/} file1.txt[0m
+
+[36m(16)  :[0m [34mtest bisync run with --conflict-resolve=path2 --conflict-loser=num --conflict-suffix=dinosaur[0m
+
+[36m(17)  :[0m [34mbisync conflict-resolve=path2 conflict-loser=num conflict-suffix=dinosaur[0m
+INFO  : [2mSetting --ignore-listing-checksum as neither --checksum nor --compare checksum are set.[0m
+INFO  : Bisyncing with Comparison Settings:
+{
+"Modtime": true,
+"Size": true,
+"Checksum": false,
+"NoSlowHash": false,
+"SlowHashSyncOnly": false,
+"DownloadHash": false
+}
+INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
+INFO  : Building Path1 and Path2 listings
+INFO  : Path1 checking for diffs
+INFO  : - [36mPath1[0m    [35m[33mFile changed: [35mtime (newer)[0m[0m[0m - [36mfile1.txt[0m
+INFO  : Path1:    1 changes: [32m   0 new[0m, [33m   1 modified[0m, [31m   0 deleted[0m
+INFO  : ([33mModified[0m: [36m   1 newer[0m, [34m   0 older[0m)
+INFO  : Path2 checking for diffs
+INFO  : - [34mPath2[0m    [35m[33mFile changed: [35mtime (newer)[0m[0m[0m - [36mfile1.txt[0m
+INFO  : Path2:    1 changes: [32m   0 new[0m, [33m   1 modified[0m, [31m   0 deleted[0m
+INFO  : ([33mModified[0m: [36m   1 newer[0m, [34m   0 older[0m)
+INFO  : Applying changes
+INFO  : Checking potential conflicts...
+ERROR : file1.txt: md5 differ
+NOTICE: {path2String}: 1 differences found
+NOTICE: {path2String}: 1 errors while checking
+INFO  : Finished checking the potential conflicts. 1 differences found
+NOTICE: - [34mWARNING[0m  [35mNew or changed in both paths[0m       - [36mfile1.txt[0m
+INFO  : file1.txt: [32mThe winner is: Path2[0m
+NOTICE: - [36mPath1[0m    [35mRenaming Path1 copy[0m                - [36m{path1/}file1.txt.dinosaur1[0m
+NOTICE: - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file1.txt.dinosaur1[0m
+NOTICE: - [34mPath2[0m    [35mNot renaming Path2 copy, as it was determined the winner[0m - [36m{path2/}file1.txt[0m
+NOTICE: - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}file1.txt[0m
+INFO  : - [34mPath2[0m    [35mDo queued copies to[0m                - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mDo queued copies to[0m                - [36mPath2[0m
+INFO  : Updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
+INFO  : [32mBisync successful[0m
+
+[36m(18)  :[0m [34mtest changed on both paths and NOT identical - file1 (file1R, file1L)[0m
+[36m(19)  :[0m [34mtouch-glob 2002-07-23 {datadir/} file1R.txt[0m
+[36m(20)  :[0m [34mcopy-as {datadir/}file1R.txt {path2/} file1.txt[0m
+[36m(21)  :[0m [34mtouch-glob 2002-08-26 {datadir/} file1L.txt[0m
+[36m(22)  :[0m [34mcopy-as {datadir/}file1L.txt {path1/} file1.txt[0m
+
+[36m(23)  :[0m [34mtest bisync run with --conflict-resolve=larger --conflict-loser=num --conflict-suffix=apple[0m
+
+[36m(24)  :[0m [34mbisync conflict-resolve=larger conflict-loser=num conflict-suffix=apple[0m
+INFO  : [2mSetting --ignore-listing-checksum as neither --checksum nor --compare checksum are set.[0m
+INFO  : Bisyncing with Comparison Settings:
+{
+"Modtime": true,
+"Size": true,
+"Checksum": false,
+"NoSlowHash": false,
+"SlowHashSyncOnly": false,
+"DownloadHash": false
+}
+INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
+INFO  : Building Path1 and Path2 listings
+INFO  : Path1 checking for diffs
+INFO  : - [36mPath1[0m    [35m[32mFile is new[0m[0m               - [36mfile1.txt[0m
+INFO  : Path1:    1 changes: [32m   1 new[0m, [33m   0 modified[0m, [31m   0 deleted[0m
+INFO  : Path2 checking for diffs
+INFO  : - [34mPath2[0m    [35m[32mFile is new[0m[0m               - [36mfile1.txt[0m
+INFO  : Path2:    1 changes: [32m   1 new[0m, [33m   0 modified[0m, [31m   0 deleted[0m
+INFO  : Applying changes
+INFO  : Checking potential conflicts...
+ERROR : file1.txt: md5 differ
+NOTICE: {path2String}: 1 differences found
+NOTICE: {path2String}: 1 errors while checking
+INFO  : Finished checking the potential conflicts. 1 differences found
+NOTICE: - [34mWARNING[0m  [35mNew or changed in both paths[0m       - [36mfile1.txt[0m
+INFO  : file1.txt: Winner cannot be determined as sizes are equal. Path1: 33, Path2: 33, Difference: 0
+INFO  : file1.txt: [31mA winner could not be determined.[0m
+NOTICE: - [36mPath1[0m    [35mRenaming Path1 copy[0m                - [36m{path1/}file1.txt.apple1[0m
+NOTICE: - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file1.txt.apple1[0m
+NOTICE: - [34mPath2[0m    [35mRenaming Path2 copy[0m                - [36m{path2/}file1.txt.apple2[0m
+NOTICE: - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}file1.txt.apple2[0m
+INFO  : - [34mPath2[0m    [35mDo queued copies to[0m                - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mDo queued copies to[0m                - [36mPath2[0m
+INFO  : Updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
+INFO  : [32mBisync successful[0m
+
+[36m(25)  :[0m [34mtest different suffixes[0m
+[36m(26)  :[0m [34mtouch-glob 2003-07-23 {datadir/} file1R.txt[0m
+[36m(27)  :[0m [34mcopy-as {datadir/}file1R.txt {path2/} file1.txt[0m
+[36m(28)  :[0m [34mtouch-glob 2003-07-23 {datadir/} file1L.txt[0m
+[36m(29)  :[0m [34mcopy-as {datadir/}file1L.txt {path1/} file1.txt[0m
+
+[36m(30)  :[0m [34mtest bisync run with --conflict-resolve=older --conflict-loser=num --conflict-suffix=cloud,local[0m
+
+[36m(31)  :[0m [34mbisync conflict-resolve=older conflict-loser=num conflict-suffix=cloud,local[0m
+INFO  : [2mSetting --ignore-listing-checksum as neither --checksum nor --compare checksum are set.[0m
+INFO  : Bisyncing with Comparison Settings:
+{
+"Modtime": true,
+"Size": true,
+"Checksum": false,
+"NoSlowHash": false,
+"SlowHashSyncOnly": false,
+"DownloadHash": false
+}
+INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
+INFO  : Building Path1 and Path2 listings
+INFO  : Path1 checking for diffs
+INFO  : - [36mPath1[0m    [35m[32mFile is new[0m[0m               - [36mfile1.txt[0m
+INFO  : Path1:    1 changes: [32m   1 new[0m, [33m   0 modified[0m, [31m   0 deleted[0m
+INFO  : Path2 checking for diffs
+INFO  : - [34mPath2[0m    [35m[32mFile is new[0m[0m               - [36mfile1.txt[0m
+INFO  : Path2:    1 changes: [32m   1 new[0m, [33m   0 modified[0m, [31m   0 deleted[0m
+INFO  : Applying changes
+INFO  : Checking potential conflicts...
+ERROR : file1.txt: md5 differ
+NOTICE: {path2String}: 1 differences found
+NOTICE: {path2String}: 1 errors while checking
+INFO  : Finished checking the potential conflicts. 1 differences found
+NOTICE: - [34mWARNING[0m  [35mNew or changed in both paths[0m       - [36mfile1.txt[0m
+INFO  : file1.txt: Winner cannot be determined as times are equal. Path1: 2003-07-23 00:00:00 +0000 UTC, Path2: 2003-07-23 00:00:00 +0000 UTC, Difference: 0s
+INFO  : file1.txt: [31mA winner could not be determined.[0m
+NOTICE: - [36mPath1[0m    [35mRenaming Path1 copy[0m                - [36m{path1/}file1.txt.cloud1[0m
+NOTICE: - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file1.txt.cloud1[0m
+NOTICE: - [34mPath2[0m    [35mRenaming Path2 copy[0m                - [36m{path2/}file1.txt.local1[0m
+NOTICE: - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}file1.txt.local1[0m
+INFO  : - [34mPath2[0m    [35mDo queued copies to[0m                - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mDo queued copies to[0m                - [36mPath2[0m
+INFO  : Updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
+INFO  : [32mBisync successful[0m
+
+[36m(32)  :[0m [34mtest legacy[0m
+[36m(33)  :[0m [34mtouch-glob 2004-07-23 {datadir/} file1R.txt[0m
+[36m(34)  :[0m [34mcopy-as {datadir/}file1R.txt {path2/} file1.txt[0m
+[36m(35)  :[0m [34mtouch-glob 2004-07-23 {datadir/} file1L.txt[0m
+[36m(36)  :[0m [34mcopy-as {datadir/}file1L.txt {path1/} file1.txt[0m
+
+[36m(37)  :[0m [34mtest bisync run with --conflict-resolve=none --conflict-loser=pathname --conflict-suffix=.path[0m
+
+[36m(38)  :[0m [34mbisync conflict-resolve=none conflict-loser=pathname conflict-suffix=.path[0m
+INFO  : [2mSetting --ignore-listing-checksum as neither --checksum nor --compare checksum are set.[0m
+INFO  : Bisyncing with Comparison Settings:
+{
+"Modtime": true,
+"Size": true,
+"Checksum": false,
+"NoSlowHash": false,
+"SlowHashSyncOnly": false,
+"DownloadHash": false
+}
+INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
+INFO  : Building Path1 and Path2 listings
+INFO  : Path1 checking for diffs
+INFO  : - [36mPath1[0m    [35m[32mFile is new[0m[0m               - [36mfile1.txt[0m
+INFO  : Path1:    1 changes: [32m   1 new[0m, [33m   0 modified[0m, [31m   0 deleted[0m
+INFO  : Path2 checking for diffs
+INFO  : - [34mPath2[0m    [35m[32mFile is new[0m[0m               - [36mfile1.txt[0m
+INFO  : Path2:    1 changes: [32m   1 new[0m, [33m   0 modified[0m, [31m   0 deleted[0m
+INFO  : Applying changes
+INFO  : Checking potential conflicts...
+ERROR : file1.txt: md5 differ
+NOTICE: {path2String}: 1 differences found
+NOTICE: {path2String}: 1 errors while checking
+INFO  : Finished checking the potential conflicts. 1 differences found
+NOTICE: - [34mWARNING[0m  [35mNew or changed in both paths[0m       - [36mfile1.txt[0m
+NOTICE: - [36mPath1[0m    [35mRenaming Path1 copy[0m                - [36m{path1/}file1.txt..path1[0m
+NOTICE: - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file1.txt..path1[0m
+NOTICE: - [34mPath2[0m    [35mRenaming Path2 copy[0m                - [36m{path2/}file1.txt..path2[0m
+NOTICE: - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}file1.txt..path2[0m
+INFO  : - [34mPath2[0m    [35mDo queued copies to[0m                - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mDo queued copies to[0m                - [36mPath2[0m
+INFO  : Updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
+INFO  : [32mBisync successful[0m
+
+[36m(39)  :[0m [34mtest deletes on both sides with default suffix[0m
+[36m(40)  :[0m [34mtouch-glob 2005-01-02 {datadir/} file1R.txt[0m
+[36m(41)  :[0m [34mcopy-as {datadir/}file1R.txt {path2/} file1.txt[0m
+[36m(42)  :[0m [34mcopy-as {datadir/}file1R.txt {path1/} file2.txt[0m
+[36m(43)  :[0m [34mtouch-glob 2006-03-04 {datadir/} file1L.txt[0m
+[36m(44)  :[0m [34mcopy-as {datadir/}file1L.txt {path1/} file1.txt[0m
+[36m(45)  :[0m [34mcopy-as {datadir/}file1L.txt {path2/} file2.txt[0m
+
+[36m(46)  :[0m [34mtest bisync run with --conflict-resolve=newer --conflict-loser=delete[0m
+[36m(47)  :[0m [34mbisync conflict-resolve=newer conflict-loser=delete[0m
+INFO  : [2mSetting --ignore-listing-checksum as neither --checksum nor --compare checksum are set.[0m
+INFO  : Bisyncing with Comparison Settings:
+{
+"Modtime": true,
+"Size": true,
+"Checksum": false,
+"NoSlowHash": false,
+"SlowHashSyncOnly": false,
+"DownloadHash": false
+}
+INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
+INFO  : Building Path1 and Path2 listings
+INFO  : Path1 checking for diffs
+INFO  : - [36mPath1[0m    [35m[33mFile changed: [35msize (larger)[0m, [35mtime (newer)[0m[0m[0m - [36mfile2.txt[0m
+INFO  : - [36mPath1[0m    [35m[32mFile is new[0m[0m               - [36mfile1.txt[0m
+INFO  : Path1:    2 changes: [32m   1 new[0m, [33m   1 modified[0m, [31m   0 deleted[0m
+INFO  : ([33mModified[0m: [36m   1 newer[0m, [34m   0 older[0m, [36m   1 larger[0m, [34m   0 smaller[0m)
+INFO  : Path2 checking for diffs
+INFO  : - [34mPath2[0m    [35m[33mFile changed: [35msize (larger)[0m, [35mtime (newer)[0m[0m[0m - [36mfile2.txt[0m
+INFO  : - [34mPath2[0m    [35m[32mFile is new[0m[0m               - [36mfile1.txt[0m
+INFO  : Path2:    2 changes: [32m   1 new[0m, [33m   1 modified[0m, [31m   0 deleted[0m
+INFO  : ([33mModified[0m: [36m   1 newer[0m, [34m   0 older[0m, [36m   1 larger[0m, [34m   0 smaller[0m)
+INFO  : Applying changes
+INFO  : Checking potential conflicts...
+ERROR : file2.txt: md5 differ
+ERROR : file1.txt: md5 differ
+NOTICE: {path2String}: 2 differences found
+NOTICE: {path2String}: 2 errors while checking
+INFO  : Finished checking the potential conflicts. 2 differences found
+NOTICE: - [34mWARNING[0m  [35mNew or changed in both paths[0m       - [36mfile1.txt[0m
+INFO  : file1.txt: Path1 is newer. Path1: 2006-03-04 00:00:00 +0000 UTC, Path2: 2005-01-02 00:00:00 +0000 UTC, Difference: 10224h0m0s
+INFO  : file1.txt: [32mThe winner is: Path1[0m
+NOTICE: - [34mPath2[0m    [35mDeleting Path2 copy[0m                - [36m{path2/}file1.txt[0m
+INFO  : - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36mfile1.txt[0m
+NOTICE: - [34mWARNING[0m  [35mNew or changed in both paths[0m       - [36mfile2.txt[0m
+INFO  : file2.txt: Path2 is newer. Path1: 2005-01-02 00:00:00 +0000 UTC, Path2: 2006-03-04 00:00:00 +0000 UTC, Difference: 10224h0m0s
+INFO  : file2.txt: [32mThe winner is: Path2[0m
+NOTICE: - [36mPath1[0m    [35mDeleting Path1 copy[0m                - [36m{path1/}file2.txt[0m
+INFO  : - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36mfile2.txt[0m
+INFO  : - [34mPath2[0m    [35mDo queued copies to[0m                - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mDo queued copies to[0m                - [36mPath2[0m
+INFO  : Updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
+INFO  : [32mBisync successful[0m
diff --git a/cmd/bisync/testdata/test_resolve/initial/RCLONE_TEST b/cmd/bisync/testdata/test_resolve/initial/RCLONE_TEST
new file mode 100644
index 0000000000000..d8ca97c2a4dbe
--- /dev/null
+++ b/cmd/bisync/testdata/test_resolve/initial/RCLONE_TEST
@@ -0,0 +1,1 @@
+This file is used for testing the health of rclone accesses to the local/remote file system.  Do not delete.
diff --git a/cmd/bisync/testdata/test_resolve/initial/file1.txt b/cmd/bisync/testdata/test_resolve/initial/file1.txt
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/cmd/bisync/testdata/test_resolve/initial/file2.txt b/cmd/bisync/testdata/test_resolve/initial/file2.txt
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/cmd/bisync/testdata/test_resolve/modfiles/file1L.txt b/cmd/bisync/testdata/test_resolve/modfiles/file1L.txt
new file mode 100644
index 0000000000000..6906ccb095ef8
--- /dev/null
+++ b/cmd/bisync/testdata/test_resolve/modfiles/file1L.txt
@@ -0,0 +1,1 @@
+This file is NOT identical to 1R
diff --git a/cmd/bisync/testdata/test_resolve/modfiles/file1R.txt b/cmd/bisync/testdata/test_resolve/modfiles/file1R.txt
new file mode 100644
index 0000000000000..e49d06a949b6d
--- /dev/null
+++ b/cmd/bisync/testdata/test_resolve/modfiles/file1R.txt
@@ -0,0 +1,1 @@
+This file is NOT identical to 1L
diff --git a/cmd/bisync/testdata/test_resolve/modfiles/file2.txt b/cmd/bisync/testdata/test_resolve/modfiles/file2.txt
new file mode 100644
index 0000000000000..2ee5fc1eea273
--- /dev/null
+++ b/cmd/bisync/testdata/test_resolve/modfiles/file2.txt
@@ -0,0 +1,1 @@
+This file is identical on both sides
diff --git a/cmd/bisync/testdata/test_resolve/scenario.txt b/cmd/bisync/testdata/test_resolve/scenario.txt
new file mode 100644
index 0000000000000..1e72757f74685
--- /dev/null
+++ b/cmd/bisync/testdata/test_resolve/scenario.txt
@@ -0,0 +1,67 @@
+test resolve
+# Check conflict-resolution options
+# - Changed on Path2 and on Path1, and NOT identical       file1 (file1r, file1l)
+
+test initial bisync
+bisync resync
+
+test changed on both paths and NOT identical - file1 (file1R, file1L)
+touch-glob 2001-01-02 {datadir/} file1R.txt
+copy-as {datadir/}file1R.txt {path2/} file1.txt
+touch-glob 2001-03-04 {datadir/} file1L.txt
+copy-as {datadir/}file1L.txt {path1/} file1.txt
+
+test bisync run with --conflict-resolve=newer --conflict-loser=delete --conflict-suffix=potato
+# result should be "file1.txt", "file1.txt" (no potato)
+bisync conflict-resolve=newer conflict-loser=delete conflict-suffix=potato
+
+test changed on both paths and NOT identical - file1 (file1R, file1L)
+touch-glob 2001-07-23 {datadir/} file1R.txt
+copy-as {datadir/}file1R.txt {path2/} file1.txt
+touch-glob 2001-08-26 {datadir/} file1L.txt
+copy-as {datadir/}file1L.txt {path1/} file1.txt
+
+test bisync run with --conflict-resolve=path2 --conflict-loser=num --conflict-suffix=dinosaur
+# result should be "file1.txt.dinosaur1", "file1.txt"
+bisync conflict-resolve=path2 conflict-loser=num conflict-suffix=dinosaur
+
+test changed on both paths and NOT identical - file1 (file1R, file1L)
+touch-glob 2002-07-23 {datadir/} file1R.txt
+copy-as {datadir/}file1R.txt {path2/} file1.txt
+touch-glob 2002-08-26 {datadir/} file1L.txt
+copy-as {datadir/}file1L.txt {path1/} file1.txt
+
+test bisync run with --conflict-resolve=larger --conflict-loser=num --conflict-suffix=apple
+# result should be no winner -- "file1.txt.apple1", "file1.txt.apple2"
+bisync conflict-resolve=larger conflict-loser=num conflict-suffix=apple
+
+test different suffixes
+touch-glob 2003-07-23 {datadir/} file1R.txt
+copy-as {datadir/}file1R.txt {path2/} file1.txt
+touch-glob 2003-07-23 {datadir/} file1L.txt
+copy-as {datadir/}file1L.txt {path1/} file1.txt
+
+test bisync run with --conflict-resolve=older --conflict-loser=num --conflict-suffix=cloud,local
+# result should be no winner -- "file1.txt.cloud1", "file1.txt.local1"
+bisync conflict-resolve=older conflict-loser=num conflict-suffix=cloud,local
+
+test legacy
+touch-glob 2004-07-23 {datadir/} file1R.txt
+copy-as {datadir/}file1R.txt {path2/} file1.txt
+touch-glob 2004-07-23 {datadir/} file1L.txt
+copy-as {datadir/}file1L.txt {path1/} file1.txt
+
+test bisync run with --conflict-resolve=none --conflict-loser=pathname --conflict-suffix=.path
+# result should be no winner -- "file1.txt..path1", "file1.txt..path2"
+bisync conflict-resolve=none conflict-loser=pathname conflict-suffix=.path
+
+test deletes on both sides with default suffix
+touch-glob 2005-01-02 {datadir/} file1R.txt
+copy-as {datadir/}file1R.txt {path2/} file1.txt
+copy-as {datadir/}file1R.txt {path1/} file2.txt
+touch-glob 2006-03-04 {datadir/} file1L.txt
+copy-as {datadir/}file1L.txt {path1/} file1.txt
+copy-as {datadir/}file1L.txt {path2/} file2.txt
+
+test bisync run with --conflict-resolve=newer --conflict-loser=delete
+bisync conflict-resolve=newer conflict-loser=delete
\ No newline at end of file
diff --git a/cmd/bisync/testdata/test_resync/golden/test.log b/cmd/bisync/testdata/test_resync/golden/test.log
index 9c7164f85044f..f9488a672573b 100644
--- a/cmd/bisync/testdata/test_resync/golden/test.log
+++ b/cmd/bisync/testdata/test_resync/golden/test.log
@@ -15,10 +15,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 [36m(05)  :[0m [34mmove-listings empty-path1[0m
 
@@ -36,10 +37,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 [36m(09)  :[0m [34mmove-listings empty-path2[0m
 
@@ -83,10 +85,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 [36m(31)  :[0m [34mcopy-listings mixed-diffs[0m
 
diff --git a/cmd/bisync/testdata/test_resync_modes/golden/_testdir_path1.._testdir_path2.path1.lst b/cmd/bisync/testdata/test_resync_modes/golden/_testdir_path1.._testdir_path2.path1.lst
new file mode 100644
index 0000000000000..b0d6803885498
--- /dev/null
+++ b/cmd/bisync/testdata/test_resync_modes/golden/_testdir_path1.._testdir_path2.path1.lst
@@ -0,0 +1,4 @@
+# bisync listing v1 from test
+-      109 - - 2000-01-01T00:00:00.000000000+0000 "RCLONE_TEST"
+-       42 - - 2022-02-22T00:00:00.000000000+0000 "file1.txt"
+-       33 - - 2022-02-22T00:00:00.000000000+0000 "file2.txt"
diff --git a/cmd/bisync/testdata/test_resync_modes/golden/_testdir_path1.._testdir_path2.path1.lst-new b/cmd/bisync/testdata/test_resync_modes/golden/_testdir_path1.._testdir_path2.path1.lst-new
new file mode 100644
index 0000000000000..4f98654dca5ce
--- /dev/null
+++ b/cmd/bisync/testdata/test_resync_modes/golden/_testdir_path1.._testdir_path2.path1.lst-new
@@ -0,0 +1,1 @@
+# bisync listing v1 from test
diff --git a/cmd/bisync/testdata/test_resync_modes/golden/_testdir_path1.._testdir_path2.path1.lst-old b/cmd/bisync/testdata/test_resync_modes/golden/_testdir_path1.._testdir_path2.path1.lst-old
new file mode 100644
index 0000000000000..75d37f056e61c
--- /dev/null
+++ b/cmd/bisync/testdata/test_resync_modes/golden/_testdir_path1.._testdir_path2.path1.lst-old
@@ -0,0 +1,4 @@
+# bisync listing v1 from test
+-      109 - - 2000-01-01T00:00:00.000000000+0000 "RCLONE_TEST"
+-       33 - - 2006-03-04T00:00:00.000000000+0000 "file1.txt"
+-       42 - - 2005-01-02T00:00:00.000000000+0000 "file2.txt"
diff --git a/cmd/bisync/testdata/test_resync_modes/golden/_testdir_path1.._testdir_path2.path2.lst b/cmd/bisync/testdata/test_resync_modes/golden/_testdir_path1.._testdir_path2.path2.lst
new file mode 100644
index 0000000000000..b0d6803885498
--- /dev/null
+++ b/cmd/bisync/testdata/test_resync_modes/golden/_testdir_path1.._testdir_path2.path2.lst
@@ -0,0 +1,4 @@
+# bisync listing v1 from test
+-      109 - - 2000-01-01T00:00:00.000000000+0000 "RCLONE_TEST"
+-       42 - - 2022-02-22T00:00:00.000000000+0000 "file1.txt"
+-       33 - - 2022-02-22T00:00:00.000000000+0000 "file2.txt"
diff --git a/cmd/bisync/testdata/test_resync_modes/golden/_testdir_path1.._testdir_path2.path2.lst-new b/cmd/bisync/testdata/test_resync_modes/golden/_testdir_path1.._testdir_path2.path2.lst-new
new file mode 100644
index 0000000000000..4f98654dca5ce
--- /dev/null
+++ b/cmd/bisync/testdata/test_resync_modes/golden/_testdir_path1.._testdir_path2.path2.lst-new
@@ -0,0 +1,1 @@
+# bisync listing v1 from test
diff --git a/cmd/bisync/testdata/test_resync_modes/golden/_testdir_path1.._testdir_path2.path2.lst-old b/cmd/bisync/testdata/test_resync_modes/golden/_testdir_path1.._testdir_path2.path2.lst-old
new file mode 100644
index 0000000000000..75d37f056e61c
--- /dev/null
+++ b/cmd/bisync/testdata/test_resync_modes/golden/_testdir_path1.._testdir_path2.path2.lst-old
@@ -0,0 +1,4 @@
+# bisync listing v1 from test
+-      109 - - 2000-01-01T00:00:00.000000000+0000 "RCLONE_TEST"
+-       33 - - 2006-03-04T00:00:00.000000000+0000 "file1.txt"
+-       42 - - 2005-01-02T00:00:00.000000000+0000 "file2.txt"
diff --git a/cmd/bisync/testdata/test_resync_modes/golden/test.log b/cmd/bisync/testdata/test_resync_modes/golden/test.log
new file mode 100644
index 0000000000000..017822aa2d873
--- /dev/null
+++ b/cmd/bisync/testdata/test_resync_modes/golden/test.log
@@ -0,0 +1,192 @@
+[36m(01)  :[0m [34mtest resync-mode[0m
+
+
+[36m(02)  :[0m [34mtest changed on both paths and NOT identical - file1 (file1R, file1L)[0m
+[36m(03)  :[0m [34mtouch-glob 2001-01-02 {datadir/} file1R.txt[0m
+[36m(04)  :[0m [34mcopy-as {datadir/}file1R.txt {path2/} file1.txt[0m
+[36m(05)  :[0m [34mtouch-glob 2001-03-04 {datadir/} file1L.txt[0m
+[36m(06)  :[0m [34mcopy-as {datadir/}file1L.txt {path1/} file1.txt[0m
+
+[36m(07)  :[0m [34mtest bisync run with --resync-mode=newer[0m
+[36m(08)  :[0m [34mbisync resync resync-mode=newer[0m
+INFO  : [2mSetting --ignore-listing-checksum as neither --checksum nor --compare checksum are set.[0m
+INFO  : Bisyncing with Comparison Settings:
+{
+"Modtime": true,
+"Size": true,
+"Checksum": false,
+"NoSlowHash": false,
+"SlowHashSyncOnly": false,
+"DownloadHash": false
+}
+INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
+INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
+INFO  : [32mBisync successful[0m
+
+[36m(09)  :[0m [34mtest changed on both paths and NOT identical - file1 (file1R, file1L)[0m
+[36m(10)  :[0m [34mtouch-glob 2001-07-23 {datadir/} file1R.txt[0m
+[36m(11)  :[0m [34mcopy-as {datadir/}file1R.txt {path2/} file1.txt[0m
+[36m(12)  :[0m [34mtouch-glob 2001-08-26 {datadir/} file1L.txt[0m
+[36m(13)  :[0m [34mcopy-as {datadir/}file1L.txt {path1/} file1.txt[0m
+
+[36m(14)  :[0m [34mtest bisync run with --resync-mode=path2[0m
+[36m(15)  :[0m [34mbisync resync resync-mode=path2[0m
+INFO  : [2mSetting --ignore-listing-checksum as neither --checksum nor --compare checksum are set.[0m
+INFO  : Bisyncing with Comparison Settings:
+{
+"Modtime": true,
+"Size": true,
+"Checksum": false,
+"NoSlowHash": false,
+"SlowHashSyncOnly": false,
+"DownloadHash": false
+}
+INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
+INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
+INFO  : [32mBisync successful[0m
+
+[36m(16)  :[0m [34mtest changed on both paths and NOT identical - file1 (file1R, file1L)[0m
+[36m(17)  :[0m [34mtouch-glob 2002-07-23 {datadir/} file1R.txt[0m
+[36m(18)  :[0m [34mcopy-as {datadir/}file1R.txt {path2/} file1.txt[0m
+[36m(19)  :[0m [34mtouch-glob 2002-08-26 {datadir/} file1L.txt[0m
+[36m(20)  :[0m [34mcopy-as {datadir/}file1L.txt {path1/} file1.txt[0m
+
+[36m(21)  :[0m [34mtest bisync run with --resync-mode=larger[0m
+[36m(22)  :[0m [34mbisync resync resync-mode=larger[0m
+INFO  : [2mSetting --ignore-listing-checksum as neither --checksum nor --compare checksum are set.[0m
+INFO  : Bisyncing with Comparison Settings:
+{
+"Modtime": true,
+"Size": true,
+"Checksum": false,
+"NoSlowHash": false,
+"SlowHashSyncOnly": false,
+"DownloadHash": false
+}
+INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : file1.txt: Path2 is larger. Path1: 33, Path2: 42, Difference: 9
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
+INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
+INFO  : [32mBisync successful[0m
+
+[36m(23)  :[0m [34mtest changed on both paths and NOT identical - file1 (file1R, file1L)[0m
+[36m(24)  :[0m [34mtouch-glob 2003-07-23 {datadir/} file1R.txt[0m
+[36m(25)  :[0m [34mcopy-as {datadir/}file1R.txt {path2/} file1.txt[0m
+[36m(26)  :[0m [34mtouch-glob 2003-09-04 {datadir/} file1L.txt[0m
+[36m(27)  :[0m [34mcopy-as {datadir/}file1L.txt {path1/} file1.txt[0m
+
+[36m(28)  :[0m [34mtest bisync run with --resync-mode=older[0m
+[36m(29)  :[0m [34mbisync resync resync-mode=older[0m
+INFO  : [2mSetting --ignore-listing-checksum as neither --checksum nor --compare checksum are set.[0m
+INFO  : Bisyncing with Comparison Settings:
+{
+"Modtime": true,
+"Size": true,
+"Checksum": false,
+"NoSlowHash": false,
+"SlowHashSyncOnly": false,
+"DownloadHash": false
+}
+INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : file1.txt: Path2 is older. Path1: 2003-09-03 20:00:00 -0400 EDT, Path2: 2003-07-22 20:00:00 -0400 EDT, Difference: 1032h0m0s
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
+INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
+INFO  : [32mBisync successful[0m
+
+[36m(30)  :[0m [34mtest changed on both paths and NOT identical - file1 (file1R, file1L)[0m
+[36m(31)  :[0m [34mtouch-glob 2004-07-23 {datadir/} file1R.txt[0m
+[36m(32)  :[0m [34mcopy-as {datadir/}file1R.txt {path2/} file1.txt[0m
+[36m(33)  :[0m [34mtouch-glob 2004-07-23 {datadir/} file1L.txt[0m
+[36m(34)  :[0m [34mcopy-as {datadir/}file1L.txt {path1/} file1.txt[0m
+
+[36m(35)  :[0m [34mtest bisync run with --resync-mode=smaller[0m
+[36m(36)  :[0m [34mbisync resync resync-mode=smaller[0m
+INFO  : [2mSetting --ignore-listing-checksum as neither --checksum nor --compare checksum are set.[0m
+INFO  : Bisyncing with Comparison Settings:
+{
+"Modtime": true,
+"Size": true,
+"Checksum": false,
+"NoSlowHash": false,
+"SlowHashSyncOnly": false,
+"DownloadHash": false
+}
+INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : file1.txt: Path1 is smaller. Path1: 33, Path2: 42, Difference: 9
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
+INFO  : file1.txt: Path1 is smaller. Path1: 33, Path2: 42, Difference: 9
+INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
+INFO  : [32mBisync successful[0m
+
+[36m(37)  :[0m [34mtest changed on both paths and NOT identical - file1 (file1R, file1L)[0m
+[36m(38)  :[0m [34mtouch-glob 2005-01-02 {datadir/} file1R.txt[0m
+[36m(39)  :[0m [34mcopy-as {datadir/}file1R.txt {path2/} file1.txt[0m
+[36m(40)  :[0m [34mcopy-as {datadir/}file1R.txt {path1/} file2.txt[0m
+[36m(41)  :[0m [34mtouch-glob 2006-03-04 {datadir/} file1L.txt[0m
+[36m(42)  :[0m [34mcopy-as {datadir/}file1L.txt {path1/} file1.txt[0m
+[36m(43)  :[0m [34mcopy-as {datadir/}file1L.txt {path2/} file2.txt[0m
+
+[36m(44)  :[0m [34mtest bisync run with --resync-mode=path1[0m
+[36m(45)  :[0m [34mbisync resync resync-mode=path1[0m
+INFO  : [2mSetting --ignore-listing-checksum as neither --checksum nor --compare checksum are set.[0m
+INFO  : Bisyncing with Comparison Settings:
+{
+"Modtime": true,
+"Size": true,
+"Checksum": false,
+"NoSlowHash": false,
+"SlowHashSyncOnly": false,
+"DownloadHash": false
+}
+INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
+INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
+INFO  : [32mBisync successful[0m
+
+[36m(46)  :[0m [34mtest no winner[0m
+[36m(47)  :[0m [34mtouch-glob 2022-02-22 {datadir/} file1R.txt[0m
+[36m(48)  :[0m [34mcopy-as {datadir/}file1R.txt {path2/} file1.txt[0m
+[36m(49)  :[0m [34mcopy-as {datadir/}file1R.txt {path1/} file2.txt[0m
+[36m(50)  :[0m [34mtouch-glob 2022-02-22 {datadir/} file1L.txt[0m
+[36m(51)  :[0m [34mcopy-as {datadir/}file1L.txt {path1/} file1.txt[0m
+[36m(52)  :[0m [34mcopy-as {datadir/}file1L.txt {path2/} file2.txt[0m
+
+[36m(53)  :[0m [34mtest bisync run with --resync-mode=newer[0m
+[36m(54)  :[0m [34mbisync resync resync-mode=newer[0m
+INFO  : [2mSetting --ignore-listing-checksum as neither --checksum nor --compare checksum are set.[0m
+INFO  : Bisyncing with Comparison Settings:
+{
+"Modtime": true,
+"Size": true,
+"Checksum": false,
+"NoSlowHash": false,
+"SlowHashSyncOnly": false,
+"DownloadHash": false
+}
+INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
+INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
+INFO  : [32mBisync successful[0m
diff --git a/cmd/bisync/testdata/test_resync_modes/initial/RCLONE_TEST b/cmd/bisync/testdata/test_resync_modes/initial/RCLONE_TEST
new file mode 100644
index 0000000000000..d8ca97c2a4dbe
--- /dev/null
+++ b/cmd/bisync/testdata/test_resync_modes/initial/RCLONE_TEST
@@ -0,0 +1,1 @@
+This file is used for testing the health of rclone accesses to the local/remote file system.  Do not delete.
diff --git a/cmd/bisync/testdata/test_resync_modes/initial/file1.txt b/cmd/bisync/testdata/test_resync_modes/initial/file1.txt
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/cmd/bisync/testdata/test_resync_modes/initial/file2.txt b/cmd/bisync/testdata/test_resync_modes/initial/file2.txt
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/cmd/bisync/testdata/test_resync_modes/modfiles/file1L.txt b/cmd/bisync/testdata/test_resync_modes/modfiles/file1L.txt
new file mode 100644
index 0000000000000..6906ccb095ef8
--- /dev/null
+++ b/cmd/bisync/testdata/test_resync_modes/modfiles/file1L.txt
@@ -0,0 +1,1 @@
+This file is NOT identical to 1R
diff --git a/cmd/bisync/testdata/test_resync_modes/modfiles/file1R.txt b/cmd/bisync/testdata/test_resync_modes/modfiles/file1R.txt
new file mode 100644
index 0000000000000..1e3eb3f7792ce
--- /dev/null
+++ b/cmd/bisync/testdata/test_resync_modes/modfiles/file1R.txt
@@ -0,0 +1,1 @@
+This file is NOT identical to 1L (LARGER)
diff --git a/cmd/bisync/testdata/test_resync_modes/modfiles/file2.txt b/cmd/bisync/testdata/test_resync_modes/modfiles/file2.txt
new file mode 100644
index 0000000000000..2ee5fc1eea273
--- /dev/null
+++ b/cmd/bisync/testdata/test_resync_modes/modfiles/file2.txt
@@ -0,0 +1,1 @@
+This file is identical on both sides
diff --git a/cmd/bisync/testdata/test_resync_modes/scenario.txt b/cmd/bisync/testdata/test_resync_modes/scenario.txt
new file mode 100644
index 0000000000000..51ca567fc73cf
--- /dev/null
+++ b/cmd/bisync/testdata/test_resync_modes/scenario.txt
@@ -0,0 +1,70 @@
+test resync-mode
+# Check conflict-resolution options during resync
+# - Changed on Path2 and on Path1, and NOT identical       file1 (file1r, file1l)
+
+test changed on both paths and NOT identical - file1 (file1R, file1L)
+touch-glob 2001-01-02 {datadir/} file1R.txt
+copy-as {datadir/}file1R.txt {path2/} file1.txt
+touch-glob 2001-03-04 {datadir/} file1L.txt
+copy-as {datadir/}file1L.txt {path1/} file1.txt
+
+test bisync run with --resync-mode=newer
+bisync resync resync-mode=newer
+
+test changed on both paths and NOT identical - file1 (file1R, file1L)
+touch-glob 2001-07-23 {datadir/} file1R.txt
+copy-as {datadir/}file1R.txt {path2/} file1.txt
+touch-glob 2001-08-26 {datadir/} file1L.txt
+copy-as {datadir/}file1L.txt {path1/} file1.txt
+
+test bisync run with --resync-mode=path2
+bisync resync resync-mode=path2
+
+test changed on both paths and NOT identical - file1 (file1R, file1L)
+touch-glob 2002-07-23 {datadir/} file1R.txt
+copy-as {datadir/}file1R.txt {path2/} file1.txt
+touch-glob 2002-08-26 {datadir/} file1L.txt
+copy-as {datadir/}file1L.txt {path1/} file1.txt
+
+test bisync run with --resync-mode=larger
+bisync resync resync-mode=larger
+
+test changed on both paths and NOT identical - file1 (file1R, file1L)
+touch-glob 2003-07-23 {datadir/} file1R.txt
+copy-as {datadir/}file1R.txt {path2/} file1.txt
+touch-glob 2003-09-04 {datadir/} file1L.txt
+copy-as {datadir/}file1L.txt {path1/} file1.txt
+
+test bisync run with --resync-mode=older
+bisync resync resync-mode=older
+
+test changed on both paths and NOT identical - file1 (file1R, file1L)
+touch-glob 2004-07-23 {datadir/} file1R.txt
+copy-as {datadir/}file1R.txt {path2/} file1.txt
+touch-glob 2004-07-23 {datadir/} file1L.txt
+copy-as {datadir/}file1L.txt {path1/} file1.txt
+
+test bisync run with --resync-mode=smaller
+bisync resync resync-mode=smaller
+
+test changed on both paths and NOT identical - file1 (file1R, file1L)
+touch-glob 2005-01-02 {datadir/} file1R.txt
+copy-as {datadir/}file1R.txt {path2/} file1.txt
+copy-as {datadir/}file1R.txt {path1/} file2.txt
+touch-glob 2006-03-04 {datadir/} file1L.txt
+copy-as {datadir/}file1L.txt {path1/} file1.txt
+copy-as {datadir/}file1L.txt {path2/} file2.txt
+
+test bisync run with --resync-mode=path1
+bisync resync resync-mode=path1
+
+test no winner
+touch-glob 2022-02-22 {datadir/} file1R.txt
+copy-as {datadir/}file1R.txt {path2/} file1.txt
+copy-as {datadir/}file1R.txt {path1/} file2.txt
+touch-glob 2022-02-22 {datadir/} file1L.txt
+copy-as {datadir/}file1L.txt {path1/} file1.txt
+copy-as {datadir/}file1L.txt {path2/} file2.txt
+
+test bisync run with --resync-mode=newer
+bisync resync resync-mode=newer
\ No newline at end of file
diff --git a/cmd/bisync/testdata/test_rmdirs/golden/test.log b/cmd/bisync/testdata/test_rmdirs/golden/test.log
index b5e47b879838b..4e6763801b0c8 100644
--- a/cmd/bisync/testdata/test_rmdirs/golden/test.log
+++ b/cmd/bisync/testdata/test_rmdirs/golden/test.log
@@ -14,10 +14,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 
 [36m(04)  :[0m [34mtest 1. delete path1 subdir file[0m
diff --git a/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.copy1to2.que b/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.copy1to2.que
index cc3b08914b8cd..185e98b185620 100644
--- a/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.copy1to2.que
+++ b/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.copy1to2.que
@@ -1,1 +1,1 @@
-"file5.txt..path1"
+"file5.txt.conflict5"
diff --git a/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.copy2to1.que b/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.copy2to1.que
index 8457cd213488e..68562bb614422 100644
--- a/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.copy2to1.que
+++ b/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.copy2to1.que
@@ -1,1 +1,1 @@
-"file5.txt..path2"
+"file5.txt.conflict6"
diff --git a/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path1.lst b/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path1.lst
index 1a9f106fc6d42..5c8d754bb531a 100644
--- a/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path1.lst
+++ b/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path1.lst
@@ -46,8 +46,12 @@
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file47.txt"
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file48.txt"
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file49.txt"
--       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1"
--       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2"
+-       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1"
+-       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2"
+-       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict3"
+-       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict4"
+-       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict5"
+-       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict6"
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file51.txt"
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file52.txt"
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file53.txt"
diff --git a/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path1.lst-new b/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path1.lst-new
index 9adf42243ff60..18bfbb3d0da82 100644
--- a/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path1.lst-new
+++ b/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path1.lst-new
@@ -47,8 +47,10 @@
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file48.txt"
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file49.txt"
 -       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt"
--       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1"
--       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2"
+-       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1"
+-       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2"
+-       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict3"
+-       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict4"
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file51.txt"
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file52.txt"
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file53.txt"
diff --git a/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path1.lst-old b/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path1.lst-old
index 1a9f106fc6d42..8190c030049c6 100644
--- a/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path1.lst-old
+++ b/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path1.lst-old
@@ -46,8 +46,10 @@
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file47.txt"
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file48.txt"
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file49.txt"
--       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1"
--       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2"
+-       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1"
+-       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2"
+-       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict3"
+-       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict4"
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file51.txt"
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file52.txt"
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file53.txt"
diff --git a/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path2.lst b/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path2.lst
index 1a9f106fc6d42..5c8d754bb531a 100644
--- a/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path2.lst
+++ b/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path2.lst
@@ -46,8 +46,12 @@
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file47.txt"
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file48.txt"
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file49.txt"
--       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1"
--       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2"
+-       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1"
+-       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2"
+-       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict3"
+-       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict4"
+-       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict5"
+-       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict6"
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file51.txt"
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file52.txt"
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file53.txt"
diff --git a/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path2.lst-new b/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path2.lst-new
index a8ce37fdca5de..968eeeae6349e 100644
--- a/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path2.lst-new
+++ b/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path2.lst-new
@@ -47,8 +47,10 @@
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file48.txt"
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file49.txt"
 -       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt"
--       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1"
--       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2"
+-       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1"
+-       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2"
+-       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict3"
+-       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict4"
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file51.txt"
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file52.txt"
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file53.txt"
diff --git a/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path2.lst-old b/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path2.lst-old
index 1a9f106fc6d42..8190c030049c6 100644
--- a/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path2.lst-old
+++ b/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path2.lst-old
@@ -46,8 +46,10 @@
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file47.txt"
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file48.txt"
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file49.txt"
--       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1"
--       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2"
+-       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1"
+-       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2"
+-       39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict3"
+-       39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict4"
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file51.txt"
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file52.txt"
 -       19 - - 2023-08-26T00:00:00.000000000+0000 "file53.txt"
diff --git a/cmd/bisync/testdata/test_volatile/golden/test.log b/cmd/bisync/testdata/test_volatile/golden/test.log
index 7facb598057d3..ab3003a766a79 100644
--- a/cmd/bisync/testdata/test_volatile/golden/test.log
+++ b/cmd/bisync/testdata/test_volatile/golden/test.log
@@ -13,10 +13,11 @@ INFO  : Bisyncing with Comparison Settings:
 "DownloadHash": false
 }
 INFO  : Synching Path1 "{path1/}" with Path2 "{path2/}"
-INFO  : Copying unique Path2 files to Path1
-INFO  : - [34mPath2[0m    [35mResync is copying UNIQUE files to[0m  - [36mPath1[0m
-INFO  : - [36mPath1[0m    [35mResync is copying UNIQUE OR DIFFERING files to[0m - [36mPath2[0m
+INFO  : Copying Path2 files to Path1
+INFO  : - [34mPath2[0m    [35mResync is copying files to[0m         - [36mPath1[0m
+INFO  : - [36mPath1[0m    [35mResync is copying files to[0m         - [36mPath2[0m
 INFO  : Resync updating listings
+INFO  : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}"
 INFO  : [32mBisync successful[0m
 
 [36m(04)  :[0m [34mtest changed on both paths - file5 (file5R, file5L)[0m
@@ -56,10 +57,10 @@ NOTICE: {path2String}: 1 differences found
 NOTICE: {path2String}: 1 errors while checking
 INFO  : Finished checking the potential conflicts. 1 differences found
 NOTICE: - [34mWARNING[0m  [35mNew or changed in both paths[0m       - [36mfile5.txt[0m
-NOTICE: - [36mPath1[0m    [35mRenaming Path1 copy[0m                - [36m{path1/}file5.txt..path1[0m
-NOTICE: - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file5.txt..path1[0m
-NOTICE: - [34mPath2[0m    [35mRenaming Path2 copy[0m                - [36m{path2/}file5.txt..path2[0m
-NOTICE: - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}file5.txt..path2[0m
+NOTICE: - [36mPath1[0m    [35mRenaming Path1 copy[0m                - [36m{path1/}file5.txt.conflict1[0m
+NOTICE: - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file5.txt.conflict1[0m
+NOTICE: - [34mPath2[0m    [35mRenaming Path2 copy[0m                - [36m{path2/}file5.txt.conflict2[0m
+NOTICE: - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}file5.txt.conflict2[0m
 INFO  : - [34mPath2[0m    [35mDo queued copies to[0m                - [36mPath1[0m
 INFO  : - [36mPath1[0m    [35mDo queued copies to[0m                - [36mPath2[0m
 INFO  : Updating listings
@@ -201,10 +202,10 @@ NOTICE: {path2String}: 1 errors while checking
 INFO  : Finished checking the potential conflicts. 1 differences found
 INFO  : - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file100.txt[0m
 NOTICE: - [34mWARNING[0m  [35mNew or changed in both paths[0m       - [36mfile5.txt[0m
-NOTICE: - [36mPath1[0m    [35mRenaming Path1 copy[0m                - [36m{path1/}file5.txt..path1[0m
-NOTICE: - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file5.txt..path1[0m
-NOTICE: - [34mPath2[0m    [35mRenaming Path2 copy[0m                - [36m{path2/}file5.txt..path2[0m
-NOTICE: - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}file5.txt..path2[0m
+NOTICE: - [36mPath1[0m    [35mRenaming Path1 copy[0m                - [36m{path1/}file5.txt.conflict3[0m
+NOTICE: - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file5.txt.conflict3[0m
+NOTICE: - [34mPath2[0m    [35mRenaming Path2 copy[0m                - [36m{path2/}file5.txt.conflict4[0m
+NOTICE: - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}file5.txt.conflict4[0m
 INFO  : - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file51.txt[0m
 INFO  : - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file52.txt[0m
 INFO  : - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file53.txt[0m
@@ -343,10 +344,10 @@ NOTICE: {path2String}: 1 differences found
 NOTICE: {path2String}: 1 errors while checking
 INFO  : Finished checking the potential conflicts. 1 differences found
 NOTICE: - [34mWARNING[0m  [35mNew or changed in both paths[0m       - [36mfile5.txt[0m
-NOTICE: - [36mPath1[0m    [35mRenaming Path1 copy[0m                - [36m{path1/}file5.txt..path1[0m
-NOTICE: - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file5.txt..path1[0m
-NOTICE: - [34mPath2[0m    [35mRenaming Path2 copy[0m                - [36m{path2/}file5.txt..path2[0m
-NOTICE: - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}file5.txt..path2[0m
+NOTICE: - [36mPath1[0m    [35mRenaming Path1 copy[0m                - [36m{path1/}file5.txt.conflict5[0m
+NOTICE: - [36mPath1[0m    [35m[32mQueue copy to[0m Path2[0m       - [36m{path2/}file5.txt.conflict5[0m
+NOTICE: - [34mPath2[0m    [35mRenaming Path2 copy[0m                - [36m{path2/}file5.txt.conflict6[0m
+NOTICE: - [34mPath2[0m    [35m[32mQueue copy to[0m Path1[0m       - [36m{path1/}file5.txt.conflict6[0m
 INFO  : - [34mPath2[0m    [35mDo queued copies to[0m                - [36mPath1[0m
 INFO  : - [36mPath1[0m    [35mDo queued copies to[0m                - [36mPath2[0m
 INFO  : Updating listings