"" // | "" // | ||||
}, execute("git status")); // | }, execute("git status")); // | ||||
} | } | ||||
@Test | |||||
public void testStatusPorcelain() throws Exception { | |||||
Git git = new Git(db); | |||||
// Write all files | |||||
writeTrashFile("tracked", "tracked"); | |||||
writeTrashFile("stagedNew", "stagedNew"); | |||||
writeTrashFile("stagedModified", "stagedModified"); | |||||
writeTrashFile("stagedDeleted", "stagedDeleted"); | |||||
writeTrashFile("trackedModified", "trackedModified"); | |||||
writeTrashFile("trackedDeleted", "trackedDeleted"); | |||||
writeTrashFile("untracked", "untracked"); | |||||
// Test untracked | |||||
assertArrayOfLinesEquals(new String[] { // git status output | |||||
"?? stagedDeleted", // | |||||
"?? stagedModified", // | |||||
"?? stagedNew", // | |||||
"?? tracked", // | |||||
"?? trackedDeleted", // | |||||
"?? trackedModified", // | |||||
"?? untracked", // | |||||
"" // | |||||
}, execute("git status --porcelain")); // | |||||
// Add to index | |||||
git.add().addFilepattern("tracked").call(); | |||||
git.add().addFilepattern("stagedModified").call(); | |||||
git.add().addFilepattern("stagedDeleted").call(); | |||||
git.add().addFilepattern("trackedModified").call(); | |||||
git.add().addFilepattern("trackedDeleted").call(); | |||||
// Test staged count | |||||
assertArrayOfLinesEquals(new String[] { // git status output | |||||
"A stagedDeleted", // | |||||
"A stagedModified", // | |||||
"A tracked", // | |||||
"A trackedDeleted", // | |||||
"A trackedModified", // | |||||
"?? stagedNew", // | |||||
"?? untracked", // | |||||
"" // | |||||
}, execute("git status --porcelain")); // | |||||
// Commit | |||||
git.commit().setMessage("initial commit").call(); | |||||
assertArrayOfLinesEquals(new String[] { // git status output | |||||
"?? stagedNew", // | |||||
"?? untracked", // | |||||
"" // | |||||
}, execute("git status --porcelain")); // | |||||
// Make some changes and stage them | |||||
writeTrashFile("stagedModified", "stagedModified modified"); | |||||
deleteTrashFile("stagedDeleted"); | |||||
writeTrashFile("trackedModified", "trackedModified modified"); | |||||
deleteTrashFile("trackedDeleted"); | |||||
git.add().addFilepattern("stagedModified").call(); | |||||
git.rm().addFilepattern("stagedDeleted").call(); | |||||
git.add().addFilepattern("stagedNew").call(); | |||||
// Test staged/not-staged status | |||||
assertArrayOfLinesEquals(new String[] { // git status output | |||||
"D stagedDeleted", // | |||||
"M stagedModified", // | |||||
"A stagedNew", // | |||||
" D trackedDeleted", // | |||||
" M trackedModified", // | |||||
"?? untracked", // | |||||
"" // | |||||
}, execute("git status --porcelain")); // | |||||
// Create unmerged file | |||||
writeTrashFile("unmerged", "unmerged"); | |||||
git.add().addFilepattern("unmerged").call(); | |||||
// Commit pending changes | |||||
git.add().addFilepattern("trackedModified").call(); | |||||
git.rm().addFilepattern("trackedDeleted").call(); | |||||
git.commit().setMessage("commit before branching").call(); | |||||
assertArrayOfLinesEquals(new String[] { // git status output | |||||
"?? untracked", // | |||||
"" // | |||||
}, execute("git status --porcelain")); // | |||||
// Checkout new branch | |||||
git.checkout().setCreateBranch(true).setName("test").call(); | |||||
// Test branch status | |||||
assertArrayOfLinesEquals(new String[] { // git status output | |||||
"?? untracked", // | |||||
"" // | |||||
}, execute("git status --porcelain")); // | |||||
// Commit change and checkout master again | |||||
writeTrashFile("unmerged", "changed in test branch"); | |||||
git.add().addFilepattern("unmerged").call(); | |||||
RevCommit testBranch = git.commit() | |||||
.setMessage("changed unmerged in test branch").call(); | |||||
assertArrayOfLinesEquals(new String[] { // git status output | |||||
"?? untracked", // | |||||
"" // | |||||
}, execute("git status --porcelain")); // | |||||
git.checkout().setName("master").call(); | |||||
// Change the same file and commit | |||||
writeTrashFile("unmerged", "changed in master branch"); | |||||
git.add().addFilepattern("unmerged").call(); | |||||
git.commit().setMessage("changed unmerged in master branch").call(); | |||||
assertArrayOfLinesEquals(new String[] { // git status output | |||||
"?? untracked", // | |||||
"" // | |||||
}, execute("git status --porcelain")); // | |||||
// Merge test branch into master | |||||
git.merge().include(testBranch.getId()).call(); | |||||
// Test unmerged status | |||||
assertArrayOfLinesEquals(new String[] { // git status output | |||||
"UU unmerged", // | |||||
"?? untracked", // | |||||
"" // | |||||
}, execute("git status --porcelain")); // | |||||
// Test detached head | |||||
String commitId = db.getRef(Constants.MASTER).getObjectId().name(); | |||||
git.checkout().setName(commitId).call(); | |||||
assertArrayOfLinesEquals(new String[] { // git status output | |||||
"UU unmerged", // | |||||
"?? untracked", // | |||||
"" // | |||||
}, execute("git status --porcelain")); // | |||||
} | |||||
} | } |
usage_listBothRemoteTrackingAndLocalBranches=list both remote-tracking and local branches | usage_listBothRemoteTrackingAndLocalBranches=list both remote-tracking and local branches | ||||
usage_listCreateOrDeleteBranches=List, create, or delete branches | usage_listCreateOrDeleteBranches=List, create, or delete branches | ||||
usage_logAllPretty=format:%H %ct %P' output=log --all '--pretty=format:%H %ct %P' output | usage_logAllPretty=format:%H %ct %P' output=log --all '--pretty=format:%H %ct %P' output | ||||
usage_machineReadableOutput=machine-readable output | |||||
usage_manageReflogInformation=Manage reflog information | usage_manageReflogInformation=Manage reflog information | ||||
usage_mergeFf=When the merge resolves as a fast-forward, only update the branch pointer, without creating a merge commit. | usage_mergeFf=When the merge resolves as a fast-forward, only update the branch pointer, without creating a merge commit. | ||||
usage_mergeNoFf=Create a merge commit even when the merge resolves as a fast-forward. | usage_mergeNoFf=Create a merge commit even when the merge resolves as a fast-forward. |
import java.util.Collections; | import java.util.Collections; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | import java.util.Map; | ||||
import java.util.TreeSet; | |||||
import org.eclipse.jgit.api.Git; | import org.eclipse.jgit.api.Git; | ||||
import org.eclipse.jgit.api.StatusCommand; | import org.eclipse.jgit.api.StatusCommand; | ||||
protected final String statusFileListFormatUnmerged = CLIText.get().statusFileListFormatUnmerged; | protected final String statusFileListFormatUnmerged = CLIText.get().statusFileListFormatUnmerged; | ||||
@Option(name = "--porcelain", usage = "usage_machineReadableOutput") | |||||
protected boolean porcelain; | |||||
@Option(name = "--", metaVar = "metaVar_path", multiValued = true) | @Option(name = "--", metaVar = "metaVar_path", multiValued = true) | ||||
protected List<String> filterPaths; | protected List<String> filterPaths; | ||||
@Override | @Override | ||||
protected void run() throws Exception { | protected void run() throws Exception { | ||||
StatusCommand statusCommand = new Git(db).status(); | |||||
if (filterPaths != null && filterPaths.size() > 0) | |||||
for (String path : filterPaths) | |||||
statusCommand.addPath(path); | |||||
org.eclipse.jgit.api.Status status = statusCommand.call(); | |||||
printStatus(status); | |||||
} | |||||
private void printStatus(org.eclipse.jgit.api.Status status) | |||||
throws IOException { | |||||
if (porcelain) | |||||
printPorcelainStatus(status); | |||||
else | |||||
printLongStatus(status); | |||||
} | |||||
private void printPorcelainStatus(org.eclipse.jgit.api.Status status) | |||||
throws IOException { | |||||
Collection<String> added = status.getAdded(); | |||||
Collection<String> changed = status.getChanged(); | |||||
Collection<String> removed = status.getRemoved(); | |||||
Collection<String> modified = status.getModified(); | |||||
Collection<String> missing = status.getMissing(); | |||||
Map<String, StageState> conflicting = status.getConflictingStageState(); | |||||
// build a sorted list of all paths except untracked and ignored | |||||
TreeSet<String> sorted = new TreeSet<String>(); | |||||
sorted.addAll(added); | |||||
sorted.addAll(changed); | |||||
sorted.addAll(removed); | |||||
sorted.addAll(modified); | |||||
sorted.addAll(missing); | |||||
sorted.addAll(conflicting.keySet()); | |||||
// list each path | |||||
for (String path : sorted) { | |||||
char x = ' '; | |||||
char y = ' '; | |||||
if (added.contains(path)) | |||||
x = 'A'; | |||||
else if (changed.contains(path)) | |||||
x = 'M'; | |||||
else if (removed.contains(path)) | |||||
x = 'D'; | |||||
if (modified.contains(path)) | |||||
y = 'M'; | |||||
else if (missing.contains(path)) | |||||
y = 'D'; | |||||
if (conflicting.containsKey(path)) { | |||||
StageState stageState = conflicting.get(path); | |||||
switch (stageState) { | |||||
case BOTH_DELETED: | |||||
x = 'D'; | |||||
y = 'D'; | |||||
break; | |||||
case ADDED_BY_US: | |||||
x = 'A'; | |||||
y = 'U'; | |||||
break; | |||||
case DELETED_BY_THEM: | |||||
x = 'U'; | |||||
y = 'D'; | |||||
break; | |||||
case ADDED_BY_THEM: | |||||
x = 'U'; | |||||
y = 'A'; | |||||
break; | |||||
case DELETED_BY_US: | |||||
x = 'D'; | |||||
y = 'U'; | |||||
break; | |||||
case BOTH_ADDED: | |||||
x = 'A'; | |||||
y = 'A'; | |||||
break; | |||||
case BOTH_MODIFIED: | |||||
x = 'U'; | |||||
y = 'U'; | |||||
break; | |||||
default: | |||||
throw new IllegalArgumentException("Unknown StageState: " //$NON-NLS-1$ | |||||
+ stageState); | |||||
} | |||||
} | |||||
printPorcelainLine(x, y, path); | |||||
} | |||||
// untracked are always at the end of the list | |||||
TreeSet<String> untracked = new TreeSet<String>(status.getUntracked()); | |||||
for (String path : untracked) | |||||
printPorcelainLine('?', '?', path); | |||||
} | |||||
private void printPorcelainLine(char x, char y, String path) | |||||
throws IOException { | |||||
StringBuilder lineBuilder = new StringBuilder(); | |||||
lineBuilder.append(x).append(y).append(' ').append(path); | |||||
outw.println(lineBuilder.toString()); | |||||
} | |||||
private void printLongStatus(org.eclipse.jgit.api.Status status) | |||||
throws IOException { | |||||
// Print current branch name | // Print current branch name | ||||
final Ref head = db.getRef(Constants.HEAD); | final Ref head = db.getRef(Constants.HEAD); | ||||
boolean firstHeader = true; | |||||
if (head != null && head.isSymbolic()) { | if (head != null && head.isSymbolic()) { | ||||
String branch = Repository.shortenRefName(head.getLeaf().getName()); | String branch = Repository.shortenRefName(head.getLeaf().getName()); | ||||
outw.println(CLIText.formatLine( | |||||
MessageFormat.format(CLIText.get().onBranch, branch))); | |||||
outw.println(CLIText.formatLine(MessageFormat.format( | |||||
CLIText.get().onBranch, branch))); | |||||
} else | } else | ||||
outw.println(CLIText.formatLine(CLIText.get().notOnAnyBranch)); | outw.println(CLIText.formatLine(CLIText.get().notOnAnyBranch)); | ||||
// List changes | // List changes | ||||
StatusCommand statusCommand = new Git(db).status(); | |||||
if (filterPaths != null && filterPaths.size() > 0) | |||||
for (String path : filterPaths) | |||||
statusCommand.addPath(path); | |||||
org.eclipse.jgit.api.Status status = statusCommand.call(); | |||||
boolean firstHeader = true; | |||||
Collection<String> added = status.getAdded(); | Collection<String> added = status.getAdded(); | ||||
Collection<String> changed = status.getChanged(); | Collection<String> changed = status.getChanged(); | ||||
Collection<String> removed = status.getRemoved(); | Collection<String> removed = status.getRemoved(); |