diff --git a/src/de/uni_passau/fim/seibt/gitwrapper/repo/Commit.java b/src/de/uni_passau/fim/seibt/gitwrapper/repo/Commit.java
index ffb2a39c58ef5f5f67a13c3f4630d99d1a58e95b..7d240900848ebded71ece2ead38d492db4464e44 100644
--- a/src/de/uni_passau/fim/seibt/gitwrapper/repo/Commit.java
+++ b/src/de/uni_passau/fim/seibt/gitwrapper/repo/Commit.java
@@ -50,7 +50,7 @@ public class Commit {
             LOG.fine(() -> String.format("Found %d parents for %s.", ids.length - 1, this));
             LOG.finer(() -> String.format("Commit id and parents are:%n%s", String.join(System.lineSeparator(), id)));
 
-            return Arrays.stream(ids).skip(1).map(repo::getCommit).collect(Collectors.toList());
+            return Arrays.stream(ids).skip(1).map(repo::getCommitUnchecked).collect(Collectors.toList());
         };
 
         return revList.map(toParentsList).orElse(Collections.emptyList());
@@ -83,7 +83,7 @@ public class Commit {
                 return null;
             }
 
-            Commit base = repo.getCommit(res.output.trim());
+            Commit base = repo.getCommitUnchecked(res.output.trim());
 
             LOG.fine(() -> String.format("Commits %s and %s have the merge base %s.", this, other, base));
 
diff --git a/src/de/uni_passau/fim/seibt/gitwrapper/repo/Repository.java b/src/de/uni_passau/fim/seibt/gitwrapper/repo/Repository.java
index ebc9760587145e017c092eccff7053903de4e809..4d103af3c80246d750088f84cd14556b39ff473c 100644
--- a/src/de/uni_passau/fim/seibt/gitwrapper/repo/Repository.java
+++ b/src/de/uni_passau/fim/seibt/gitwrapper/repo/Repository.java
@@ -23,6 +23,8 @@ public class Repository {
 
     private static final Logger LOG = Logger.getLogger(Repository.class.getCanonicalName());
 
+    private static final String TYPE_COMMIT = "commit";
+
     private GitWrapper git;
 
     private String url;
@@ -73,23 +75,95 @@ public class Repository {
             LOG.fine(() -> String.format("Found %d merge commits in %s.", lines.length, this));
             LOG.finer(() -> String.format("Merge commits are:%n%s", String.join(System.lineSeparator(), lines)));
 
-            return Arrays.stream(lines).map(this::getCommit).collect(Collectors.toList());
+            return Arrays.stream(lines).map(this::getCommitUnchecked).collect(Collectors.toList());
         };
 
         return revList.map(toCommitList).orElse(Collections.emptyList());
     }
 
     /**
-     * Returns a {@link Commit} for the given id. The <code>id</code> is not checked for validity, this method
-     * only ensures that only one {@link Commit} object is created for every <code>id</code>.
+     * Returns a {@link Commit} for the given ID. The caller must ensure that the ID is a full SHA1 hash of a
+     * commit that exists in this repository.
      *
-     * @param id the ID of the commit
+     * @param id the ID for the {@link Commit}
      * @return the {@link Commit}
      */
-    public Commit getCommit(String id) {
+    Commit getCommitUnchecked(String id) {
         return commits.computeIfAbsent(id, theID -> new Commit(this, theID));
     }
 
+    /**
+     * Returns a {@link Commit} for the given ID. If the given ID does not designate a commit that exists in this
+     * {@link Repository} an empty {@link Optional} will be returned. The ID will be resolved to a full SHA1 hash.
+     *
+     * @param id the ID of the commit
+     * @return the {@link Commit} or an empty {@link Optional} if the ID is invalid or an exception occurs
+     */
+    public Optional<Commit> getCommit(String id) {
+
+        if (commits.containsKey(id)) {
+            return Optional.of(commits.get(id));
+        }
+
+        if (!isCommit(id)) {
+            return Optional.empty();
+        }
+
+        return toHash(id).map(fullID -> commits.put(fullID, new Commit(this, fullID)));
+    }
+
+    /**
+     * Determines whether the given object ID designates a commit.
+     *
+     * @param id
+     *         the ID to check
+     * @return true iff the ID designates a commit
+     */
+    private boolean isCommit(String id) {
+        Optional<ExecRes> catFile = git.exec(dir, "cat-file", "-t", id);
+        Function<ExecRes, Boolean> toBoolean = res -> {
+
+            if (git.failed(res)) {
+                LOG.warning(() -> String.format("Failed to determine whether %s is a valid commit id.", id));
+                return null;
+            }
+
+            boolean isCommit = res.output.startsWith(TYPE_COMMIT);
+
+            if (isCommit) {
+                LOG.finer(() -> String.format("%s is a commit.", id));
+            }
+
+            return isCommit;
+        };
+
+        return catFile.map(toBoolean).orElse(false);
+    }
+
+    /**
+     * Resolves the given <code>id</code> to the full SHA1 hash.
+     *
+     * @param id
+     *         the <code>id</code> to transform
+     * @return the full SHA1 hash or an empty {@link Optional} if an exception occurs
+     */
+    private Optional<String> toHash(String id) {
+        Optional<ExecRes> revParse = git.exec(dir, "rev-parse", id);
+        Function<ExecRes, String> toHash = res -> {
+
+            if (git.failed(res)) {
+                LOG.warning(() -> String.format("Failed to resolve %s to its unique SHA1 hash.", id));
+                return null;
+            }
+
+            LOG.finer(() -> String.format("Resolved %s to %s.", id, res.output));
+
+            return res.output;
+        };
+
+        return revParse.map(toHash);
+    }
+
     /**
      * Returns the {@link GitWrapper} used by this {@link Repository}.
      *