Introduction⌗

A Git Patch is essentially a text file that records the differences in code (i.e., additions, deletions, or modifications). It is usually generated by git diff or created as a patch file with commit information using git format-patch. Patch files can be applied to a code repository using git apply or other tools.

Common Commands⌗

diff⌗

Generate the differences between the working directory, the staging area, or commits.

git diff > diff.patch

This will save the uncommitted changes as a patch file.

format-patch⌗

Generate patch files based on the commit history, usually including commit information such as author, date, and commit message.

git format-patch -1 HEAD

Generate a patch file for the most recent commit (e.g., 0001-my-commit-message.patch).

apply⌗

Apply the patch file to the current working directory.

git apply diff.patch

Apply the patch without creating a commit.

am⌗

Apply the patch generated by git format-patch and directly create the corresponding commit.

git am 0001-my-commit-message.patch

Usage Scenarios⌗

Code sharing without direct push access⌗

When you cannot directly push code to the target repository (for example, in open-source projects), you can use git format-patch to generate patch files, share them via email or files, and the recipient can apply them using git am.

Temporary Fixes or Debugging⌗

Quickly apply patches in production or testing environments without fully pulling the branch. For example, generate a patch using git diff, transfer it to the server, and apply it with git apply.

Code Review⌗

Send code changes as patches to team members to facilitate reviewing specific modifications. For example:

git format-patch origin/master generates a series of patch files for others to review.

Migrating Small-Scale Changes⌗

When you want to migrate only part of the changes from one branch or repository to another without merging the entire branch, you can use patches. For example, after completing a feature in a development branch, extract the changes with git diff and apply them to the main branch.

Backup Uncommitted Changes⌗

Before switching branches, uncommitted changes can be saved using git diff > patchfile.patch and later restored with git apply.

Summary⌗

I came across Git Patch recently because I was looking into the Anytype project. Since this project’s self-hosted setup depends on too many services, the architecture became overly complex. As a result, some community members modified the source code of the official any-sync project to reduce project dependencies.

At first, I thought this developer had simply forked the any-sync project and maintained their own code branch. But after checking their project, I realized they used Git Patch to make partial adjustments to the code.

If you’re interested, you can take a look at this project: hellodword/anytype-all.

patches/any-sync-coordinator-v0.3.25.patch:

diff --git a/accountlimit/accountlimit.go b/accountlimit/accountlimit.go
index 668b66b..049a0e7 100644
--- a/accountlimit/accountlimit.go
+++ b/accountlimit/accountlimit.go
@@ -12,7 +12,7 @@ import (
 	"github.com/anyproto/any-sync/net/pool"
 	"github.com/anyproto/any-sync/nodeconf"
 	"go.mongodb.org/mongo-driver/bson"
-	"go.mongodb.org/mongo-driver/mongo"
+	mongo "github.com/256dpi/lungo"
 	"go.mongodb.org/mongo-driver/mongo/options"
 	"storj.io/drpc"
 
@@ -59,7 +59,7 @@ type AccountLimit interface {
 type accountLimit struct {
 	pool          pool.Pool
 	nodeConf      nodeconf.Service
-	coll          *mongo.Collection
+	coll          mongo.ICollection
 	spaceStatus   spacestatus.SpaceStatus
 	defaultLimits SpaceLimits
 }
diff --git a/coordinatorlog/coordinatorlog.go b/coordinatorlog/coordinatorlog.go
index 2975a0f..81e87b9 100644
--- a/coordinatorlog/coordinatorlog.go
+++ b/coordinatorlog/coordinatorlog.go
@@ -6,7 +6,7 @@ import (
 	"time"
 
 	"github.com/anyproto/any-sync/app"
-	"go.mongodb.org/mongo-driver/mongo"
+	mongo "github.com/256dpi/lungo"
 
 	"github.com/anyproto/any-sync-coordinator/db"
 )
@@ -33,7 +33,7 @@ func New() CoordinatorLog {
 }
 
 type coordinatorLog struct {
-	logColl *mongo.Collection
+	logColl mongo.ICollection
 }
 
 func (c *coordinatorLog) Init(a *app.App) (err error) {
diff --git a/db/db.go b/db/db.go
index c4273de..c0efcbe 100644
--- a/db/db.go
+++ b/db/db.go
@@ -4,10 +4,14 @@ import (
 	"context"
 	"github.com/anyproto/any-sync/app"
 	"github.com/anyproto/any-sync/app/logger"
-	"go.mongodb.org/mongo-driver/mongo"
+	mongo "github.com/256dpi/lungo"
 	"go.mongodb.org/mongo-driver/mongo/options"
 	"go.mongodb.org/mongo-driver/mongo/readconcern"
 	"time"
+	"go.uber.org/zap"
+	"github.com/anyproto/any-sync/nodeconf"
+	"go.mongodb.org/mongo-driver/bson/primitive"
+	"fmt"
 )
 
 const CName = "coordinator.db"
@@ -16,8 +20,8 @@ var log = logger.NewNamed(CName)
 
 type Database interface {
 	app.Component
-	Db() *mongo.Database
-	Tx(ctx context.Context, f func(txCtx mongo.SessionContext) error) error
+	Db() mongo.IDatabase
+	Tx(ctx context.Context, f func(txCtx mongo.ISessionContext) error) error
 }
 
 func New() Database {
@@ -29,18 +33,22 @@ type mongoProvider interface {
 }
 
 type database struct {
-	db *mongo.Database
+	db mongo.IDatabase
 }
 
 func (d *database) Init(a *app.App) (err error) {
 	conf := a.MustComponent("config").(mongoProvider).GetMongo()
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
 	defer cancel()
-	client, err := mongo.Connect(ctx, options.Client().ApplyURI(conf.Connect))
+	opts := mongo.Options{
+		Store: mongo.NewFileStore("any-sync-coordinator.db", 0644),
+	}
+	client, _, err := mongo.Open(ctx, opts)
 	if err != nil {
 		return err
 	}
 	d.db = client.Database(conf.Database)
+	confapply(a, d)
 	return
 }
 
@@ -48,16 +56,16 @@ func (d *database) Name() (name string) {
 	return CName
 }
 
-func (d *database) Db() *mongo.Database {
+func (d *database) Db() mongo.IDatabase {
 	return d.db
 }
 
-func (d *database) Tx(ctx context.Context, f func(txCtx mongo.SessionContext) error) error {
+func (d *database) Tx(ctx context.Context, f func(txCtx mongo.ISessionContext) error) error {
 	client := d.db.Client()
 	return client.UseSessionWithOptions(
 		ctx,
 		options.Session().SetDefaultReadConcern(readconcern.Majority()),
-		func(txCtx mongo.SessionContext) error {
+		func(txCtx mongo.ISessionContext) error {
 			if err := txCtx.StartTransaction(); err != nil {
 				return err
 			}
@@ -77,3 +85,41 @@ func (d *database) Tx(ctx context.Context, f func(txCtx mongo.SessionContext) er
 			return txCtx.CommitTransaction(context.Background())
 		})
 }
+
+type nodeConfProvider interface {
+	GetNodeConf() nodeconf.Configuration
+}
+
+func confapply(a *app.App, d Database) {
+
+	type ConfModel struct {
+		Id           primitive.ObjectID `bson:"_id"`
+		NetworkId    string             `bson:"networkId"`
+		Nodes        []nodeconf.Node    `bson:"nodes"`
+		CreationTime time.Time          `bson:"creationTime"`
+		Enable       bool               `bson:"enable"`
+	}
+
+	const collName = "nodeConf"
+	// var getLastSort = options.FindOne().SetSort(bson.D{{"_id", -1}})
+	// var getLastFilter = bson.D{{"enable", true}}
+	coll := d.Db().Collection(collName)
+
+	nodeConf := a.MustComponent("config").(nodeConfProvider).GetNodeConf()
+
+	flagNetworkEnable := true
+
+	m := ConfModel{
+		Id:           primitive.NewObjectID(),
+		NetworkId:    nodeConf.NetworkId,
+		Nodes:        nodeConf.Nodes,
+		CreationTime: time.Now(),
+		Enable:       flagNetworkEnable,
+	}
+	ctx := context.Background()
+	if _, err := coll.InsertOne(ctx, m); err != nil {
+		log.Error("InsertOne network", zap.Error(err))
+		return
+	}
+	fmt.Println(m.Id.Hex())
+}
diff --git a/deletionlog/deletionlog.go b/deletionlog/deletionlog.go
index 66728e9..0fdd9c1 100644
--- a/deletionlog/deletionlog.go
+++ b/deletionlog/deletionlog.go
@@ -9,7 +9,7 @@ import (
 	"github.com/anyproto/any-sync/coordinator/coordinatorproto"
 	"go.mongodb.org/mongo-driver/bson"
 	"go.mongodb.org/mongo-driver/bson/primitive"
-	"go.mongodb.org/mongo-driver/mongo"
+	mongo "github.com/256dpi/lungo"
 	"go.mongodb.org/mongo-driver/mongo/options"
 
 	"github.com/anyproto/any-sync-coordinator/db"
@@ -50,7 +50,7 @@ const (
 )
 
 type deletionLog struct {
-	coll *mongo.Collection
+	coll mongo.ICollection
 }
 
 func (d *deletionLog) Init(a *app.App) (err error) {
diff --git a/go.mod b/go.mod
index 3704063..5125b52 100644
--- a/go.mod
+++ b/go.mod
@@ -18,6 +18,7 @@ require (
 
 require (
 	filippo.io/edwards25519 v1.1.0 // indirect
+	github.com/256dpi/lungo v0.3.7 // indirect
 	github.com/anyproto/go-chash v0.1.0 // indirect
 	github.com/anyproto/go-slip10 v1.0.0 // indirect
 	github.com/anyproto/go-slip21 v1.0.0 // indirect
@@ -77,8 +78,10 @@ require (
 	github.com/prometheus/common v0.48.0 // indirect
 	github.com/prometheus/procfs v0.12.0 // indirect
 	github.com/quic-go/quic-go v0.42.0 // indirect
+	github.com/shopspring/decimal v1.3.1 // indirect
 	github.com/spaolacci/murmur3 v1.1.0 // indirect
 	github.com/supranational/blst v0.3.11 // indirect
+	github.com/tidwall/btree v1.7.0 // indirect
 	github.com/tyler-smith/go-bip39 v1.1.0 // indirect
 	github.com/xdg-go/pbkdf2 v1.0.0 // indirect
 	github.com/xdg-go/scram v1.1.2 // indirect
@@ -99,6 +102,7 @@ require (
 	golang.org/x/time v0.5.0 // indirect
 	golang.org/x/tools v0.19.0 // indirect
 	google.golang.org/protobuf v1.32.0 // indirect
+	gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 // indirect
 	lukechampine.com/blake3 v1.2.1 // indirect
 	rsc.io/tmplfunc v0.0.3 // indirect
 )
diff --git a/go.sum b/go.sum
index 6fa0405..0a9db77 100644
--- a/go.sum
+++ b/go.sum
@@ -1,5 +1,7 @@
 filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
 filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
+github.com/256dpi/lungo v0.3.7 h1:2tX3oOaeQP2GpLj7eqMaIAHBGmEkrvXSZmqDACOzOjU=
+github.com/256dpi/lungo v0.3.7/go.mod h1:r69kf9biVOiUB6LGKtceM2YwIIF/QRGruhQIKFN6J/U=
 github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ=
 github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
 github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
@@ -223,6 +225,8 @@ github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjR
 github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
 github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU=
 github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
+github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
+github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
 github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
 github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
@@ -237,6 +241,8 @@ github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbe
 github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=
 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
+github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI=
+github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY=
 github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
 github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
 github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
@@ -366,6 +372,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
 gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 h1:yiW+nvdHb9LVqSHQBXfZCieqV4fzYhNBql77zY0ykqs=
+gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk=
 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/identityrepo/identityrepo.go b/identityrepo/identityrepo.go
index a800fbc..c9fddce 100644
--- a/identityrepo/identityrepo.go
+++ b/identityrepo/identityrepo.go
@@ -10,7 +10,7 @@ import (
 	"github.com/anyproto/any-sync/net/peer"
 	"github.com/anyproto/any-sync/net/rpc/server"
 	"go.mongodb.org/mongo-driver/bson"
-	"go.mongodb.org/mongo-driver/mongo"
+	mongo "github.com/256dpi/lungo"
 	"go.mongodb.org/mongo-driver/mongo/options"
 	"time"
 )
@@ -42,7 +42,7 @@ type IdentityRepo interface {
 }
 
 type identityRepo struct {
-	coll    *mongo.Collection
+	coll    mongo.ICollection
 	handler *rpcHandler
 }
 
diff --git a/nodeconfsource/source.go b/nodeconfsource/source.go
index 894535d..679bbeb 100644
--- a/nodeconfsource/source.go
+++ b/nodeconfsource/source.go
@@ -8,7 +8,7 @@ import (
 	"github.com/anyproto/any-sync/nodeconf"
 	"go.mongodb.org/mongo-driver/bson"
 	"go.mongodb.org/mongo-driver/bson/primitive"
-	"go.mongodb.org/mongo-driver/mongo"
+	mongo "github.com/256dpi/lungo"
 	"go.mongodb.org/mongo-driver/mongo/options"
 	"time"
 )
@@ -34,7 +34,7 @@ type ConfModel struct {
 }
 
 type nodeConfSource struct {
-	coll *mongo.Collection
+	coll mongo.ICollection
 }
 
 func (n *nodeConfSource) Init(a *app.App) (err error) {
diff --git a/spacestatus/spacedeleter.go b/spacestatus/spacedeleter.go
index 37ef817..da0707e 100644
--- a/spacestatus/spacedeleter.go
+++ b/spacestatus/spacedeleter.go
@@ -4,9 +4,9 @@ import (
 	"context"
 	"time"
 
+	mongo "github.com/256dpi/lungo"
 	"github.com/anyproto/any-sync/util/periodicsync"
 	"go.mongodb.org/mongo-driver/bson"
-	"go.mongodb.org/mongo-driver/mongo"
 	"go.uber.org/zap"
 )
 
@@ -15,7 +15,7 @@ const deletionTimeout = time.Second * 100
 type Deleter func(ctx context.Context, spaceId string) (err error)
 
 type SpaceDeleter interface {
-	Run(spaces *mongo.Collection, delSender Deleter)
+	Run(spaces mongo.ICollection, delSender Deleter)
 	Close()
 }
 
@@ -70,7 +70,7 @@ type StatusEntry struct {
 }
 
 type spaceDeleter struct {
-	spaces         *mongo.Collection
+	spaces         mongo.ICollection
 	runSeconds     int
 	deletionPeriod time.Duration
 	loop           periodicsync.PeriodicSync
@@ -86,7 +86,7 @@ func newSpaceDeleter(runSeconds int, deletionPeriod time.Duration) SpaceDeleter
 	}
 }
 
-func (s *spaceDeleter) Run(spaces *mongo.Collection, deleter Deleter) {
+func (s *spaceDeleter) Run(spaces mongo.ICollection, deleter Deleter) {
 	s.deleter = deleter
 	s.spaces = spaces
 	s.loop = periodicsync.NewPeriodicSync(s.runSeconds, deletionTimeout, s.delete, log)
@@ -120,7 +120,7 @@ func (s *spaceDeleter) delete(ctx context.Context) (err error) {
 	return
 }
 
-func (s *spaceDeleter) processEntry(ctx context.Context, cur *mongo.Cursor) (err error) {
+func (s *spaceDeleter) processEntry(ctx context.Context, cur mongo.ICursor) (err error) {
 	entry := &StatusEntry{}
 	err = cur.Decode(entry)
 	if err != nil {
diff --git a/spacestatus/spacestatus.go b/spacestatus/spacestatus.go
index 838eb1c..665eb70 100644
--- a/spacestatus/spacestatus.go
+++ b/spacestatus/spacestatus.go
@@ -11,7 +11,7 @@ import (
 	"github.com/anyproto/any-sync/coordinator/coordinatorproto"
 	"github.com/anyproto/any-sync/util/crypto"
 	"go.mongodb.org/mongo-driver/bson"
-	"go.mongodb.org/mongo-driver/mongo"
+	mongo "github.com/256dpi/lungo"
 	"go.mongodb.org/mongo-driver/mongo/options"
 	"go.uber.org/zap"
 
@@ -104,7 +104,7 @@ func New() SpaceStatus {
 
 type spaceStatus struct {
 	conf           Config
-	spaces         *mongo.Collection
+	spaces         mongo.ICollection
 	verifier       ChangeVerifier
 	deleter        SpaceDeleter
 	db             db.Database
@@ -173,7 +173,7 @@ func (s *spaceStatus) AccountDelete(ctx context.Context, payload AccountDeletion
 		deletionTimestamp    = tm.Unix()
 		toBeDeletedTimestamp = tm.Add(s.deletionPeriod).Unix()
 	)
-	err = s.db.Tx(ctx, func(txCtx mongo.SessionContext) error {
+	err = s.db.Tx(ctx, func(txCtx mongo.ISessionContext) error {
 		// Find personal space with SpaceStatusCreated status for the given identity
 		if !s.accountStatusFindTx(txCtx, identity, SpaceStatusCreated) {
 			return coordinatorproto.ErrAccountIsDeleted
@@ -223,7 +223,7 @@ func (s *spaceStatus) AccountRevertDeletion(ctx context.Context, payload Account
 	if payload.Identity != nil {
 		identity = payload.Identity.Account()
 	}
-	return s.db.Tx(ctx, func(txCtx mongo.SessionContext) error {
+	return s.db.Tx(ctx, func(txCtx mongo.ISessionContext) error {
 		if !s.accountStatusFindTx(txCtx, identity, SpaceStatusDeletionPending) {
 			return coordinatorproto.ErrUnexpected
 		}
@@ -264,7 +264,7 @@ func (s *spaceStatus) SpaceDelete(ctx context.Context, payload SpaceDeletion) (t
 		deletionTimestamp    = tm.Unix()
 		toBeDeletedTimestamp = tm.Add(payload.DeletionPeriod).Unix()
 	)
-	err = s.db.Tx(ctx, func(txCtx mongo.SessionContext) error {
+	err = s.db.Tx(ctx, func(txCtx mongo.ISessionContext) error {
 		spType, err := s.getSpaceTypeTx(txCtx, payload.SpaceId)
 		if err != nil {
 			return coordinatorproto.ErrSpaceNotExists
@@ -301,7 +301,7 @@ func (s *spaceStatus) SpaceDelete(ctx context.Context, payload SpaceDeletion) (t
 func (s *spaceStatus) ChangeStatus(ctx context.Context, change StatusChange) (entry StatusEntry, err error) {
 	switch change.Status {
 	case SpaceStatusCreated:
-		err = s.db.Tx(ctx, func(txCtx mongo.SessionContext) error {
+		err = s.db.Tx(ctx, func(txCtx mongo.ISessionContext) error {
 			if entry, err = s.setStatusTx(txCtx, change, SpaceStatusDeletionPending); err != nil {
 				return err
 			}
@@ -324,14 +324,14 @@ func (s *spaceStatus) ChangeStatus(ctx context.Context, change StatusChange) (en
 }
 
 func (s *spaceStatus) setStatus(ctx context.Context, change StatusChange, oldStatus int) (entry StatusEntry, err error) {
-	err = s.db.Tx(ctx, func(txCtx mongo.SessionContext) error {
+	err = s.db.Tx(ctx, func(txCtx mongo.ISessionContext) error {
 		entry, err = s.setStatusTx(txCtx, change, oldStatus)
 		return err
 	})
 	return
 }
 
-func (s *spaceStatus) setStatusTx(txCtx mongo.SessionContext, change StatusChange, oldStatus int) (entry StatusEntry, err error) {
+func (s *spaceStatus) setStatusTx(txCtx mongo.ISessionContext, change StatusChange, oldStatus int) (entry StatusEntry, err error) {
 	entry, err = s.modifyStatus(txCtx, change, oldStatus)
 	if err != nil {
 		return
@@ -412,7 +412,7 @@ func (s *spaceStatus) Status(ctx context.Context, spaceId string) (entry StatusE
 	return
 }
 
-func (s *spaceStatus) accountStatusFindTx(txCtx mongo.SessionContext, identity string, status int) (found bool) {
+func (s *spaceStatus) accountStatusFindTx(txCtx mongo.ISessionContext, identity string, status int) (found bool) {
 	err := s.spaces.FindOne(txCtx, newPersonalAccountQuery(identity, status)).Err()
 	if err == nil {
 		return true
@@ -420,7 +420,7 @@ func (s *spaceStatus) accountStatusFindTx(txCtx mongo.SessionContext, identity s
 	return false
 }
 
-func (s *spaceStatus) getSpaceTypeTx(txCtx mongo.SessionContext, spaceId string) (spaceType SpaceType, err error) {
+func (s *spaceStatus) getSpaceTypeTx(txCtx mongo.ISessionContext, spaceId string) (spaceType SpaceType, err error) {
 	var entry StatusEntry
 	err = s.spaces.FindOne(txCtx, findStatusQuery{
 		SpaceId: spaceId,
@@ -432,7 +432,7 @@ func (s *spaceStatus) getSpaceTypeTx(txCtx mongo.SessionContext, spaceId string)
 }
 
 func (s *spaceStatus) NewStatus(ctx context.Context, spaceId string, identity, oldIdentity crypto.PubKey, spaceType SpaceType, force bool) error {
-	return s.db.Tx(ctx, func(txCtx mongo.SessionContext) error {
+	return s.db.Tx(ctx, func(txCtx mongo.ISessionContext) error {
 		if s.accountStatusFindTx(txCtx, identity.Account(), SpaceStatusDeletionPending) {
 			return coordinatorproto.ErrAccountIsDeleted
 		}
@@ -478,7 +478,7 @@ func (s *spaceStatus) NewStatus(ctx context.Context, spaceId string, identity, o
 }
 
 func (s *spaceStatus) MakeShareable(ctx context.Context, spaceId string, limit uint32) (err error) {
-	return s.db.Tx(ctx, func(txCtx mongo.SessionContext) error {
+	return s.db.Tx(ctx, func(txCtx mongo.ISessionContext) error {
 		entry, err := s.Status(txCtx, spaceId)
 		if err != nil {
 			return err
@@ -504,7 +504,7 @@ func (s *spaceStatus) MakeShareable(ctx context.Context, spaceId string, limit u
 }
 
 func (s *spaceStatus) MakeUnshareable(ctx context.Context, spaceId string) (err error) {
-	return s.db.Tx(ctx, func(txCtx mongo.SessionContext) error {
+	return s.db.Tx(ctx, func(txCtx mongo.ISessionContext) error {
 		entry, err := s.Status(txCtx, spaceId)
 		if err != nil {
 			return err
@@ -526,7 +526,7 @@ type byIdentityAndStatus struct {
 	Status   int    `bson:"status"`
 }
 
-func (s *spaceStatus) checkLimitTx(txCtx mongo.SessionContext, identity crypto.PubKey) (err error) {
+func (s *spaceStatus) checkLimitTx(txCtx mongo.ISessionContext, identity crypto.PubKey) (err error) {
 	if s.conf.SpaceLimit <= 0 {
 		return
 	}

docker/coordinator.Dockerfile:

FROM golang:bookworm AS builder

ARG ANY_SYNC_COORDINATOR_VERSION="v0.4.4"

RUN git clone --depth=1 -b ${ANY_SYNC_COORDINATOR_VERSION} https://github.com/anyproto/any-sync-coordinator /usr/src/app

WORKDIR /usr/src/app

COPY patches /patches

RUN git apply /patches/"any-sync-coordinator-${ANY_SYNC_COORDINATOR_VERSION}.patch"

RUN go mod download && go mod verify

RUN go build -x -v -trimpath -ldflags "-s -w -X github.com/anyproto/any-sync/app.AppName=any-sync-coordinator" -buildvcs=false -o /usr/local/bin/any-sync-coordinator ./cmd/coordinator

FROM gcr.io/distroless/base-debian12

COPY --from=builder /usr/local/bin/any-sync-coordinator /usr/local/bin/any-sync-coordinator

WORKDIR /app

CMD ["/usr/local/bin/any-sync-coordinator", "-c", "/app/config.yml"]

Compared to forking, using patches has much lower maintenance costs in the long run. However, this does not mean that no effort is required for maintenance later on; the maintenance cost mainly depends on the extent of changes in the target project’s code!

I hope this is helpful, Happy hacking…