code: package org.rug.data.project;
  
  import org.apache.logging.log4j.LogManager;
  import org.apache.logging.log4j.Logger;
  import org.eclipse.jgit.api.CheckoutCommand;
  import org.eclipse.jgit.api.errors.GitAPIException;
  import org.eclipse.jgit.lib.ObjectId;
  import org.eclipse.jgit.lib.Repository;
  import org.rug.data.characteristics.comps.SourceCodeRetriever;
  
  import java.nio.file.Path;
  
  public class GitVersion extends AbstractVersion {
  
      private transient final static Logger logger = LogManager.getLogger(GitVersion.class);
  
      private transient Repository repository;
      private transient CheckoutCommand checkoutCommand;
      private String commitName;
      private boolean isCheckedOut;
  
      public GitVersion(Path path, Repository repository, CheckoutCommand checkoutCommand, SourceCodeRetriever sourceCodeRetriever){
          super(path, sourceCodeRetriever);
          this.checkoutCommand = checkoutCommand;
          this.repository = repository;
          this.isCheckedOut = false;
      }
  
  
      @Override
      public synchronized SourceCodeRetriever getSourceCodeRetriever() {
          if (!isCheckedOut) {
                  checkoutCommand.setName(commitName);
                  checkoutCommand.setForced(true);
                  try {
                      checkoutCommand.call();
                      isCheckedOut = true;
                  } catch (GitAPIException e) {
                      isCheckedOut = false;
                      logger.error("Could not checkout commit {} due a JGit unrecoverable exception: {}", commitName, e.getMessage());
                      throw new IllegalArgumentException("Could not checkout the given commit: " + commitName, e);
                  }
          }
          return super.getSourceCodeRetriever();
      }
  
      /**
       * Parses a file name (presumably of a GraphML file) that contains information
       * about the version in the following format:
       * {@code graph-#versionPosition-#day-#month-#year-#commitName.graphML}
       * Note that the file extension is not used.
       * @param f the path object to use for parsing the string version from the name.
       * @return the versionString of this version in the following format {@code #versionPosition-#commitName}.
       */
      @Override
      public String parseVersionString(Path f) {
          var fileName = f.getFileName().toString();
          int endIndex = f.toFile().isDirectory() ? fileName.length() : fileName.lastIndexOf('.');
          var splits = fileName.substring(0, endIndex).split("-");
          setVersionIndex(Long.parseLong(splits[1]));
          versionDate = String.join("-", splits[2].split("_"));
          commitName = splits[3];
          return String.join("-", String.valueOf(versionIndex), commitName);
      }
  
      /**
       * Retrieves the name of the commit represented by this version instance.
       * @return the SHA-1 commit id parsed during initialization.
       */
      public String getCommitName() {
          return commitName;
      }
  
      /**
       * Returns the current commit name as an object id.
       * @return an object id instance
       */
      public ObjectId getCommitObjectId(){
          return ObjectId.fromString(commitName);
      }
  
      public Repository getRepository() {
          return repository;
      }
  
      @Override
      public String toString() {
          return String.format("%s: %s", getVersionString(), getGraphMLPath().toString());
      }
  
  }
  