Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added GitHash.class
Binary file not shown.
104 changes: 95 additions & 9 deletions GitHash.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,26 @@
import java.nio.file.Files;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;

import java.util.Comparator;
import java.util.Date;
import java.util.PriorityQueue;


public class GitHash {

// Create directories
public static void gitRepoInit() throws IOException {
public static void init() throws IOException {
GitHash.createDirectoryIfMissing("git");
GitHash.createDirectoryIfMissing("git/objects");
GitHash.createFileIfMissing("git/HEAD");
GitHash.createFileIfMissing("git/INDEX");
}

// Create directories
public static void gitRepoInit() throws IOException {
init();
System.out.println("Git Repository Created");
}

Expand Down Expand Up @@ -50,8 +56,34 @@ public static void createFileIfMissing(String path) throws IOException {

public static void add(String filePath) throws IOException {
File f = new File(filePath);
createBLOBAndAddToObjects(f);
addBLOBEntryToIndex(filePath);
if (!f.exists()) {
throw new IOException("File does not exist: " + filePath);
}
if (f.isDirectory()) {
throw new IOException("Cannot add directory: " + filePath);
}

if (!isFileInIndex(filePath)) {
createBLOBAndAddToObjects(f);
addBLOBEntryToIndex(filePath);
}
}

public static boolean isFileInIndex(String filePath) throws IOException {
File indexFile = new File("git/INDEX");
if (!indexFile.exists()) {
return false;
}
BufferedReader br = new BufferedReader(new FileReader(indexFile));
String line;
while ((line = br.readLine()) != null) {
if (line.contains(" ./" + filePath)) {
br.close();
return true;
}
}
br.close();
return false;
}

public static String generateSHA1FromString(String contents) throws IOException {
Expand Down Expand Up @@ -190,19 +222,24 @@ public static PriorityQueue<WorkingDirectoryInfo> convertIndexToWorkingDirectory

// Goes through dirs in priority order (as mentioned above) and converts the contents into object
public static void convertNestedDirs(PriorityQueue<WorkingDirectoryInfo> wd) throws IOException {
if (wd.peek().size() != -1) {
if (!wd.isEmpty()) {
ArrayList<WorkingDirectoryInfo> nestedFolders = new ArrayList<>();
nestedFolders.add(wd.poll());

WorkingDirectoryInfo currFolder = nestedFolders.get(0);

while (wd.peek() != null && wd.peek().isInSameFolder(currFolder)) {
while (!wd.isEmpty() && wd.peek().isInSameFolder(currFolder)) {
nestedFolders.add(wd.poll());
}

String hash = writeTreeFile(convertContentsToString(nestedFolders));
wd.add(new WorkingDirectoryInfo("tree", hash, currFolder.getStringPath()));
convertNestedDirs(wd);
if (currFolder.size() == -1) {
writeWorkingListFile(convertContentsToString(nestedFolders));
return;
} else {
String hash = writeTreeFile(convertContentsToString(nestedFolders));
wd.add(new WorkingDirectoryInfo("tree", hash, currFolder.getStringPath()));
convertNestedDirs(wd);
}
}

}
Expand Down Expand Up @@ -278,4 +315,53 @@ public static String writeTreeFile(String contents) throws IOException {

}

// writes the final working list to a file named "workingList"
public static void writeWorkingListFile(String contents) throws IOException {
File workingListFile = new File("./git/objects/workingList");
BufferedWriter bw = new BufferedWriter(new FileWriter(workingListFile));
bw.write(contents);
bw.close();
}

// creates a commit file with author, message, root tree hash, and previous commit
public static String commit(String author, String message) throws IOException {
stageFolders();
BufferedReader br = new BufferedReader(new FileReader("./git/objects/workingList"));
String rootTreeContent = br.readLine();
br.close();
String rootTreeHash = generateSHA1FromString(rootTreeContent);
String previousCommit = "";
File headFile = new File("./git/HEAD");
if (headFile.exists() && headFile.length() > 0) {
BufferedReader headReader = new BufferedReader(new FileReader(headFile));
String headContent = headReader.readLine();
headReader.close();
if (headContent != null && !headContent.trim().isEmpty()) {
File previousCommitFile = new File("./git/objects/" + headContent.trim());
if (previousCommitFile.exists()) {
previousCommit = headContent.trim();
}
}
}

// https://docs.oracle.com/javase/8/docs/api/java/text/SimpleDateFormat.html
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy");
String currentDate = sdf.format(new Date());
StringBuilder commitContent = new StringBuilder();
commitContent.append("tree: ").append(rootTreeHash).append("\n");
commitContent.append("parent: ").append(previousCommit).append("\n");
commitContent.append("author: ").append(author).append("\n");
commitContent.append("date: ").append(currentDate).append("\n");
commitContent.append("summary: ").append(message);
String commitHash = generateSHA1FromString(commitContent.toString());
File commitFile = new File("./git/objects/" + commitHash);
BufferedWriter commitWriter = new BufferedWriter(new FileWriter(commitFile));
commitWriter.write(commitContent.toString());
commitWriter.close();
BufferedWriter headWriter = new BufferedWriter(new FileWriter("./git/HEAD"));
headWriter.write(commitHash);
headWriter.close();
return commitHash;
}

}
Binary file added GitHashTester.class
Binary file not shown.
1 change: 1 addition & 0 deletions GitHashTester.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public static void main(String[] args) throws IOException {
GitHash.add("goofy_ahh/BEANS/dawg.txt");
GitHash.add("goofy_ahh/goofy_nahhh/snog/dog.txt");
GitHash.stageFolders();
GitHash.commit("Samuel Bernardo", "Initial commit with test files");

// PriorityQueue<WorkingDirectoryInfo> q = GitHash.convertIndexToWorkingDirectory();
// System.out.println(q.poll().size());
Expand Down
Binary file added GitTester.class
Binary file not shown.
24 changes: 24 additions & 0 deletions GitTester.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import java.io.IOException;

public class GitTester {

public static void main(String args[]) throws IOException {

GitHash.deleteGitDirectory();

GitWrapper gw = new GitWrapper();
gw.init();

gw.add("myProgram/hello.txt");
gw.add("myProgram/inner/world.txt");

String commitHash = gw.commit("John Doe", "Initial commit");
System.out.println("Commit created with hash: " + commitHash);

gw.add("myProgram/hello.txt");
System.out.println("Duplicate add attempt - should not add again");

System.out.println("Git functionality test completed");
}

}
Binary file added GitWrapper.class
Binary file not shown.
64 changes: 64 additions & 0 deletions GitWrapper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import java.io.IOException;

public class GitWrapper {

/**
* Initializes a new Git repository.
* This method creates the necessary directory structure
* and initial files (index, HEAD) required for a Git repository.
*/
public void init() throws IOException {
GitHash.init();
}

/**
* Stages a file for the next commit.
* This method adds a file to the index file.
* If the file does not exist, it throws an IOException.
* If the file is a directory, it throws an IOException.
* If the file is already in the index, it does nothing.
* If the file is successfully staged, it creates a blob for the file.
* @param filePath The path to the file to be staged.
*/
public void add(String filePath) throws IOException {
GitHash.add(filePath);
}

/**
* Creates a commit with the given author and message.
* It should capture the current state of the repository by building trees based on the index file,
* writing the tree to the objects directory,
* writing the commit to the objects directory,
* updating the HEAD file,
* and returning the commit hash.
*
* The commit should be formatted as follows:
* tree: <tree_sha>
* parent: <parent_sha>
* author: <author>
* date: <date>
* summary: <summary>
*
* @param author The name of the author making the commit.
* @param message The commit message describing the changes.
* @return The SHA1 hash of the new commit.
*/
public String commit(String author, String message) throws IOException {
return GitHash.commit(author, message);
}

/**
* EXTRA CREDIT:
* Checks out a specific commit given its hash.
* This method should read the HEAD file to determine the "checked out" commit.
* Then it should update the working directory to match the
* state of the repository at that commit by tracing through the root tree and
* all its children.
*
* @param commitHash The SHA1 hash of the commit to check out.
*/
public void checkout(String commitHash) {
// to-do: implement functionality here

};
}
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ I meant working list here but I'm too lazy to change it now. Creates a priority
**convertNestedDirs()**
Using a priority queue of sorted based on file depths, adds folders in the same path to an arraylist and then converts all those folders into a tree object. repeats until Priority Queue is used up and all folders have been stored.

**Max's Note About Tree Functionality**
When running the tester prior to my fixes, it would create trees for all files but not make a final "Working List" with the root tree and its hash in it. Fixed now

**convertContentsToString()**
takes tree info (generally longer form info that has different lines / multiple data poibts) and turns into a string

Expand All @@ -95,6 +98,9 @@ stages ALL CONTENTS inside a folder NOT RELATED TO INDEX as trees in objects fol
creates a filename based on hashed contents and then writes those contents into the a file in the objects folder.


**Commit Functionality**

commit method in GitHash.java takes in the author of the commit and the commit message as strings. When called, it makes an up to date working list of the directory, and writes it to a file named as the hash of the commit file contents. The most recent commit is stored in the HEAD file, and each commit includes the previous commit's hash (so it can be found in the objects folder), leading up to the initial commit.
---

(Sam's) NOTES TO SELF:
Expand Down
Binary file added WorkingDirectoryInfo.class
Binary file not shown.
1 change: 1 addition & 0 deletions git/HEAD
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
5cd696bcdcde35f53a3731745d10f3e46ac1370d
2 changes: 2 additions & 0 deletions git/INDEX
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ea7b8499509da0261a19e48a8631a6a506f0de0a ./myProgram/hello.txt
b245828b90464cecb0c07ee6e61491ee2dc0c00e ./myProgram/inner/world.txt
1 change: 1 addition & 0 deletions git/objects/008eee1073f2cfbdac1be079e6bbea7037832695
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
blob 70260c5719d16e1f1d7ce2168377eb52a32d438f dawg.txt
3 changes: 3 additions & 0 deletions git/objects/0bc2179e8827414a3bc71984585b4a9044945f4d
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
tree 179acc793851176faa924288cb66af6cf9f99256 goofy_nahhh
tree 008eee1073f2cfbdac1be079e6bbea7037832695 BEANS
blob 70260c5719d16e1f1d7ce2168377eb52a32d438f wow.txt
1 change: 1 addition & 0 deletions git/objects/179acc793851176faa924288cb66af6cf9f99256
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
tree a91e5e5ee24e1cf52367bded740c0424a4b29cd7 snog
5 changes: 5 additions & 0 deletions git/objects/5cd696bcdcde35f53a3731745d10f3e46ac1370d
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
tree: d8259ac2dd220dfb92c86eb978592c0661467d07
parent:
author: John Doe
date: Sun Oct 12 07:13:21 PDT 2025
summary: Initial commit
1 change: 1 addition & 0 deletions git/objects/70260c5719d16e1f1d7ce2168377eb52a32d438f
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test content
5 changes: 5 additions & 0 deletions git/objects/76f1f0fed543c6cf133d919e540df11e0cbbcbed
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
tree: d8259ac2dd220dfb92c86eb978592c0661467d07
parent:
author: John Doe
date: Sun Oct 12 07:08:18 PDT 2025
summary: Initial commit
5 changes: 5 additions & 0 deletions git/objects/a2fd0600daef89a553a9f4489c72b8bcc069e975
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
tree: 9e00765445c7f8a55abf47df54880d9c454fe8ca
parent:
author: Samuel Bernardo
date: Sun Oct 12 06:59:32 PDT 2025
message: Initial commit with test files
1 change: 1 addition & 0 deletions git/objects/a91e5e5ee24e1cf52367bded740c0424a4b29cd7
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
blob 70260c5719d16e1f1d7ce2168377eb52a32d438f dog.txt
1 change: 1 addition & 0 deletions git/objects/b245828b90464cecb0c07ee6e61491ee2dc0c00e
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Inner World!
1 change: 1 addition & 0 deletions git/objects/b29b66f5a083ef031a56ebb437e7f58f9b664744
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
blob b245828b90464cecb0c07ee6e61491ee2dc0c00e world.txt
2 changes: 2 additions & 0 deletions git/objects/b34d976be64c07a6de9824d1ede86e66d1184112
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
blob ea7b8499509da0261a19e48a8631a6a506f0de0a hello.txt
tree b29b66f5a083ef031a56ebb437e7f58f9b664744 inner
1 change: 1 addition & 0 deletions git/objects/ea7b8499509da0261a19e48a8631a6a506f0de0a
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hello World!
1 change: 1 addition & 0 deletions git/objects/workingList
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
tree b34d976be64c07a6de9824d1ede86e66d1184112 myProgram
1 change: 1 addition & 0 deletions goofy_ahh/BEANS/dawg.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test content
1 change: 1 addition & 0 deletions goofy_ahh/goofy_nahhh/snog/dog.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test content
1 change: 1 addition & 0 deletions goofy_ahh/wow.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test content
1 change: 1 addition & 0 deletions myProgram/hello.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hello World!
1 change: 1 addition & 0 deletions myProgram/inner/world.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Inner World!
5 changes: 5 additions & 0 deletions temp
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
tree: d8259ac2dd220dfb92c86eb978592c0661467d07
parent:
author: John Doe
date: Sun Oct 12 07:13:21 PDT 2025
summary: Initial commit