This is an automated email from the ASF dual-hosted git repository.

matthiasblaesing pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git


The following commit(s) were added to refs/heads/master by this push:
     new 729f4dcb75 Git client: Enable forced pushes for configured push and 
push to upstream
     new 296b2bff0a Merge pull request #6823 from matthiasblaesing/git
729f4dcb75 is described below

commit 729f4dcb75e9d77c415406a8b3ca673f51933673
Author: Matthias Bläsing <mblaes...@doppel-helix.eu>
AuthorDate: Sat Nov 11 14:20:54 2023 +0100

    Git client: Enable forced pushes for configured push and push to upstream
---
 ide/git/nbproject/project.xml                      |  2 +-
 .../modules/git/ui/fetch/BranchMapping.java        | 10 ++---
 .../modules/git/ui/fetch/FetchBranchesStep.java    |  2 +-
 .../modules/git/ui/fetch/PullBranchesStep.java     |  2 +-
 .../netbeans/modules/git/ui/push/PushAction.java   |  2 +
 .../modules/git/ui/push/PushBranchesStep.java      |  8 ++--
 .../netbeans/modules/git/ui/push/PushMapping.java  | 36 ++++++++++------
 .../modules/git/ui/push/PushToUpstreamAction.java  | 49 +++++++++++++++++++++-
 .../netbeans/modules/git/ui/push/PushWizard.java   |  2 +-
 .../modules/git/ui/selectors/Bundle.properties     |  5 ++-
 .../modules/git/ui/selectors/ItemSelector.java     | 28 ++++++-------
 .../modules/git/ui/selectors/ItemsPanel.form       | 12 +++---
 .../modules/git/ui/selectors/ItemsPanel.java       | 12 +++---
 .../org/netbeans/modules/git/utils/GitUtils.java   |  7 +++-
 ide/libs.git/apichanges.xml                        | 19 +++++++++
 ide/libs.git/manifest.mf                           |  2 +-
 .../libs/git/jgit/commands/PushCommand.java        | 12 +-----
 .../netbeans/libs/git/jgit/commands/PushTest.java  |  4 +-
 18 files changed, 143 insertions(+), 71 deletions(-)

diff --git a/ide/git/nbproject/project.xml b/ide/git/nbproject/project.xml
index 2a3a8514c8..9bc4b97802 100644
--- a/ide/git/nbproject/project.xml
+++ b/ide/git/nbproject/project.xml
@@ -53,7 +53,7 @@
                     <compile-dependency/>
                     <run-dependency>
                         <release-version>1</release-version>
-                        <specification-version>1.31</specification-version>
+                        <specification-version>1.58</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
diff --git a/ide/git/src/org/netbeans/modules/git/ui/fetch/BranchMapping.java 
b/ide/git/src/org/netbeans/modules/git/ui/fetch/BranchMapping.java
index 248a5fe834..08d3122e26 100644
--- a/ide/git/src/org/netbeans/modules/git/ui/fetch/BranchMapping.java
+++ b/ide/git/src/org/netbeans/modules/git/ui/fetch/BranchMapping.java
@@ -49,7 +49,7 @@ public class BranchMapping extends ItemSelector.Item {
         this.remoteBranchName = remoteBranchName;
         this.localBranch = localBranch;
         this.remote = remote;
-        if (isDeletion()) {
+        if (isDestructive()) {
             // to remove
             label = MessageFormat.format(BRANCH_DELETE_MAPPING_LABEL, 
localBranch.getName(), "<font color=\"" + COLOR_REMOVED + "\">R</font>");
 
@@ -93,7 +93,7 @@ public class BranchMapping extends ItemSelector.Item {
     }
 
     public String getRefSpec () {
-        if (isDeletion()) {
+        if (isDestructive()) {
             return GitUtils.getDeletedRefSpec(localBranch);
         } else {
             return GitUtils.getRefSpec(remoteBranchName, 
remote.getRemoteName());
@@ -125,12 +125,12 @@ public class BranchMapping extends ItemSelector.Item {
         }
         if(t instanceof BranchMapping) {
             BranchMapping other = (BranchMapping) t;
-            if (isDeletion() && other.isDeletion()) {
+            if (isDestructive() && other.isDestructive()) {
                 return 
localBranch.getName().compareTo(other.localBranch.getName());
-            } else if (isDeletion() && !other.isDeletion()) {
+            } else if (isDestructive() && !other.isDestructive()) {
                 // deleted branches should be at the bottom
                 return 1;
-            } else if (!isDeletion() && other.isDeletion()) {
+            } else if (!isDestructive() && other.isDestructive()) {
                 // deleted branches should be at the bottom
                 return -1;
             } else {
diff --git 
a/ide/git/src/org/netbeans/modules/git/ui/fetch/FetchBranchesStep.java 
b/ide/git/src/org/netbeans/modules/git/ui/fetch/FetchBranchesStep.java
index 2bb1c983e5..2fdd6a348d 100644
--- a/ide/git/src/org/netbeans/modules/git/ui/fetch/FetchBranchesStep.java
+++ b/ide/git/src/org/netbeans/modules/git/ui/fetch/FetchBranchesStep.java
@@ -228,7 +228,7 @@ public class FetchBranchesStep extends AbstractWizardPanel 
implements WizardDesc
     static String getDeletedBranchesMessage (List<BranchMapping> 
selectedBranches) {
         StringBuilder sb = new StringBuilder(100);
         for (BranchMapping m : selectedBranches) {
-            if (m.isDeletion()) {
+            if (m.isDestructive()) {
                 
sb.append(Bundle.MSG_FetchBranchesStep_toBeDeletedBranch(m.getLocalBranch().getName())).append("<br>");
             }
         }
diff --git 
a/ide/git/src/org/netbeans/modules/git/ui/fetch/PullBranchesStep.java 
b/ide/git/src/org/netbeans/modules/git/ui/fetch/PullBranchesStep.java
index 913669e025..4d3704b821 100644
--- a/ide/git/src/org/netbeans/modules/git/ui/fetch/PullBranchesStep.java
+++ b/ide/git/src/org/netbeans/modules/git/ui/fetch/PullBranchesStep.java
@@ -206,7 +206,7 @@ public class PullBranchesStep extends AbstractWizardPanel 
implements WizardDescr
         mergingBranch = null;
         List<BranchMapping> candidates = new 
ArrayList<BranchMapping>(branches.getSelectedBranches().size());
         for (BranchMapping mapping : branches.getSelectedBranches()) {
-            if (!mapping.isDeletion()) {
+            if (!mapping.isDestructive()) {
                 candidates.add(mapping);
             }
         }
diff --git a/ide/git/src/org/netbeans/modules/git/ui/push/PushAction.java 
b/ide/git/src/org/netbeans/modules/git/ui/push/PushAction.java
index 03302a8d53..89dda6cccb 100644
--- a/ide/git/src/org/netbeans/modules/git/ui/push/PushAction.java
+++ b/ide/git/src/org/netbeans/modules/git/ui/push/PushAction.java
@@ -190,6 +190,8 @@ public class PushAction extends SingleRepositoryAction {
         "CTL_PushAction.report.outputButton.desc=Opens output with more 
information",
         "CTL_PushAction.report.pullButton.text=&Pull Changes",
         "CTL_PushAction.report.pullButton.desc=Fetch and merge remote 
changes.",
+        "CTL_PushAction.report.forceButton.text=&Force push",
+        "CTL_PushAction.report.forceButton.desc=Force push local branch to 
remote.",
         "LBL_PushAction.report.error.title=Git Push Failed",
         "MSG_PushAction.pullingChanges=Waiting for pull to finish",
         "LBL_PushAction.pullingChanges.finished=Remote Changes Pulled",
diff --git a/ide/git/src/org/netbeans/modules/git/ui/push/PushBranchesStep.java 
b/ide/git/src/org/netbeans/modules/git/ui/push/PushBranchesStep.java
index 42c0320763..4925ef2ac2 100644
--- a/ide/git/src/org/netbeans/modules/git/ui/push/PushBranchesStep.java
+++ b/ide/git/src/org/netbeans/modules/git/ui/push/PushBranchesStep.java
@@ -80,7 +80,7 @@ public class PushBranchesStep extends AbstractWizardPanel 
implements WizardDescr
         } else if (isDeleteUpdateConflict(localObjects.getSelectedBranches())) 
{
             setValid(false, new 
Message(NbBundle.getMessage(PushBranchesStep.class, 
"MSG_PushBranchesPanel.errorMixedSeletion"), false)); //NOI18N
         } else {
-            String msgDeletedBranches = 
getDeletedBranchesMessage(localObjects.getSelectedBranches());
+            String msgDeletedBranches = 
getDestructiveActionMessage(localObjects.getSelectedBranches());
             if (msgDeletedBranches != null) {
                 setValid(true, new Message(msgDeletedBranches, true));
             }
@@ -232,10 +232,10 @@ public class PushBranchesStep extends AbstractWizardPanel 
implements WizardDescr
         return localObjects.getSelectedBranches();
     }
     
-    public static String getDeletedBranchesMessage (List<PushMapping> 
selectedObjects) {
+    private static String getDestructiveActionMessage (List<PushMapping> 
selectedObjects) {
         StringBuilder sb = new StringBuilder(100);
         for (PushMapping m : selectedObjects) {
-            if (m.isDeletion()) {
+            if (m.isDestructive()) {
                 sb.append(m.getInfoMessage()).append("<br>");
             }
         }
@@ -251,7 +251,7 @@ public class PushBranchesStep extends AbstractWizardPanel 
implements WizardDescr
         Set<String> toDelete = new HashSet<String>(selectedObjects.size());
         Set<String> toUpdate = new HashSet<String>(selectedObjects.size());
         for (PushMapping m : selectedObjects) {
-            if (m.isDeletion()) {
+            if (m.isDestructive() && m.getLocalName() != null) {
                 toDelete.add(m.getRemoteName());
             } else {
                 toUpdate.add(m.getRemoteName());
diff --git a/ide/git/src/org/netbeans/modules/git/ui/push/PushMapping.java 
b/ide/git/src/org/netbeans/modules/git/ui/push/PushMapping.java
index ebdbedf766..fa9006173e 100644
--- a/ide/git/src/org/netbeans/modules/git/ui/push/PushMapping.java
+++ b/ide/git/src/org/netbeans/modules/git/ui/push/PushMapping.java
@@ -46,7 +46,7 @@ public abstract class PushMapping extends ItemSelector.Item {
     private static final String COLOR_CONFLICT = 
GitUtils.getColorString(AnnotationColorProvider.getInstance().CONFLICT_FILE.getActualColor());
     
     protected PushMapping (String localName, String localId, String 
remoteName, boolean conflict, boolean preselected, boolean updateNeeded) {
-        super(preselected, localName == null);
+        super(preselected, localName == null || conflict);
         this.localName = localName;
         this.remoteName = remoteName == null ? localName : remoteName;
         if (localName == null) {
@@ -125,13 +125,13 @@ public abstract class PushMapping extends 
ItemSelector.Item {
         }
         if (t instanceof PushMapping) {
             PushMapping other = (PushMapping) t;
-            if (isDeletion() && other.isDeletion()) {
+            if (isDestructive() && other.isDestructive()) {
                 return remoteName.compareTo(other.remoteName);
-            } else if (isDeletion() && !other.isDeletion()) {
-                // deleted branches should be at the bottom
+            } else if (isDestructive() && !other.isDestructive()) {
+                // destructive changes should be at the bottom
                 return 1;
-            } else if (!isDeletion() && other.isDeletion()) {
-                // deleted branches should be at the bottom
+            } else if (!isDestructive() && other.isDestructive()) {
+                // destructive changes should be at the bottom
                 return -1;
             } else {
                 return localName.compareTo(other.localName);
@@ -197,23 +197,33 @@ public abstract class PushMapping extends 
ItemSelector.Item {
 
         @Override
         public String getRefSpec () {
-            if (isDeletion()) {
+            if (isDestructive() && getLocalName() == null) {
                 return GitUtils.getPushDeletedRefSpec(remoteBranchName);
             } else {
-                return GitUtils.getPushRefSpec(localBranch.getName(), 
remoteBranchName == null ? localBranch.getName() : remoteBranchName);
+                return GitUtils.getPushRefSpec(
+                        localBranch.getName(),
+                        remoteBranchName == null ? localBranch.getName() : 
remoteBranchName,
+                        isDestructive()
+                );
             }
         }
         
         @Override
         @NbBundle.Messages({
             "# {0} - branch name",
-            "MSG_PushMapping.toBeDeletedBranch=Branch {0} will be permanently 
removed from the remote repository."
+            "MSG_PushMapping.toBeDeletedBranch=Branch {0} will be permanently 
removed from the remote repository.",
+            "# {0} - branch name",
+            "MSG_PushMapping.toBeForcepushedBranch=Branch {0} will be force 
pushed to the remote repository."
         })
         String getInfoMessage () {
-            if (isDeletion()) {
+            if (isDestructive() &&  getLocalName() == null) {
                 return 
Bundle.MSG_PushMapping_toBeDeletedBranch(remoteBranchName);
             } else {
-                return super.getInfoMessage();
+                if(isDestructive()) {
+                    return 
Bundle.MSG_PushMapping_toBeForcepushedBranch(remoteBranchName);
+                } else {
+                    return super.getInfoMessage();
+                }
             }
         }
 
@@ -255,7 +265,7 @@ public abstract class PushMapping extends ItemSelector.Item 
{
 
         @Override
         public String getRefSpec() {
-            if (isDeletion()) {
+            if (isDestructive() && !isUpdate) {
                 //get command for tag deletion
                 return GitUtils.getPushDeletedTagRefSpec(remoteTagName);
             } else {
@@ -269,7 +279,7 @@ public abstract class PushMapping extends ItemSelector.Item 
{
             "MSG_PushMapping.toBeDeletedTag=Tag {0} will be permanently 
removed from the remote repository."
         })
         String getInfoMessage() {
-            if (isDeletion()) {
+            if (isDestructive() && !isUpdate) {
                 return Bundle.MSG_PushMapping_toBeDeletedTag(remoteTagName);
             } else {
                 return super.getInfoMessage();
diff --git 
a/ide/git/src/org/netbeans/modules/git/ui/push/PushToUpstreamAction.java 
b/ide/git/src/org/netbeans/modules/git/ui/push/PushToUpstreamAction.java
index d2e5473f75..aeaf42541f 100644
--- a/ide/git/src/org/netbeans/modules/git/ui/push/PushToUpstreamAction.java
+++ b/ide/git/src/org/netbeans/modules/git/ui/push/PushToUpstreamAction.java
@@ -24,8 +24,12 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 import org.netbeans.libs.git.GitBranch;
+import org.netbeans.libs.git.GitException;
 import org.netbeans.libs.git.GitRemoteConfig;
+import org.netbeans.libs.git.GitRevisionInfo;
 import org.netbeans.modules.git.Git;
 import org.netbeans.modules.git.client.GitProgressSupport;
 import org.netbeans.modules.git.ui.actions.MultipleRepositoryAction;
@@ -36,11 +40,14 @@ import org.openide.awt.ActionID;
 import org.openide.awt.ActionRegistration;
 import org.openide.util.NbBundle;
 import org.openide.util.actions.SystemAction;
+
 import static org.netbeans.modules.git.ui.push.Bundle.*;
+
 import org.netbeans.modules.git.ui.repository.RepositoryInfo.PushMode;
 import org.netbeans.modules.git.utils.GitUtils;
 import org.openide.DialogDisplayer;
 import org.openide.NotifyDescriptor;
+import org.openide.util.Exceptions;
 import org.openide.util.NbBundle.Messages;
 import org.openide.util.RequestProcessor;
 import org.openide.util.RequestProcessor.Task;
@@ -102,6 +109,7 @@ public class PushToUpstreamAction extends 
MultipleRepositoryAction {
                 List<String> fetchSpecs = cfg.getFetchRefSpecs();
                 String remoteBranchName;
                 String trackedBranchId = null;
+                boolean conflicted = false;
                 if (trackedBranch == null) {
                     if (shallCreateNewBranch(activeBranch)) {
                         remoteBranchName = activeBranch.getName();
@@ -115,8 +123,28 @@ public class PushToUpstreamAction extends 
MultipleRepositoryAction {
                         GitUtils.notifyError(errorLabel, 
MSG_Err_unknownRemoteBranchName(trackedBranch.getName()));
                         return;
                     }
+
+                    try {
+                        GitBranch remoteBranch = getClient()
+                                .listRemoteBranches(uri, getProgressMonitor())
+                                .get(remoteBranchName);
+                        GitRevisionInfo rev = 
getClient().getCommonAncestor(new String[]{activeBranch.getId(), 
remoteBranch.getId()}, getProgressMonitor());
+                        // conflict if
+                        // A) rev == null : completely unrelated commits
+                        // B) ancestor is neither remote branch (opposite 
means EQUAL or PUSH needed but not CONFLICT)
+                        //    nor local head (opposite means EQUAL or pull 
needed but not CONFLICT)
+                        conflicted = rev == null || 
(!remoteBranch.getId().equals(rev.getRevision()) && 
!activeBranch.getId().equals(rev.getRevision()));
+                    } catch (GitException ex) {
+                        
Logger.getLogger(PushBranchesStep.class.getName()).log(Level.INFO, 
activeBranch.getId() + ", " + remoteBranchName, ex); //NOI18N
+                    }
+
+                    if(conflicted) {
+                        if(!shallForcePush(remoteBranchName)) {
+                            return;
+                        }
+                    }
                 }
-                pushMappings.add(new 
PushMapping.PushBranchMapping(remoteBranchName, trackedBranchId, activeBranch, 
false, false));
+                pushMappings.add(new 
PushMapping.PushBranchMapping(remoteBranchName, trackedBranchId, activeBranch, 
conflicted, false));
                 Utils.logVCSExternalRepository("GIT", uri); //NOI18N
                 if (!isCanceled()) {
                     t[0] = SystemAction.get(PushAction.class).push(repository, 
uri, pushMappings,
@@ -226,5 +254,24 @@ public class PushToUpstreamAction extends 
MultipleRepositoryAction {
                 Bundle.LBL_Push_createNewBranch(),
                 NotifyDescriptor.YES_NO_OPTION, 
NotifyDescriptor.QUESTION_MESSAGE));
     }
+
+    @NbBundle.Messages({
+        "LBL_Push.forcePush=Conflicting change",
+        "# {0} - branch name",
+        "MSG_Push.forcePush=There are conflicting changes in the target branch 
\"{0}\".\n"
+                + "Do you want to abort or force push?",
+        "BTN_Push.forcePush=Force push"
+    })
+    private static boolean shallForcePush (String branchName) {
+        String push = Bundle.BTN_Push_forcePush();
+        return push == DialogDisplayer.getDefault().notify(new 
NotifyDescriptor(
+                Bundle.MSG_Push_forcePush(branchName),
+                Bundle.LBL_Push_forcePush(),
+                NotifyDescriptor.YES_NO_OPTION,
+                NotifyDescriptor.QUESTION_MESSAGE,
+                new Object[] {NotifyDescriptor.CANCEL_OPTION, push},
+                NotifyDescriptor.CANCEL_OPTION
+        ));
+    }
     
 }
diff --git a/ide/git/src/org/netbeans/modules/git/ui/push/PushWizard.java 
b/ide/git/src/org/netbeans/modules/git/ui/push/PushWizard.java
index e67d624a70..761310e2db 100644
--- a/ide/git/src/org/netbeans/modules/git/ui/push/PushWizard.java
+++ b/ide/git/src/org/netbeans/modules/git/ui/push/PushWizard.java
@@ -169,7 +169,7 @@ class PushWizard  implements ChangeListener {
                 Collection<PushMapping> mappings = 
pushBranchesStep.getSelectedMappings();
                 Map<String, String> remoteBranches = new LinkedHashMap<String, 
String>(mappings.size());
                 for (PushMapping mapping : mappings) {
-                    if (!mapping.isDeletion() && mapping instanceof 
PushMapping.PushBranchMapping) {
+                    if ((!mapping.isDestructive() || mapping.getLocalName() != 
null) && mapping instanceof PushMapping.PushBranchMapping) {
                         PushBranchMapping pushMapping = 
(PushMapping.PushBranchMapping) mapping;
                         
remoteBranches.put(pushMapping.getRemoteRepositoryBranchName(), 
pushMapping.getLocalRepositoryBranchHeadId());
                     }
diff --git 
a/ide/git/src/org/netbeans/modules/git/ui/selectors/Bundle.properties 
b/ide/git/src/org/netbeans/modules/git/ui/selectors/Bundle.properties
index 886cb7013a..99b18ff90b 100644
--- a/ide/git/src/org/netbeans/modules/git/ui/selectors/Bundle.properties
+++ b/ide/git/src/org/netbeans/modules/git/ui/selectors/Bundle.properties
@@ -22,5 +22,6 @@ ItemsPanel.btnSelectAll.text=Select &All
 ItemsPanel.btnSelectNone.text=Select &None
 ItemsPanel.btnSelectNone.TTtext=Deselect all available branches
 ItemsPanel.btnSelectAll.TTtext=Select all available branches
-ItemsPanel.btnAllowDeletes.text=Enable &Deletes
-ItemsPanel.btnDisableDeletes.text=Disable &Deletes
+ItemsPanel.btnDisableDestructiveActions.text=Disable &destructive Actions
+ItemsPanel.btnAllowDestructiveActions.text=Enable &destructive Actions
+ItemsPanel.btnAllowDestructiveActions.description=Enable/Disable destructive 
actions like deletes and force pushes
diff --git 
a/ide/git/src/org/netbeans/modules/git/ui/selectors/ItemSelector.java 
b/ide/git/src/org/netbeans/modules/git/ui/selectors/ItemSelector.java
index 4587dead1e..9cd6183b11 100644
--- a/ide/git/src/org/netbeans/modules/git/ui/selectors/ItemSelector.java
+++ b/ide/git/src/org/netbeans/modules/git/ui/selectors/ItemSelector.java
@@ -56,7 +56,7 @@ public class ItemSelector<I extends Item> implements 
ListSelectionListener {
 
     public ItemSelector(String title) {
         panel = new ItemsPanel();
-        panel.btnAllowDeletes.setVisible(false);
+        panel.btnAllowDestructiveActions.setVisible(false);
         Mnemonics.setLocalizedText(panel.titleLabel, title); 
         panel.list.setCellRenderer(new ItemRenderer());
         attachListeners();
@@ -79,8 +79,8 @@ public class ItemSelector<I extends Item> implements 
ListSelectionListener {
         DefaultListModel<I> model = new DefaultListModel<>();
         for (I i : branches) {
             model.addElement(i);
-            if (i.isDeletion()) {
-                panel.btnAllowDeletes.setVisible(true);
+            if (i.isDestructive()) {
+                panel.btnAllowDestructiveActions.setVisible(true);
             }
         }
         panel.list.setModel(model);        
@@ -165,7 +165,7 @@ public class ItemSelector<I extends Item> implements 
ListSelectionListener {
                 selectAll(false);
             }
         });
-        panel.btnAllowDeletes.addActionListener(new ActionListener() {
+        panel.btnAllowDestructiveActions.addActionListener(new 
ActionListener() {
 
             @Override
             public void actionPerformed(ActionEvent e) {
@@ -175,7 +175,7 @@ public class ItemSelector<I extends Item> implements 
ListSelectionListener {
                     int maxItemsCount = panel.list.getModel().getSize();
                     for (int i = 0; i < maxItemsCount; i++) {
                         Item item = (Item) 
panel.list.getModel().getElementAt(i);
-                        if (item.isDelete) {
+                        if (item.isDestructive()) {
                             fireChange = item.isSelected;
                             item.isSelected = false;
                         }
@@ -183,9 +183,9 @@ public class ItemSelector<I extends Item> implements 
ListSelectionListener {
                 }
                 panel.list.repaint();
                 if (deletesAllowed) {
-                    Mnemonics.setLocalizedText(panel.btnAllowDeletes, 
NbBundle.getMessage(ItemsPanel.class, "ItemsPanel.btnDisableDeletes.text")); 
//NOI18N
+                    
Mnemonics.setLocalizedText(panel.btnAllowDestructiveActions, 
NbBundle.getMessage(ItemsPanel.class, 
"ItemsPanel.btnDisableDestructiveActions.text")); //NOI18N
                 } else {
-                    Mnemonics.setLocalizedText(panel.btnAllowDeletes, 
NbBundle.getMessage(ItemsPanel.class, "ItemsPanel.btnAllowDeletes.text")); 
//NOI18N
+                    
Mnemonics.setLocalizedText(panel.btnAllowDestructiveActions, 
NbBundle.getMessage(ItemsPanel.class, 
"ItemsPanel.btnAllowDestructiveActions.text")); //NOI18N
                 }
                 if (fireChange) {
                     changeSupport.fireChange();
@@ -224,7 +224,7 @@ public class ItemSelector<I extends Item> implements 
ListSelectionListener {
     }
     
     private boolean isSelectedStateAllowed (Item item) {
-        return !item.isDelete || deletesAllowed;
+        return !item.isDestructive() || deletesAllowed;
     }
     
     public class ItemRenderer implements ListCellRenderer {
@@ -249,7 +249,7 @@ public class ItemSelector<I extends Item> implements 
ListSelectionListener {
                 renderer.setText("<html>" + item.getText() + "</html>");
                 renderer.setToolTipText(item.getTooltipText());
                 renderer.setSelected(item.isSelected);
-                renderer.setEnabled(!item.isDelete || deletesAllowed);
+                renderer.setEnabled(!item.isDestructive() || deletesAllowed);
             }
             renderer.setBorder(isSelected ? 
UIManager.getBorder("List.focusCellHighlightBorder") : noFocusBorder);
             return renderer;
@@ -259,18 +259,18 @@ public class ItemSelector<I extends Item> implements 
ListSelectionListener {
     
     public abstract static class Item implements Comparable<Item> {
         boolean isSelected;
-        private final boolean isDelete;
+        private final boolean isDestructive;
 
-        protected Item (boolean selected, boolean delete) {
+        protected Item (boolean selected, boolean isDestructive) {
             this.isSelected = selected;
-            this.isDelete = delete;
+            this.isDestructive = isDestructive;
         }
         
         public abstract String getText();
         public abstract String getTooltipText();
 
-        public final boolean isDeletion () {
-            return isDelete;
+        public final boolean isDestructive () {
+            return isDestructive;
         }
     }
     
diff --git a/ide/git/src/org/netbeans/modules/git/ui/selectors/ItemsPanel.form 
b/ide/git/src/org/netbeans/modules/git/ui/selectors/ItemsPanel.form
index f45c271328..7add25b43f 100644
--- a/ide/git/src/org/netbeans/modules/git/ui/selectors/ItemsPanel.form
+++ b/ide/git/src/org/netbeans/modules/git/ui/selectors/ItemsPanel.form
@@ -40,7 +40,7 @@
           <Group type="102" attributes="0">
               <EmptySpace max="-2" attributes="0"/>
               <Group type="103" groupAlignment="0" attributes="0">
-                  <Component id="jScrollPane1" alignment="0" pref="360" 
max="32767" attributes="0"/>
+                  <Component id="jScrollPane1" alignment="0" max="32767" 
attributes="0"/>
                   <Group type="102" attributes="0">
                       <Group type="103" groupAlignment="0" attributes="0">
                           <Component id="titleLabel" min="-2" max="-2" 
attributes="0"/>
@@ -49,7 +49,7 @@
                               <EmptySpace max="-2" attributes="0"/>
                               <Component id="btnSelectNone" min="-2" max="-2" 
attributes="0"/>
                               <EmptySpace max="-2" attributes="0"/>
-                              <Component id="btnAllowDeletes" min="-2" 
max="-2" attributes="0"/>
+                              <Component id="btnAllowDestructiveActions" 
min="-2" max="-2" attributes="0"/>
                           </Group>
                       </Group>
                       <EmptySpace min="0" pref="0" max="32767" attributes="0"/>
@@ -70,7 +70,7 @@
               <Group type="103" groupAlignment="0" attributes="0">
                   <Group type="103" alignment="0" groupAlignment="3" 
attributes="0">
                       <Component id="btnSelectNone" alignment="3" min="-2" 
max="-2" attributes="0"/>
-                      <Component id="btnAllowDeletes" alignment="3" min="-2" 
max="-2" attributes="0"/>
+                      <Component id="btnAllowDestructiveActions" alignment="3" 
min="-2" max="-2" attributes="0"/>
                   </Group>
                   <Component id="btnSelectAll" min="-2" max="-2" 
attributes="0"/>
               </Group>
@@ -141,13 +141,13 @@
         <AuxValue name="JavaCodeGenerator_VariableModifier" 
type="java.lang.Integer" value="0"/>
       </AuxValues>
     </Component>
-    <Component class="javax.swing.JButton" name="btnAllowDeletes">
+    <Component class="javax.swing.JButton" name="btnAllowDestructiveActions">
       <Properties>
         <Property name="text" type="java.lang.String" 
editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
-          <ResourceString 
bundle="org/netbeans/modules/git/ui/selectors/Bundle.properties" 
key="ItemsPanel.btnAllowDeletes.text" 
replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, 
&quot;{key}&quot;)"/>
+          <ResourceString 
bundle="org/netbeans/modules/git/ui/selectors/Bundle.properties" 
key="ItemsPanel.btnAllowDestructiveActions.text" 
replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, 
&quot;{key}&quot;)"/>
         </Property>
         <Property name="toolTipText" type="java.lang.String" 
editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
-          <ResourceString 
bundle="org/netbeans/modules/git/ui/selectors/Bundle.properties" 
key="ItemsPanel.btnAllowDeletes.text" 
replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, 
&quot;{key}&quot;)"/>
+          <ResourceString 
bundle="org/netbeans/modules/git/ui/selectors/Bundle.properties" 
key="ItemsPanel.btnAllowDestructiveActions.description" 
replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, 
&quot;{key}&quot;)"/>
         </Property>
       </Properties>
       <AuxValues>
diff --git a/ide/git/src/org/netbeans/modules/git/ui/selectors/ItemsPanel.java 
b/ide/git/src/org/netbeans/modules/git/ui/selectors/ItemsPanel.java
index 89716f18f0..d96760d1c9 100644
--- a/ide/git/src/org/netbeans/modules/git/ui/selectors/ItemsPanel.java
+++ b/ide/git/src/org/netbeans/modules/git/ui/selectors/ItemsPanel.java
@@ -65,8 +65,8 @@ public class ItemsPanel extends javax.swing.JPanel {
         
btnSelectAll.setToolTipText(org.openide.util.NbBundle.getMessage(ItemsPanel.class,
 "ItemsPanel.btnSelectAll.TTtext")); // NOI18N
         btnSelectAll.setEnabled(false);
 
-        org.openide.awt.Mnemonics.setLocalizedText(btnAllowDeletes, 
org.openide.util.NbBundle.getMessage(ItemsPanel.class, 
"ItemsPanel.btnAllowDeletes.text")); // NOI18N
-        
btnAllowDeletes.setToolTipText(org.openide.util.NbBundle.getMessage(ItemsPanel.class,
 "ItemsPanel.btnAllowDeletes.text")); // NOI18N
+        org.openide.awt.Mnemonics.setLocalizedText(btnAllowDestructiveActions, 
org.openide.util.NbBundle.getMessage(ItemsPanel.class, 
"ItemsPanel.btnAllowDestructiveActions.text")); // NOI18N
+        
btnAllowDestructiveActions.setToolTipText(org.openide.util.NbBundle.getMessage(ItemsPanel.class,
 "ItemsPanel.btnAllowDestructiveActions.description")); // NOI18N
 
         javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
         this.setLayout(layout);
@@ -75,7 +75,7 @@ public class ItemsPanel extends javax.swing.JPanel {
             .addGroup(layout.createSequentialGroup()
                 .addContainerGap()
                 
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-                    .addComponent(jScrollPane1, 
javax.swing.GroupLayout.DEFAULT_SIZE, 360, Short.MAX_VALUE)
+                    .addComponent(jScrollPane1)
                     .addGroup(layout.createSequentialGroup()
                         
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                             .addComponent(titleLabel)
@@ -84,7 +84,7 @@ public class ItemsPanel extends javax.swing.JPanel {
                                 
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                 .addComponent(btnSelectNone)
                                 
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
-                                .addComponent(btnAllowDeletes)))
+                                .addComponent(btnAllowDestructiveActions)))
                         .addGap(0, 0, Short.MAX_VALUE)))
                 .addContainerGap())
         );
@@ -99,13 +99,13 @@ public class ItemsPanel extends javax.swing.JPanel {
                 
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                     
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                         .addComponent(btnSelectNone)
-                        .addComponent(btnAllowDeletes))
+                        .addComponent(btnAllowDestructiveActions))
                     .addComponent(btnSelectAll))
                 .addContainerGap())
         );
     }// </editor-fold>//GEN-END:initComponents
     // Variables declaration - do not modify//GEN-BEGIN:variables
-    final javax.swing.JButton btnAllowDeletes = new javax.swing.JButton();
+    final javax.swing.JButton btnAllowDestructiveActions = new 
javax.swing.JButton();
     javax.swing.JButton btnSelectAll;
     javax.swing.JButton btnSelectNone;
     private javax.swing.JScrollPane jScrollPane1;
diff --git a/ide/git/src/org/netbeans/modules/git/utils/GitUtils.java 
b/ide/git/src/org/netbeans/modules/git/utils/GitUtils.java
index 874a9268bc..d4adf74092 100644
--- a/ide/git/src/org/netbeans/modules/git/utils/GitUtils.java
+++ b/ide/git/src/org/netbeans/modules/git/utils/GitUtils.java
@@ -835,6 +835,7 @@ public final class GitUtils {
     private static final String REF_SPEC_GLOBAL_PATTERN = 
"+refs/heads/*:refs/remotes/{0}/*"; //NOI18N
     public static final String REF_SPEC_DEL_PREFIX = ":refs/remotes/"; //NOI18N
     private static final String REF_PUSHSPEC_PATTERN = 
"refs/heads/{0}:refs/heads/{1}"; //NOI18N
+    private static final String REF_PUSHSPEC_PATTERN_FORCE = 
"+refs/heads/{0}:refs/heads/{1}"; //NOI18N
     public static final String REF_PUSHSPEC_DEL_PREFIX = ":refs/heads/"; 
//NOI18N
     public static final String REF_PUSHSPEC_DEL_TAG_PREFIX = ":refs/tags/"; 
//NOI18N
     private static final String REF_TAG_PUSHSPEC_PATTERN = 
"refs/tags/{0}:refs/tags/{0}"; //NOI18N
@@ -856,8 +857,10 @@ public final class GitUtils {
         return MessageFormat.format(REF_SPEC_PATTERN, branchName, remoteName);
     }
 
-    public static String getPushRefSpec (String branchName, String 
remoteRepositoryBranchName) {
-        return MessageFormat.format(REF_PUSHSPEC_PATTERN, branchName, 
remoteRepositoryBranchName);
+    public static String getPushRefSpec (String branchName, String 
remoteRepositoryBranchName, boolean forceUpdate) {
+        return MessageFormat.format(forceUpdate
+                ? REF_PUSHSPEC_PATTERN_FORCE
+                : REF_PUSHSPEC_PATTERN, branchName, 
remoteRepositoryBranchName);
     }
 
     public static String getPushDeletedRefSpec (String 
remoteRepositoryBranchName) {
diff --git a/ide/libs.git/apichanges.xml b/ide/libs.git/apichanges.xml
index d2e84c13b2..1f90d5ae02 100644
--- a/ide/libs.git/apichanges.xml
+++ b/ide/libs.git/apichanges.xml
@@ -85,6 +85,25 @@ is the proper place.
 
     <changes>
         
+        <change>
+            <api name="gitlibrary_api"/>
+            <summary>Enable forced pushing for branches</summary>
+            <version major="1" minor="58"/>
+            <date day="11" month="11" year="2023"/>
+            <author login="matthiasblaesing"/>
+            <compatibility modification="yes"/>
+            <description>
+                <ul>
+                    <li>
+                        PushCommand prevented forced pushes by overriding the
+                        force flag in the specification. This overriding
+                        behavior is removed and clients are now responsible to
+                        not specify a forced push if they don't intent one.
+                    </li>
+                </ul>
+            </description>
+            <class package="org.netbeans.libs.git.jgit.commands" 
name="PushCommand"/>
+        </change>
         <change>
             <api name="gitlibrary_api"/>
             <summary>API for git stash support.</summary>
diff --git a/ide/libs.git/manifest.mf b/ide/libs.git/manifest.mf
index 63052d6fcd..22429982ce 100644
--- a/ide/libs.git/manifest.mf
+++ b/ide/libs.git/manifest.mf
@@ -1,4 +1,4 @@
 Manifest-Version: 1.0
 OpenIDE-Module: org.netbeans.libs.git/1
 OpenIDE-Module-Localizing-Bundle: org/netbeans/libs/git/Bundle.properties
-OpenIDE-Module-Specification-Version: 1.57
+OpenIDE-Module-Specification-Version: 1.58
diff --git 
a/ide/libs.git/src/org/netbeans/libs/git/jgit/commands/PushCommand.java 
b/ide/libs.git/src/org/netbeans/libs/git/jgit/commands/PushCommand.java
index c73a82397e..96d98b6777 100644
--- a/ide/libs.git/src/org/netbeans/libs/git/jgit/commands/PushCommand.java
+++ b/ide/libs.git/src/org/netbeans/libs/git/jgit/commands/PushCommand.java
@@ -69,17 +69,7 @@ public class PushCommand extends TransportCommand {
     protected void runTransportCommand () throws 
GitException.AuthorizationException, GitException {
         List<RefSpec> specs = new ArrayList<RefSpec>(pushRefSpecs.size());
         for (String refSpec : pushRefSpecs) {
-            // this may be extra strict. We do not allow force updates for 
branches,
-            // but maybe we should leave that decision on the caller
-            RefSpec sp = new RefSpec(refSpec);
-            String source = sp.getSource();
-            String dest = sp.getDestination();
-            if (source != null && Transport.REFSPEC_TAGS.matchSource(source)
-                    && dest != null && 
Transport.REFSPEC_TAGS.matchDestination(sp.getDestination())) {
-                specs.add(sp);
-            } else {
-                specs.add(sp.setForceUpdate(false));
-            }
+            specs.add(new RefSpec(refSpec));
         }
         // this will ensure that refs/remotes/abc/branch will be updated, too
         List<RefSpec> fetchSpecs = new ArrayList<RefSpec>(fetchRefSpecs == 
null ? 0 : fetchRefSpecs.size());
diff --git 
a/ide/libs.git/test/unit/src/org/netbeans/libs/git/jgit/commands/PushTest.java 
b/ide/libs.git/test/unit/src/org/netbeans/libs/git/jgit/commands/PushTest.java
index f5ca3a7634..3d61d138db 100644
--- 
a/ide/libs.git/test/unit/src/org/netbeans/libs/git/jgit/commands/PushTest.java
+++ 
b/ide/libs.git/test/unit/src/org/netbeans/libs/git/jgit/commands/PushTest.java
@@ -250,7 +250,7 @@ public class PushTest extends AbstractGitTestCase {
         write(f, "huhu2");
         add(f);
         id = getClient(workDir).commit(new File[] { f }, "some change before 
merge", null, null, NULL_PROGRESS_MONITOR).getRevision();
-        updates = getClient(workDir).push(remoteUri, Arrays.asList(new 
String[] { "+refs/heads/localbranch:refs/heads/master" }), 
Collections.<String>emptyList(), 
NULL_PROGRESS_MONITOR).getRemoteRepositoryUpdates();
+        updates = getClient(workDir).push(remoteUri, Arrays.asList(new 
String[] { "refs/heads/localbranch:refs/heads/master" }), 
Collections.<String>emptyList(), 
NULL_PROGRESS_MONITOR).getRemoteRepositoryUpdates();
         remoteBranches = getClient(workDir).listRemoteBranches(remoteUri, 
NULL_PROGRESS_MONITOR);
         assertEquals(1, remoteBranches.size());
         assertEquals(newid, remoteBranches.get("master").getId());
@@ -263,7 +263,7 @@ public class PushTest extends AbstractGitTestCase {
         assertEquals(newid, remoteBranches.get("master").getId());
         assertEquals(1, updates.size());
         assertUpdate(updates.get("master"), "localbranch", "master", id, 
newid, new URIish(remoteUri).toString(), Type.BRANCH, 
GitRefUpdateResult.REJECTED_NONFASTFORWARD);
-        
+
         // if starts failing, the WA at GitTransportUpdate.(URIish uri, 
TrackingRefUpdate update) should be removed
         // this.result = GitRefUpdateResult.valueOf((update.getResult() == 
null ? RefUpdate.Result.NOT_ATTEMPTED : update.getResult()).name());
         Transport transport = 
Transport.open(getRepository(getClient(workDir)), new URIish(remoteUri));


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@netbeans.apache.org
For additional commands, e-mail: commits-h...@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists


Reply via email to