comparison src/org/tmatesoft/hg/repo/HgMergeState.java @ 341:75c452fdd76a

Merging state not detected when there's no conflicts to resolve (no merge/state file)
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Thu, 17 Nov 2011 07:04:58 +0100
parents f74e36b7344b
children a0864b2892cd
comparison
equal deleted inserted replaced
340:a54bfe0db959 341:75c452fdd76a
91 repo = hgRepo; 91 repo = hgRepo;
92 } 92 }
93 93
94 public void refresh() throws IOException/*XXX it's unlikely caller can do anything reasonable about IOException */ { 94 public void refresh() throws IOException/*XXX it's unlikely caller can do anything reasonable about IOException */ {
95 entries = null; 95 entries = null;
96 wcp1 = wcp2 = stateParent = Nodeid.NULL; 96 // it's possible there are two parents but no merge/state, we shall report this case as 'merging', with proper
97 // first and second parent values
98 stateParent = Nodeid.NULL;
99 Pool<Nodeid> nodeidPool = new Pool<Nodeid>();
100 Pool<Path> fnamePool = new Pool<Path>();
101 Pair<Nodeid, Nodeid> wcParents = repo.getWorkingCopyParents();
102 wcp1 = nodeidPool.unify(wcParents.first()); wcp2 = nodeidPool.unify(wcParents.second());
97 final File f = new File(repo.getRepositoryRoot(), "merge/state"); 103 final File f = new File(repo.getRepositoryRoot(), "merge/state");
98 if (!f.canRead()) { 104 if (!f.canRead()) {
99 // empty state 105 // empty state
100 return; 106 return;
101 } 107 }
102 Pool<Nodeid> nodeidPool = new Pool<Nodeid>();
103 Pool<Path> fnamePool = new Pool<Path>();
104 Pair<Nodeid, Nodeid> wcParents = repo.getWorkingCopyParents();
105 wcp1 = nodeidPool.unify(wcParents.first()); wcp2 = nodeidPool.unify(wcParents.second());
106 ArrayList<Entry> result = new ArrayList<Entry>(); 108 ArrayList<Entry> result = new ArrayList<Entry>();
107 // FIXME need to settle use of Pool<Path> and PathPool 109 // FIXME need to settle use of Pool<Path> and PathPool
108 // latter is pool that can create objects on demand, former is just cache 110 // latter is pool that can create objects on demand, former is just cache
109 PathPool pathPool = new PathPool(new PathRewrite.Empty()); 111 PathPool pathPool = new PathPool(new PathRewrite.Empty());
110 final ManifestRevision m1 = new ManifestRevision(nodeidPool, fnamePool); 112 final ManifestRevision m1 = new ManifestRevision(nodeidPool, fnamePool);
157 entries = result.toArray(new Entry[result.size()]); 159 entries = result.toArray(new Entry[result.size()]);
158 br.close(); 160 br.close();
159 pathPool.clear(); 161 pathPool.clear();
160 } 162 }
161 163
162 164 /**
165 * Repository is in 'merging' state when changeset to be committed got two parents.
166 * This method doesn't tell whether there are (un)resolved conflicts in the working copy,
167 * use {@link #getConflicts()} (which makes sense only when {@link #isStale()} is <code>false</code>).
168 * @return <code>true</code> when repository is being merged
169 */
163 public boolean isMerging() { 170 public boolean isMerging() {
164 return !getFirstParent().isNull() && !getSecondParent().isNull() && !isStale(); 171 return !getFirstParent().isNull() && !getSecondParent().isNull() && !isStale();
165 } 172 }
166 173
167 /** 174 /**
175 * Merge state file may not match actual working copy due to rollback or undo operations.
176 * Value of {@link #getConflicts()} is reasonable iff this method returned <code>false</code>.
177 *
168 * @return <code>true</code> when recorded merge state doesn't seem to correspond to present working copy 178 * @return <code>true</code> when recorded merge state doesn't seem to correspond to present working copy
169 */ 179 */
170 public boolean isStale() { 180 public boolean isStale() {
171 if (wcp1 == null) { 181 if (wcp1 == null) {
172 throw new HgBadStateException("Call #refresh() first"); 182 throw new HgBadStateException("Call #refresh() first");
173 } 183 }
174 return !wcp1.equals(stateParent); 184 return !stateParent.isNull() /*there's merge state*/ && !wcp1.equals(stateParent) /*and it doesn't match*/;
175 } 185 }
176 186
177 /** 187 /**
178 * FIXME decide what to return if there's no merge state altogether (perhaps, separate method to check that) 188 * It's possible for a repository to be in a 'merging' state (@see {@link #isMerging()} without any
179 * @return never <code>null</code> 189 * conflict to resolve (no merge state information file).
190 * @return first parent of the working copy, never <code>null</code>
180 */ 191 */
181 public Nodeid getFirstParent() { 192 public Nodeid getFirstParent() {
182 if (wcp1 == null) { 193 if (wcp1 == null) {
183 throw new HgBadStateException("Call #refresh() first"); 194 throw new HgBadStateException("Call #refresh() first");
184 } 195 }
185 return wcp1; 196 return wcp1;
186 } 197 }
187 198
199 /**
200 * @return second parent of the working copy, never <code>null</code>
201 */
188 public Nodeid getSecondParent() { 202 public Nodeid getSecondParent() {
189 if (wcp2 == null) { 203 if (wcp2 == null) {
190 throw new HgBadStateException("Call #refresh() first"); 204 throw new HgBadStateException("Call #refresh() first");
191 } 205 }
192 return wcp2; 206 return wcp2;
200 throw new HgBadStateException("Call #refresh() first"); 214 throw new HgBadStateException("Call #refresh() first");
201 } 215 }
202 return stateParent; 216 return stateParent;
203 } 217 }
204 218
219 /**
220 * List of conflicts as recorded in the merge state information file.
221 * Note, this information is valid unless {@link #isStale()} is <code>true</code>.
222 *
223 * @return non-<code>null</code> list with both resolved and unresolved conflicts.
224 */
205 public List<Entry> getConflicts() { 225 public List<Entry> getConflicts() {
206 return entries == null ? Collections.<Entry>emptyList() : Arrays.asList(entries); 226 return entries == null ? Collections.<Entry>emptyList() : Arrays.asList(entries);
207 } 227 }
208 } 228 }