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, "{key}")"/> + <ResourceString bundle="org/netbeans/modules/git/ui/selectors/Bundle.properties" key="ItemsPanel.btnAllowDestructiveActions.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> </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, "{key}")"/> + <ResourceString bundle="org/netbeans/modules/git/ui/selectors/Bundle.properties" key="ItemsPanel.btnAllowDestructiveActions.description" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> </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