2 * Copyright (C) 2008, Google Inc.
6 * Redistribution and use in source and binary forms, with or
7 * without modification, are permitted provided that the following
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * - Neither the name of the Git Development Community nor the
19 * names of its contributors may be used to endorse or promote
20 * products derived from this software without specific prior
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
24 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
25 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
28 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 package org
.spearce
.jgit
.merge
;
40 import java
.io
.IOException
;
42 import org
.spearce
.jgit
.errors
.IncorrectObjectTypeException
;
43 import org
.spearce
.jgit
.lib
.AnyObjectId
;
44 import org
.spearce
.jgit
.lib
.Constants
;
45 import org
.spearce
.jgit
.lib
.ObjectId
;
46 import org
.spearce
.jgit
.lib
.ObjectWriter
;
47 import org
.spearce
.jgit
.lib
.Repository
;
48 import org
.spearce
.jgit
.lib
.WindowCursor
;
49 import org
.spearce
.jgit
.revwalk
.RevCommit
;
50 import org
.spearce
.jgit
.revwalk
.RevObject
;
51 import org
.spearce
.jgit
.revwalk
.RevTree
;
52 import org
.spearce
.jgit
.revwalk
.RevWalk
;
53 import org
.spearce
.jgit
.revwalk
.filter
.RevFilter
;
54 import org
.spearce
.jgit
.treewalk
.AbstractTreeIterator
;
55 import org
.spearce
.jgit
.treewalk
.CanonicalTreeParser
;
56 import org
.spearce
.jgit
.treewalk
.EmptyTreeIterator
;
59 * Instance of a specific {@link MergeStrategy} for a single {@link Repository}.
61 public abstract class Merger
{
62 /** The repository this merger operates on. */
63 protected final Repository db
;
65 /** A RevWalk for computing merge bases, or listing incoming commits. */
66 protected final RevWalk walk
;
68 private ObjectWriter writer
;
70 /** The original objects supplied in the merge; this can be any tree-ish. */
71 protected RevObject
[] sourceObjects
;
73 /** If {@link #sourceObjects}[i] is a commit, this is the commit. */
74 protected RevCommit
[] sourceCommits
;
76 /** The trees matching every entry in {@link #sourceObjects}. */
77 protected RevTree
[] sourceTrees
;
80 * Create a new merge instance for a repository.
83 * the repository this merger will read and write data on.
85 protected Merger(final Repository local
) {
87 walk
= new RevWalk(db
);
91 * @return the repository this merger operates on.
93 public Repository
getRepository() {
98 * @return an object writer to create objects in {@link #getRepository()}.
100 public ObjectWriter
getObjectWriter() {
102 writer
= new ObjectWriter(getRepository());
107 * Merge together two or more tree-ish objects.
109 * Any tree-ish may be supplied as inputs. Commits and/or tags pointing at
110 * trees or commits may be passed as input objects.
113 * source trees to be combined together. The merge base is not
114 * included in this set.
115 * @return true if the merge was completed without conflicts; false if the
116 * merge strategy cannot handle this merge or there were conflicts
117 * preventing it from automatically resolving all paths.
118 * @throws IncorrectObjectTypeException
119 * one of the input objects is not a commit, but the strategy
120 * requires it to be a commit.
121 * @throws IOException
122 * one or more sources could not be read, or outputs could not
123 * be written to the Repository.
125 public boolean merge(final AnyObjectId
[] tips
) throws IOException
{
126 sourceObjects
= new RevObject
[tips
.length
];
127 for (int i
= 0; i
< tips
.length
; i
++)
128 sourceObjects
[i
] = walk
.parseAny(tips
[i
]);
130 sourceCommits
= new RevCommit
[sourceObjects
.length
];
131 for (int i
= 0; i
< sourceObjects
.length
; i
++) {
133 sourceCommits
[i
] = walk
.parseCommit(sourceObjects
[i
]);
134 } catch (IncorrectObjectTypeException err
) {
135 sourceCommits
[i
] = null;
139 sourceTrees
= new RevTree
[sourceObjects
.length
];
140 for (int i
= 0; i
< sourceObjects
.length
; i
++)
141 sourceTrees
[i
] = walk
.parseTree(sourceObjects
[i
]);
147 * Create an iterator to walk the merge base of two commits.
150 * index of the first commit in {@link #sourceObjects}.
152 * index of the second commit in {@link #sourceObjects}.
153 * @return the new iterator
154 * @throws IncorrectObjectTypeException
155 * one of the input objects is not a commit.
156 * @throws IOException
157 * objects are missing or multiple merge bases were found.
159 protected AbstractTreeIterator
mergeBase(final int aIdx
, final int bIdx
)
161 if (sourceCommits
[aIdx
] == null)
162 throw new IncorrectObjectTypeException(sourceObjects
[aIdx
],
163 Constants
.TYPE_COMMIT
);
164 if (sourceCommits
[bIdx
] == null)
165 throw new IncorrectObjectTypeException(sourceObjects
[bIdx
],
166 Constants
.TYPE_COMMIT
);
169 walk
.setRevFilter(RevFilter
.MERGE_BASE
);
170 walk
.markStart(sourceCommits
[aIdx
]);
171 walk
.markStart(sourceCommits
[bIdx
]);
172 final RevCommit base
= walk
.next();
174 return new EmptyTreeIterator();
175 final RevCommit base2
= walk
.next();
177 throw new IOException("Multiple merge bases for:" + "\n "
178 + sourceCommits
[aIdx
].name() + "\n "
179 + sourceCommits
[bIdx
].name() + "found:" + "\n "
180 + base
.name() + "\n " + base2
.name());
182 return openTree(base
.getTree());
186 * Open an iterator over a tree.
189 * the tree to scan; must be a tree (not a treeish).
190 * @return an iterator for the tree.
191 * @throws IncorrectObjectTypeException
192 * the input object is not a tree.
193 * @throws IOException
194 * the tree object is not found or cannot be read.
196 protected AbstractTreeIterator
openTree(final AnyObjectId treeId
)
197 throws IncorrectObjectTypeException
, IOException
{
198 final WindowCursor curs
= new WindowCursor();
200 return new CanonicalTreeParser(null, db
, treeId
, curs
);
209 * This method is called from {@link #merge(AnyObjectId[])} after the
210 * {@link #sourceObjects}, {@link #sourceCommits} and {@link #sourceTrees}
211 * have been populated.
213 * @return true if the merge was completed without conflicts; false if the
214 * merge strategy cannot handle this merge or there were conflicts
215 * preventing it from automatically resolving all paths.
216 * @throws IncorrectObjectTypeException
217 * one of the input objects is not a commit, but the strategy
218 * requires it to be a commit.
219 * @throws IOException
220 * one or more sources could not be read, or outputs could not
221 * be written to the Repository.
223 protected abstract boolean mergeImpl() throws IOException
;
226 * @return resulting tree, if {@link #merge(AnyObjectId[])} returned true.
228 public abstract ObjectId
getResultTreeId();