diff --git a/ide/git/src/org/netbeans/modules/git/ui/fetch/PullAction.java b/ide/git/src/org/netbeans/modules/git/ui/fetch/PullAction.java index fa95939931cd..d560a7fe8942 100644 --- a/ide/git/src/org/netbeans/modules/git/ui/fetch/PullAction.java +++ b/ide/git/src/org/netbeans/modules/git/ui/fetch/PullAction.java @@ -52,6 +52,7 @@ import org.netbeans.modules.git.ui.actions.ActionProgressSupport; import org.netbeans.modules.git.ui.actions.GitAction; import org.netbeans.modules.git.ui.actions.SingleRepositoryAction; +import org.netbeans.modules.git.ui.branch.SetTrackingAction; import org.netbeans.modules.git.ui.merge.MergeRevisionAction; import org.netbeans.modules.git.ui.output.OutputLogger; import org.netbeans.modules.git.ui.rebase.RebaseAction; @@ -65,6 +66,7 @@ import org.openide.awt.ActionRegistration; import org.openide.awt.Mnemonics; import org.openide.util.NbBundle; +import org.openide.util.actions.SystemAction; /** * @@ -107,6 +109,10 @@ public void run () { } private void pull (final File repository) { + pull(repository, null); + } + + public void pull (final File repository, final GitBranch branchToSelect) { RepositoryInfo info = RepositoryInfo.getInstance(repository); try { info.refreshRemotes(); @@ -117,7 +123,7 @@ private void pull (final File repository) { EventQueue.invokeLater(new Runnable() { @Override public void run () { - PullWizard wiz = new PullWizard(repository, remotes); + PullWizard wiz = new PullWizard(repository, remotes, branchToSelect); if (wiz.show()) { Utils.logVCSExternalRepository("GIT", wiz.getFetchUri()); //NOI18N pull(repository, wiz.getFetchUri(), wiz.getFetchRefSpecs(), wiz.getBranchToMerge(), wiz.getRemoteToPersist()); @@ -144,6 +150,7 @@ private static class GitProgressSupportImpl extends GitProgressSupport { private final String branchToMerge; private final String target; private final String remoteNameToUpdate; + private boolean pullSuccessful = false; public GitProgressSupportImpl (List fetchRefSpecs, String branchToMerge, String target, String remoteNameToUpdate) { this.fetchRefSpecs = fetchRefSpecs; @@ -182,48 +189,50 @@ protected void perform () { return; } } - GitUtils.runWithoutIndexing(new Callable() { - @Override - public Void call () throws Exception { - for (String branch : toDelete) { - client.deleteBranch(branch, true, getProgressMonitor()); - getLogger().outputLine(Bundle.MSG_PullAction_branchDeleted(branch)); - } - setDisplayName(Bundle.MSG_PullAction_fetching()); - Map fetchResult = FetchAction.fetchRepeatedly( - client, getProgressMonitor(), target, fetchRefSpecs); - if (isCanceled()) { - return null; + GitUtils.runWithoutIndexing(() -> { + for (String branch : toDelete) { + client.deleteBranch(branch, true, getProgressMonitor()); + getLogger().outputLine(Bundle.MSG_PullAction_branchDeleted(branch)); + } + setDisplayName(Bundle.MSG_PullAction_fetching()); + Map fetchResult = FetchAction.fetchRepeatedly( + client, getProgressMonitor(), target, fetchRefSpecs); + if (isCanceled()) { + return null; + } + FetchUtils.log(repository, fetchResult, getLogger()); + if (!isCanceled()) { + setDisplayName(Bundle.MSG_PullAction_progress_syncBranches()); + FetchUtils.syncTrackingBranches(repository, fetchResult, GitProgressSupportImpl.this, GitProgressSupportImpl.this.getProgress(), false); + } + if (isCanceled() || branchToMerge == null) { + return null; + } + new BranchSynchronizer(branchToMerge, repository, new BranchSynchronizer.GitProgressSupportDelegate() { + + @Override + public GitClient getClient () throws GitException { + return client; } - FetchUtils.log(repository, fetchResult, getLogger()); - if (!isCanceled()) { - setDisplayName(Bundle.MSG_PullAction_progress_syncBranches()); - FetchUtils.syncTrackingBranches(repository, fetchResult, GitProgressSupportImpl.this, GitProgressSupportImpl.this.getProgress(), false); + + @Override + public OutputLogger getLogger () { + return GitProgressSupportImpl.this.getLogger(); } - if (isCanceled() || branchToMerge == null) { - return null; + + @Override + public ProgressDelegate getProgress () { + return GitProgressSupportImpl.this.getProgress(); } - new BranchSynchronizer(branchToMerge, repository, new BranchSynchronizer.GitProgressSupportDelegate() { - - @Override - public GitClient getClient () throws GitException { - return client; - } - - @Override - public OutputLogger getLogger () { - return GitProgressSupportImpl.this.getLogger(); - } - - @Override - public ProgressDelegate getProgress () { - return GitProgressSupportImpl.this.getProgress(); - } - - }).execute(); - return null; + + }).execute(); + + if (!isCanceled()) { + pullSuccessful = true; } - }, repository); + + return null; + }, repository); } catch (GitException ex) { setError(true); GitClientExceptionHandler.notifyException(ex, true); @@ -231,6 +240,20 @@ public ProgressDelegate getProgress () { setDisplayName(NbBundle.getMessage(GitAction.class, "LBL_Progress.RefreshingStatuses")); //NOI18N Git.getInstance().getFileStatusCache().refreshAllRoots(Collections.>singletonMap(repository, Git.getInstance().getSeenRoots(repository))); GitUtils.headChanged(repository); + + // Check if tracking should be set up after successful pull + if (pullSuccessful && branchToMerge != null) { + RepositoryInfo info = RepositoryInfo.getInstance(repository); + info.refresh(); + GitBranch activeBranch = info.getActiveBranch(); + if (activeBranch != null && activeBranch.getTrackedBranch() == null) { + // branchToMerge is the remote branch name (e.g., "origin/master") + if (shallSetupTracking(activeBranch, branchToMerge)) { + SystemAction.get(SetTrackingAction.class).setupTrackedBranchImmediately( + repository, activeBranch.getName(), branchToMerge); + } + } + } } } } @@ -378,5 +401,17 @@ public ActionProgress call () throws GitException { } } } - + + @NbBundle.Messages({ + "LBL_Pull.setupTracking=Set Up Remote Tracking?", + "# {0} - remote branch name", "# {1} - branch name", "MSG_Pull.setupTracking=Pulled from \"{0}\".\n" + + "Do you want to set up branch \"{1}\" to track the remote branch?" + }) + private static boolean shallSetupTracking (GitBranch branch, String remoteBranchName) { + return NotifyDescriptor.YES_OPTION == DialogDisplayer.getDefault().notify(new NotifyDescriptor.Confirmation( + Bundle.MSG_Pull_setupTracking(remoteBranchName, branch.getName()), + Bundle.LBL_Pull_setupTracking(), + NotifyDescriptor.YES_NO_OPTION, NotifyDescriptor.QUESTION_MESSAGE)); + } + } 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 4d3704b82141..f4d08dcdc218 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 @@ -129,7 +129,11 @@ public void setRemote (GitRemoteConfig remote) { } public void fillRemoteBranches (final Map branches) { - fillRemoteBranches(Collections.emptyMap(), Collections.emptyMap()); + fillRemoteBranches(branches, null); + } + + public void fillRemoteBranches (final Map branches, final GitBranch branchToSelect) { + fillRemoteBranchesInternal(Collections.emptyMap(), Collections.emptyMap(), null); new GitProgressSupport.NoOutputLogging() { @Override protected void perform () { @@ -140,14 +144,14 @@ protected void perform () { EventQueue.invokeLater(new Runnable () { @Override public void run () { - fillRemoteBranches(branches, localBranches); + fillRemoteBranchesInternal(branches, localBranches, branchToSelect); } }); } }.start(Git.getInstance().getRequestProcessor(repository), repository, NbBundle.getMessage(PullBranchesStep.class, "MSG_FetchBranchesPanel.loadingLocalBranches")); //NOI18N } - private void fillRemoteBranches (Map branches, Map localBranches) { + private void fillRemoteBranchesInternal (Map branches, Map localBranches, GitBranch branchToSelect) { List l = new ArrayList(branches.size()); Set displayedBranches = new HashSet(localBranches.size()); for (GitBranch branch : localBranches.values()) { @@ -163,9 +167,14 @@ private void fillRemoteBranches (Map branches, Map 1) { + SystemAction.get(PullAction.class).pull(repository, activeBranch); + return; + } + if (trackedBranch == null) { return; } - GitRemoteConfig cfg = FetchUtils.getRemoteConfigForActiveBranch(trackedBranch, info, errorLabel); + + GitRemoteConfig cfg = FetchUtils.getRemoteConfigForActiveBranch(trackedBranch, info, errorLabel); if (cfg == null) { return; } diff --git a/ide/git/src/org/netbeans/modules/git/ui/fetch/PullWizard.java b/ide/git/src/org/netbeans/modules/git/ui/fetch/PullWizard.java index 572ba4eada1f..55c817b8ef9d 100644 --- a/ide/git/src/org/netbeans/modules/git/ui/fetch/PullWizard.java +++ b/ide/git/src/org/netbeans/modules/git/ui/fetch/PullWizard.java @@ -46,10 +46,16 @@ class PullWizard implements ChangeListener { private PanelsIterator wizardIterator; private WizardDescriptor wizardDescriptor; private final File repository; + private final GitBranch branchToSelect; public PullWizard (File repository, Map remotes) { + this(repository, remotes, null); + } + + public PullWizard (File repository, Map remotes, GitBranch branchToSelect) { this.repository = repository; this.remotes = remotes; + this.branchToSelect = branchToSelect; } boolean show () { @@ -154,7 +160,7 @@ public synchronized void nextPanel () { Map remoteBranches = selectUriStep.getRemoteBranches(); pullBranchesStep.setRemote(remote); if (remoteBranches != null) { - pullBranchesStep.fillRemoteBranches(remoteBranches); + pullBranchesStep.fillRemoteBranches(remoteBranches, branchToSelect); } selectUriStep.storeURI(); } 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 2418fec9e673..f2296a972e94 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 @@ -121,12 +121,13 @@ public void push (final File repository, GitRemoteConfig remote, Collection { + push(repository, branchToSelect); }); return; } @@ -140,7 +141,7 @@ public void run () { EventQueue.invokeLater(new Runnable() { @Override public void run () { - PushWizard wiz = new PushWizard(repository, remotes); + PushWizard wiz = new PushWizard(repository, remotes, branchToSelect); if (wiz.show()) { Utils.logVCSExternalRepository("GIT", wiz.getPushUri()); //NOI18N push(repository, wiz.getPushUri(), wiz.getPushMappings(), wiz.getFetchRefSpecs(), wiz.getRemoteName()); @@ -325,12 +326,7 @@ protected void logUpdates (File repository, Map upda logger.outputLine(Bundle.MSG_PushAction_updates_addBranch(update.getLocalName(), update.getNewObjectId(), update.getResult())); if (!remote && update.getNewObjectId() != null) { - int pos = update.getLocalName().indexOf('/'); - if (pos >= 0 && update.getLocalName().substring(pos + 1).equals(currBranch.getName())) { - if (shallSetupTracking(currBranch, update.getLocalName())) { - SystemAction.get(SetTrackingAction.class).setupTrackedBranchImmediately(repository, currBranch.getName(), update.getLocalName()); - } - } + callSetTrackingAction(update, currBranch, repository); } } else { logger.outputLine(Bundle.MSG_PushAction_updates_updateBranch(update.getRemoteName(), @@ -344,6 +340,11 @@ protected void logUpdates (File repository, Map upda update.getOldObjectId(), update.getNewObjectId(), logger); } } + + // Check if tracking should be set up for updated branches without tracking + if (!remote && update.getNewObjectId() != null && currBranch.getTrackedBranch() == null) { + callSetTrackingAction(update, currBranch, repository); + } } } else { //tag deleting or updating @@ -364,6 +365,15 @@ protected void logUpdates (File repository, Map upda } } } + + private void callSetTrackingAction(GitTransportUpdate update, GitBranch currBranch, File repository1) { + int pos = update.getLocalName().indexOf('/'); + if (pos >= 0 && update.getLocalName().substring(pos + 1).equals(currBranch.getName())) { + if (shallSetupTracking(currBranch, update.getLocalName())) { + SystemAction.get(SetTrackingAction.class).setupTrackedBranchImmediately(repository1, currBranch.getName(), update.getLocalName()); + } + } + } private void logTrackingUpdate (GitBranch b) { if (b != null && b.getTrackedBranch() != null) { 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 4925ef2ac24a..c540327522b8 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 @@ -106,6 +106,18 @@ public HelpCtx getHelp() { */ public void fillRemoteBranches (final GitRemoteConfig cfg, final Map branches, final Map tags) { + fillRemoteBranches(cfg, branches, tags, null); + } + + /** + * + * @param cfg configuration of the remote repository including URLs of remote + * @param branches list of all branches in the remote repo + * @param tags list of all tags in the remote repo + * @param branchToSelect branch that should be preselected in the list + */ + public void fillRemoteBranches (final GitRemoteConfig cfg, final Map branches, + final Map tags, final GitBranch branchToSelect) { fillLocalObjects(Collections.emptyList()); new GitProgressSupport.NoOutputLogging() { @Override @@ -162,6 +174,11 @@ protected void perform () { } boolean preselected = !conflicted && updateNeeded; + // If a specific branch should be selected, override preselection + if (branchToSelect != null && branch.getName().equals(branchToSelect.getName())) { + preselected = true; + } + //add current branch in the list for update or for adding l.add(new PushMapping.PushBranchMapping(remoteBranch == null ? null : remoteBranch.getName(), remoteBranch == null ? null : remoteBranch.getId(), 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 aeaf42541f0c..1af09292d310 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 @@ -47,7 +47,6 @@ 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; @@ -100,7 +99,13 @@ protected void perform () { } RepositoryInfo.PushMode pushMode = info.getPushMode(); GitBranch trackedBranch = getTrackedBranch(activeBranch, pushMode, errorLabel); - GitRemoteConfig cfg = getRemoteConfigForActiveBranch(trackedBranch, info, errorLabel); + + if (trackedBranch == null && info.getRemotes().size() > 1) { + SystemAction.get(PushAction.class).push(repository, activeBranch); + return; + } + + GitRemoteConfig cfg = getRemoteConfigForActiveBranch(trackedBranch, info, errorLabel); if (cfg == null) { return; } @@ -128,12 +133,14 @@ protected void perform () { 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())); + if (remoteBranch != null) { + 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 } @@ -193,7 +200,6 @@ protected static GitRemoteConfig getRemoteConfigForActiveBranch (GitBranch track GitUtils.notifyError(errorLabel, MSG_Err_noRemote()); return null; } else { - GitUtils.notifyError(errorLabel, MSG_Err_moreRemotes(remotes.size())); return null; } } else { 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 761310e2dbc5..ee5708090639 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 @@ -50,10 +50,16 @@ class PushWizard implements ChangeListener { private PanelsIterator wizardIterator; private WizardDescriptor wizardDescriptor; private final File repository; + private final GitBranch branchToSelect; public PushWizard (File repository, Map remotes) { + this(repository, remotes, null); + } + + public PushWizard (File repository, Map remotes, GitBranch branchToSelect) { this.repository = repository; this.remotes = remotes; + this.branchToSelect = branchToSelect; } boolean show () { @@ -161,7 +167,7 @@ public synchronized void nextPanel () { Map remoteTags = selectUriStep.getRemoteTags(); if (remoteBranches != null) { pushBranchesStep.fillRemoteBranches(selectUriStep.getSelectedRemote(), - remoteBranches, remoteTags == null ? Collections.emptyMap() : remoteTags); + remoteBranches, remoteTags == null ? Collections.emptyMap() : remoteTags, branchToSelect); } pushBranchesStep.setAsLastPanel(!selectUriStep.isConfiguredRemoteSelected() && selectUriStep.getRemoteName() == null); selectUriStep.storeURI();