git-timeline is a Java 25 CLI tool that improves git-log readability by formatting and hyperlinking commits to remote repositories (GitHub, Bitbucket). It uses Maven for build/test management and GraalVM for native image compilation.
./mvnw clean compile./mvnw clean test./mvnw clean test -Dtest=GitLogFormatterTest./mvnw clean test -Dtest=GitLogFormatterTest#format_givenCommitWithRemote_thenFormatCommitmake uber
# Output: target/git-timeline.jar
# Run with: java -jar ./target/git-timeline.jarmake bin
# Output: target/git-timeline
# Requires: GRAALVM_HOME environment variable pointing to GraalVM Java 25make release
# Output: release/git-timeline.jar and release/git-timeline- Use package
me.hernancerm.*for all classes - Keep package names lowercase
- One public class per file
- Related utility classes in same package
- Import static methods for frequently used utilities:
import static me.hernancerm.GitRemote.Platform.GITHUB_COM; import static org.jline.jansi.Ansi.ansi; import static org.junit.jupiter.api.Assertions.*;
- Organize imports in order: java, javax, org (3rd-party), me.hernancerm
- One import per line
- Remove unused imports
- Use 4-space indentation (no tabs)
- Line length: reasonable limit (IDE default)
- Opening braces on same line:
public class Foo { - Use var for local variables with obvious types:
var isMergeCommit = true; - Use text blocks for multi-line strings:
"""..."""
- Target Java 25+ features
- Use
varkeyword for local variable type inference - Use switch expressions where appropriate
- Use text blocks for multi-line strings
- Use records for immutable data classes when applicable
- Leverage Lombok @Data for getter/setter/equals/hashCode/toString generation
- Classes: PascalCase (GitLogFormatter, GitTimeline)
- Methods/variables: camelCase (parseArgs, isGraphEnabled, gitLogFormatter)
- Constants: UPPER_SNAKE_CASE (NAME, VERSION, GRAALVM_HOME)
- Test classes: {ClassName}Test suffix
- Test methods: descriptive pattern like
format_givenCommitWithRemote_thenFormatCommit
- Use
Objects.requireNonNull()for null validation:Objects.requireNonNull(remote, "Cannot hyperlink when remote is null");
- Throw IllegalArgumentException or IllegalStateException for invalid arguments
- Use try-catch for IOException and checked exceptions from external processes
- Propagate unexpected exceptions unless explicitly handled
- Provide meaningful error messages in exceptions
Follow the Given-When-Then (Arrange-Act-Assert) structure:
@Test
void format_givenCommitWithRemote_thenFormatCommit() {
// Given
GitCommit commit = getCommit();
// When
String result = gitLogFormatter.format(commit);
// Then
assertNotNull(result);
}- Use
@Testannotation for test methods - Use
@BeforeEachfor per-test setup - Use assertions from
org.junit.jupiter.api.Assertions.* - Test class visibility: package-private (no public modifier)
- Test method visibility: package-private
- Use
@Datafor POJOs with all getters/setters/equals/hashCode/toString:@Data public class GitCommit { private String fullHash; private String abbreviatedHash; }
- Use
@Getterand@Setterselectively if @Data is too broad - Avoid @Data on classes with custom logic; use explicit getters/setters
- Keep methods focused and small (< 20-30 lines preferred)
- Use meaningful method names that describe behavior
- Accept dependencies via constructor injection (not static access)
- Use private helper methods for internal logic
- Avoid long parameter lists; use builder or parameter objects for 4+ parameters
- Add comments only for non-obvious logic
- Explain the "why", not the "what" (code should be self-explanatory)
- Use inline comments sparingly
- Document external dependencies (e.g., links to git-scm.com/docs)
.
├── src/main/java/me/hernancerm/ # Source code
│ ├── App.java # Entry point
│ ├── GitTimeline.java # Main CLI logic
│ ├── GitLogFormatter.java # Output formatting
│ ├── GitLogProcessBuilder.java # Process execution
│ ├── GitCommit.java # Data model
│ ├── GitRemote.java # Remote repo metadata
│ ├── GitLogArgs.java # Parsed arguments
│ ├── ShellCommandParser.java # Argument parsing
│ └── AnsiUtils.java # ANSI/terminal utilities
├── src/test/java/me/hernancerm/ # Tests (same structure)
├── pom.xml # Maven configuration
├── Makefile # Build shortcuts
└── README.md # User documentation
- Java Version: Java 25 is required. Use SDKMAN or similar to manage versions.
- Native Image: Building native images with
make binis slower thanmake uberbut produces faster executables. - ANSI Output: The project uses Jansi for cross-platform ANSI color support. Always use Ansi.ansi() for coloring.
- Hyperlinks: Commits are formatted as terminal hyperlinks to GitHub/Bitbucket. Follow existing patterns in GitLogFormatter.
- No External Tools: This is a pure Java project with no external dependencies except testing and utility libraries.