View Javadoc
1   /*
2    * Copyright (C) 2011, Robin Stocker <robin@nibor.org>
3    * Copyright (C) 2012, Matthias Sohn <matthias.sohn@sap.com> and others
4    *
5    * This program and the accompanying materials are made available under the
6    * terms of the Eclipse Distribution License v. 1.0 which is available at
7    * https://www.eclipse.org/org/documents/edl-v10.php.
8    *
9    * SPDX-License-Identifier: BSD-3-Clause
10   */
11  
12  package org.eclipse.jgit.lib;
13  
14  import java.io.IOException;
15  
16  import org.eclipse.jgit.revwalk.RevCommit;
17  import org.eclipse.jgit.revwalk.RevWalk;
18  import org.eclipse.jgit.revwalk.RevWalkUtils;
19  import org.eclipse.jgit.revwalk.filter.RevFilter;
20  
21  /**
22   * Status of a branch's relation to its remote-tracking branch.
23   */
24  public class BranchTrackingStatus {
25  
26  	/**
27  	 * Compute the tracking status for the <code>branchName</code> in
28  	 * <code>repository</code>.
29  	 *
30  	 * @param repository
31  	 *            the git repository to compute the status from
32  	 * @param branchName
33  	 *            the local branch
34  	 * @return the tracking status, or null if it is not known
35  	 * @throws java.io.IOException
36  	 */
37  	public static BranchTrackingStatus of(Repository repository, String branchName)
38  			throws IOException {
39  
40  		String shortBranchName = Repository.shortenRefName(branchName);
41  		String fullBranchName = Constants.R_HEADS + shortBranchName;
42  		BranchConfig branchConfig = new BranchConfig(repository.getConfig(),
43  				shortBranchName);
44  
45  		String trackingBranch = branchConfig.getTrackingBranch();
46  		if (trackingBranch == null)
47  			return null;
48  
49  		Ref tracking = repository.exactRef(trackingBranch);
50  		if (tracking == null)
51  			return null;
52  
53  		Ref local = repository.exactRef(fullBranchName);
54  		if (local == null)
55  			return null;
56  
57  		try (RevWalk walk = new RevWalk(repository)) {
58  
59  			RevCommit localCommit = walk.parseCommit(local.getObjectId());
60  			RevCommit trackingCommit = walk.parseCommit(tracking.getObjectId());
61  
62  			walk.setRevFilter(RevFilter.MERGE_BASE);
63  			walk.markStart(localCommit);
64  			walk.markStart(trackingCommit);
65  			RevCommit mergeBase = walk.next();
66  
67  			walk.reset();
68  			walk.setRevFilter(RevFilter.ALL);
69  			int aheadCount = RevWalkUtils.count(walk, localCommit, mergeBase);
70  			int behindCount = RevWalkUtils.count(walk, trackingCommit,
71  					mergeBase);
72  
73  			return new BranchTrackingStatus(trackingBranch, aheadCount,
74  					behindCount);
75  		}
76  	}
77  
78  	private final String remoteTrackingBranch;
79  
80  	private final int aheadCount;
81  
82  	private final int behindCount;
83  
84  	private BranchTrackingStatus(String remoteTrackingBranch, int aheadCount,
85  			int behindCount) {
86  		this.remoteTrackingBranch = remoteTrackingBranch;
87  		this.aheadCount = aheadCount;
88  		this.behindCount = behindCount;
89  	}
90  
91  	/**
92  	 * Get full remote-tracking branch name
93  	 *
94  	 * @return full remote-tracking branch name
95  	 */
96  	public String getRemoteTrackingBranch() {
97  		return remoteTrackingBranch;
98  	}
99  
100 	/**
101 	 * Get number of commits that the local branch is ahead of the
102 	 * remote-tracking branch
103 	 *
104 	 * @return number of commits that the local branch is ahead of the
105 	 *         remote-tracking branch
106 	 */
107 	public int getAheadCount() {
108 		return aheadCount;
109 	}
110 
111 	/**
112 	 * Get number of commits that the local branch is behind of the
113 	 * remote-tracking branch
114 	 *
115 	 * @return number of commits that the local branch is behind of the
116 	 *         remote-tracking branch
117 	 */
118 	public int getBehindCount() {
119 		return behindCount;
120 	}
121 }