@@ -718,6 +718,8 @@ func (m *Model) toggleDrop() {
718718 // Check if any other branch has a fold targeting this branch.
719719 // A fold-up targets the branch above (lower index), fold-down
720720 // targets the branch below (higher index).
721+ // Also check if dropping this branch would cause a fold to
722+ // retarget to an inserted branch.
721723 for i , other := range m .nodes {
722724 if other .PendingAction == nil || i == m .cursor {
723725 continue
@@ -727,6 +729,25 @@ func (m *Model) toggleDrop() {
727729 for j := i - 1 ; j >= 0 ; j -- {
728730 if ! m .nodes [j ].Removed && ! m .nodes [j ].Ref .IsMerged () {
729731 if j == m .cursor {
732+ // This branch is the current target. Check what the
733+ // next target would be after dropping it.
734+ nextTarget := - 1
735+ for k := j - 1 ; k >= 0 ; k -- {
736+ if ! m .nodes [k ].Removed && ! m .nodes [k ].Ref .IsMerged () {
737+ nextTarget = k
738+ break
739+ }
740+ }
741+ if nextTarget < 0 {
742+ m .statusMessage = fmt .Sprintf ("Cannot drop: %s is folding into this branch" , other .Ref .Branch )
743+ m .statusIsError = true
744+ return
745+ }
746+ if m .nodes [nextTarget ].IsInserted {
747+ m .statusMessage = fmt .Sprintf ("Cannot drop: %s would fold into an inserted branch" , other .Ref .Branch )
748+ m .statusIsError = true
749+ return
750+ }
730751 m .statusMessage = fmt .Sprintf ("Cannot drop: %s is folding into this branch" , other .Ref .Branch )
731752 m .statusIsError = true
732753 return
@@ -740,6 +761,25 @@ func (m *Model) toggleDrop() {
740761 for j := i + 1 ; j < len (m .nodes ); j ++ {
741762 if ! m .nodes [j ].Removed && ! m .nodes [j ].Ref .IsMerged () {
742763 if j == m .cursor {
764+ // This branch is the current target. Check what the
765+ // next target would be after dropping it.
766+ nextTarget := - 1
767+ for k := j + 1 ; k < len (m .nodes ); k ++ {
768+ if ! m .nodes [k ].Removed && ! m .nodes [k ].Ref .IsMerged () {
769+ nextTarget = k
770+ break
771+ }
772+ }
773+ if nextTarget < 0 {
774+ m .statusMessage = fmt .Sprintf ("Cannot drop: %s is folding into this branch" , other .Ref .Branch )
775+ m .statusIsError = true
776+ return
777+ }
778+ if m .nodes [nextTarget ].IsInserted {
779+ m .statusMessage = fmt .Sprintf ("Cannot drop: %s would fold into an inserted branch" , other .Ref .Branch )
780+ m .statusIsError = true
781+ return
782+ }
743783 m .statusMessage = fmt .Sprintf ("Cannot drop: %s is folding into this branch" , other .Ref .Branch )
744784 m .statusIsError = true
745785 return
@@ -816,6 +856,38 @@ func (m *Model) fold(action ActionType) {
816856 return
817857 }
818858
859+ // Check if the current node is the target of another fold — folding
860+ // a branch that is receiving commits from another fold is not allowed.
861+ for i , other := range m .nodes {
862+ if other .PendingAction == nil || i == m .cursor {
863+ continue
864+ }
865+ if other .PendingAction .Type == ActionFoldUp {
866+ for j := i - 1 ; j >= 0 ; j -- {
867+ if ! m .nodes [j ].Removed && ! m .nodes [j ].Ref .IsMerged () {
868+ if j == m .cursor {
869+ m .statusMessage = fmt .Sprintf ("Cannot fold: %s is folding into this branch" , other .Ref .Branch )
870+ m .statusIsError = true
871+ return
872+ }
873+ break
874+ }
875+ }
876+ }
877+ if other .PendingAction .Type == ActionFoldDown {
878+ for j := i + 1 ; j < len (m .nodes ); j ++ {
879+ if ! m .nodes [j ].Removed && ! m .nodes [j ].Ref .IsMerged () {
880+ if j == m .cursor {
881+ m .statusMessage = fmt .Sprintf ("Cannot fold: %s is folding into this branch" , other .Ref .Branch )
882+ m .statusIsError = true
883+ return
884+ }
885+ break
886+ }
887+ }
888+ }
889+ }
890+
819891 // Find the target branch
820892 var targetIdx int
821893 var found bool
@@ -834,6 +906,11 @@ func (m *Model) fold(action ActionType) {
834906 m .statusIsError = true
835907 return
836908 }
909+ if m .nodes [targetIdx ].IsInserted {
910+ m .statusMessage = "Cannot fold into an inserted branch"
911+ m .statusIsError = true
912+ return
913+ }
837914 } else {
838915 // Fold up: target is the previous non-removed, non-merged node away from trunk (lower index)
839916 for i := m .cursor - 1 ; i >= 0 ; i -- {
@@ -848,6 +925,19 @@ func (m *Model) fold(action ActionType) {
848925 m .statusIsError = true
849926 return
850927 }
928+ if m .nodes [targetIdx ].IsInserted {
929+ m .statusMessage = "Cannot fold into an inserted branch"
930+ m .statusIsError = true
931+ return
932+ }
933+ }
934+
935+ // Check if the target is already folding (mutual fold / chain fold)
936+ target := & m .nodes [targetIdx ]
937+ if target .PendingAction != nil && (target .PendingAction .Type == ActionFoldDown || target .PendingAction .Type == ActionFoldUp ) {
938+ m .statusMessage = fmt .Sprintf ("Cannot fold: %s is already folding in the opposite direction" , target .Ref .Branch )
939+ m .statusIsError = true
940+ return
851941 }
852942
853943 // Check if this would remove the last active original branch
@@ -913,6 +1003,44 @@ func (m *Model) startInsert(direction ActionType) {
9131003 return
9141004 }
9151005
1006+ // Compute where the node would be inserted
1007+ insertIdx := m .cursor
1008+ if direction == ActionInsertBelow {
1009+ insertIdx = m .cursor + 1
1010+ }
1011+
1012+ // Check if inserting here would place the new branch between a
1013+ // folding branch and its target, making it the new fold target.
1014+ for i , other := range m .nodes {
1015+ if other .PendingAction == nil {
1016+ continue
1017+ }
1018+ if other .PendingAction .Type == ActionFoldDown {
1019+ for j := i + 1 ; j < len (m .nodes ); j ++ {
1020+ if ! m .nodes [j ].Removed && ! m .nodes [j ].Ref .IsMerged () {
1021+ if insertIdx > i && insertIdx <= j {
1022+ m .statusMessage = fmt .Sprintf ("Cannot insert here: %s is folding into %s" , other .Ref .Branch , m .nodes [j ].Ref .Branch )
1023+ m .statusIsError = true
1024+ return
1025+ }
1026+ break
1027+ }
1028+ }
1029+ }
1030+ if other .PendingAction .Type == ActionFoldUp {
1031+ for j := i - 1 ; j >= 0 ; j -- {
1032+ if ! m .nodes [j ].Removed && ! m .nodes [j ].Ref .IsMerged () {
1033+ if insertIdx > j && insertIdx <= i {
1034+ m .statusMessage = fmt .Sprintf ("Cannot insert here: %s is folding into %s" , other .Ref .Branch , m .nodes [j ].Ref .Branch )
1035+ m .statusIsError = true
1036+ return
1037+ }
1038+ break
1039+ }
1040+ }
1041+ }
1042+ }
1043+
9161044 m .insertMode = true
9171045 m .insertDirection = direction
9181046 m .insertInput .SetValue ("" )
0 commit comments