Files
Githug-Android/LevelsCompare.md
Joe Tretter 02a23694c3 Fix level setup, reword flow, and catalog scope
- create and enter the level's declared starting directory
- inspect Git state from the repository containing the active directory
- start the init level in /sandbox/git_hug and cover it with a runtime test
- apply edited reword subjects as commit messages in the in-app rebase editor
- cover rename_commit with a native interactive rebase regression test
- remove the upstream contribute call to action from the playable level catalog
- update level parity documentation
2026-06-08 14:21:21 -05:00

20 KiB

LevelsCompare

Comparison source: https://github.com/Gazler/githug/ at a613718 (release: 0.5.1, 2024-08-11).

Android source compared from app/src/main/java/solutions/tretter/githugandroid/levels/.

This file records the upstream Ruby setup and validation intent beside the Android Kotlin setup and validation. The Android port uses a real native Git sandbox for runtime state, but it exposes validation through RepoState, so some checks are expressed as equivalent state predicates rather than direct Ruby/Grit calls.

Setup Summary

Level Upstream setup intent Android setup intent Parity / reason for difference
init Creates git_hug, changes into it, and starts outside a Git repository. Creates /sandbox/git_hug, starts the learner in it, and leaves it uninitialized. Equivalent.
config Initializes a repository. Initializes a repository. Equivalent.
add Initializes repo, creates untracked README, renames branch to master. Initializes repo with untracked README on master. Equivalent.
commit Initializes repo, creates and stages README. Initializes repo with staged README. Equivalent.
clone No local repo setup. Empty state. Equivalent; validation is command/network simplified.
clone_to_folder No local repo setup. Empty state. Equivalent; validation is command/network simplified.
ignore Initializes repo, creates README.swp, clears global excludes in .git/config. Initializes repo with .gitignore available for editing. Differs slightly: Android does not need a swap file fixture because validation checks .gitignore content directly.
include Initializes repo, creates first.a, second.a, lib.a, and clears excludes. Initializes repo with .gitignore, lib.a, and main.a. Same ignore-pattern lesson; Android uses a smaller fixture.
status Initializes repo; stages config.rb, README, setup.rb, deploy.rb, Guardfile; leaves database.yml untracked. Native setup now creates/stages the same five files and leaves database.yml untracked. Equivalent.
number_of_files_committed Initializes repo with committed modified files plus staged/untracked files, leaving exactly two files staged for commit. Initializes equivalent file states with two staged files. Equivalent.
rm Initializes repo, commits deleteme.rb, then deletes it from the working tree. Initializes repo with tracked deleted deleteme.rb. Equivalent.
rm_cached Initializes repo, stages .gitignore and deleteme.rb. Initializes repo with both files staged. Equivalent.
stash Copies upstream fixture containing committed lyrics.txt plus local modifications. Native setup creates the same committed lyrics text and the same trailing Hey! working-tree modification. Equivalent.
rename Initializes repo, commits oldfile.txt. Initializes repo with tracked oldfile.txt and commit. Equivalent.
restructure Initializes repo with tracked about.html, contact.html, index.html. Same tracked HTML files. Equivalent.
log Initializes repo with one commit whose message identifies the target. Same one modeled commit. Equivalent.
tag Initializes repo with one commit. Initializes repo with one tracked file and commit. Equivalent.
push_tags Creates local and remote repos, tag tag_to_be_pushed, and origin remote. Native setup creates local/remote repo and tag; model records tag and remote. Equivalent state projection.
commit_amend Commits README, then creates untracked forgotten_file.rb. Same committed README plus untracked forgotten_file.rb. Equivalent.
commit_in_future Initializes repo with staged README. Initializes repo with staged README. Equivalent setup.
reset Commits README; stages to_commit_first.rb and to_commit_second.rb. Same committed README plus both staged files. Equivalent.
reset_soft Commits README, then commits newfile.rb. Same two commits and tracked files. Equivalent.
checkout_file Commits initial config.rb, then modifies it. Same tracked modified config.rb. Equivalent.
remote Initializes repo and adds my_remote_repo remote. Same remote in initialized repo. Equivalent.
remote_url Initializes repo and adds my_remote_repo and remote_location. Same two remotes. Equivalent.
pull Initializes repo and adds remote URL https://github.com/pull-this/thing-to-pull. Native setup creates local synthetic remote with a remote commit. Deliberate offline equivalent to upstream network remote.
remote_add Initializes repo with no origin remote. Same. Equivalent.
push Creates divergent local and remote master histories: local has file3, remote has file4. Native setup creates synthetic divergent origin with the same file/commit shape. Equivalent.
diff Copies upstream fixture with committed app.rb and one changed line. Native setup creates the same committed app.rb and the same line 26 working-tree modification. Equivalent.
blame Copies upstream fixture where password line is authored by Spider Man. Native setup creates the same config.rb content with the password line authored by Spider Man. Equivalent.
branch Initializes repo with one README commit. Same. Equivalent.
checkout Initializes repo with one README commit. Same. Equivalent.
checkout_tag Creates five commits and tags v1.0, v1.2, v1.5. Same commit/tag shape. Equivalent.
checkout_tag_over_branch Creates same tags and also a branch named v1.2. Same tag-plus-branch ambiguity. Equivalent.
branch_at Creates three commits on file1. Same three modeled commits and native setup. Equivalent.
delete_branch Copies fixture with committed readme and delete_me branch at the same commit as master. Native setup creates committed readme with master and delete_me pointing at it. Equivalent.
push_branch Creates local and remote repos with multiple branches and target test_branch. Native setup creates synthetic remote and same branch intent. Equivalent state projection.
merge Copies fixture with file1 on master and file2 on feature. Native setup creates master file1 and feature file2. Equivalent.
fetch Creates local master tracking origin/master; remote later gains new_branch with file1. Native setup creates the same synthetic remote branch scenario; model starts with one fetched head. Equivalent after latest update.
rebase Copies fixture with divergent master and feature. Native setup creates matching divergent master and feature. Equivalent.
rebase_onto Creates authors.md, bad wrong_branch, and readme-update branch needing --onto. Native setup creates the same branch graph and files. Equivalent setup.
repack Initializes repo with one committed foo. Same. Equivalent.
cherry-pick Copies fixture with master and new-feature; the desired README commit is not the branch tip. Native setup creates the same branch shape: learner must cherry-pick the earlier README commit from new-feature. Equivalent.
grep Copies fixture with four TODO entries across app.rb and config.rb. Native setup creates both source files with the same four TODO entries. Equivalent.
rename_commit Creates commits Initial commit, First coommit, Second commit. Same typo commit sequence. Equivalent.
squash Creates initial hidden commit plus README and three squash-target README updates. Same commit sequence. Equivalent.
merge_squash Creates master and long-feature-branch with multiple feature changes. Native setup creates the same branch and file3 feature effect. Mostly equivalent; Android currently validates less detail.
reorder Creates commits Initial Setup, First commit, Third commit, Second commit. Same order. Equivalent.
bisect Copies upstream Ruby fixture where ruby prog.rb 5 or make test identifies bad hash 18ed2ac. Creates a native Git history with balance.txt, test-balance.sh, and known-good tag. Intentional Android adaptation: no Ruby or make dependency, but real git bisect remains playable.
stage_lines Commits initial feature.rb, then leaves two unstaged feature lines. Initializes tracked feature.rb containing both feature lines. Setup is close, but Android does not yet model partial staged vs unstaged hunks.
find_old_branch Copies fixture whose active distractor branch is renamed to master, with other distractor branches and recoverable solve_world_hunger. Native setup creates master, solve_world_hunger, cure_common_cold, and blowup_sun_for_ransom branches with matching working-tree files. Equivalent.
revert Creates commits First commit, Bad commit, Second commit. Same commit messages. Equivalent.
restore Creates file1, file2, then creates and removes file3 so it is recoverable from reflog/history. Native setup creates matching history and removes file3; model starts without file3. Equivalent.
conflict Copies fixture with master and mybranch conflict in non-empty poem.txt. Native setup creates the conflicting poem history, leaving master with Categorized shoes by color and mybranch with the correct Sat on a wall line. Equivalent setup.
submodule Initializes empty repo. Same. Equivalent; network submodule operation is modeled.

Validation Summary

Level Upstream validation intent Android validation intent Parity / reason for difference
init repo.valid? RepoState.initialized Equivalent.
config Prompted name/email must match user.name and user.email. Validates nonblank user.name and user.email. Deliberate UI difference: Android validates repository config state, not repeated prompt text.
add README exists in index and is not untracked. README is staged. Equivalent.
commit Repository has at least one commit. Commit exists and README became tracked/unstaged. Stricter but same lesson outcome.
clone cloneme repo contains known commit 157b2b6.... Accepts exact clone command. Deliberate mobile/network simplification; no external GitHub clone is performed in-game.
clone_to_folder my_cloned_repo contains known commit. Accepts exact clone-to-folder command. Deliberate mobile/network simplification.
ignore .gitignore contains *.swp. .gitignore has a line equal to *.swp. Equivalent.
include .gitignore contains *.a and !lib.a. Same two entries are present. Equivalent.
status User answers database.yml; setup has five staged files and one untracked file. User answers database.yml; setup now mirrors staged files plus untracked database.yml. Updated for parity.
number_of_files_committed Prompt answer is integer 2. Answer is 2. Equivalent.
rm deleteme.rb no longer has an unstaged deletion. File removed from model or deletion staged. Equivalent.
rm_cached deleteme.rb is not staged and still exists. deleteme.rb is unstaged, untracked, and not deleted. Equivalent.
stash stash@{0} exists and lyrics.txt has no working-tree changes. At least one stash and no staged files. Slightly looser; Android does not model unstaged tracked dirt separately after stash.
rename oldfile.txt deleted unstaged and newfile.txt added. newfile.txt exists and live oldfile.txt is gone. Equivalent for accepted solutions.
restructure HTML files are deleted at root and added under src/. All three src/*.html files exist and no live root HTML files remain. Equivalent.
log Prompt answer matches latest commit hash prefix. Answer matches the modeled commit hash. Equivalent within Android's deterministic commit model.
tag First tag is new_tag. new_tag exists. Equivalent.
push_tags Remote tag list contains tag_to_be_pushed. tag_to_be_pushed is in pushedTags. Equivalent state projection.
commit_amend One commit and amended commit contains two files. One commit and forgotten_file.rb is tracked. Equivalent.
commit_in_future Commit authored date is in the future. At least one commit has an author timestamp later than the current system clock. Equivalent.
reset to_commit_second.rb exists but is unstaged; to_commit_first.rb remains staged. Same staged/unstaged split with one commit. Equivalent.
reset_soft newfile.rb exists, is staged, and commit count is one. Same. Equivalent.
checkout_file config.rb no longer modified and commit count remains one. config.rb content equals initial content. Equivalent.
remote User answers my_remote_repo. Answer is my_remote_repo. Equivalent.
remote_url User answers URL matching https://github.com/githug/not_a_repo/?. Answer is exact URL without trailing slash. Slightly stricter; can be relaxed if trailing slash should be accepted.
pull Latest commit hash is 1797a7c. Remote file is present, origin/master fetched, and commits advanced. Equivalent local synthetic remote outcome.
remote_add git remote -v contains https://github.com/githug/githug. origin remote equals that URL. Equivalent and slightly stricter on remote name.
push Local master and origin/master have four identical commits. origin/master was pushed, four files are present, and commit count is at least four. Equivalent user outcome; Android tracks pushed ref instead of comparing remote commit IDs.
diff Answer is changed line number 26. Answer is 26. Equivalent.
blame Answer equals author of known password commit (Spider Man). Answer is Spider Man. Equivalent with deterministic Android fixture.
branch Branch test_code exists. test_code exists and current branch remains master. Slightly stricter to prevent solving by checkout side effects.
checkout Current branch is my_branch. Current branch is my_branch and branch exists. Equivalent.
checkout_tag HEAD subject is "Some more changes" with five commits. HEAD is at tag v1.2. Equivalent in Android tag model.
checkout_tag_over_branch Same as checkout_tag; must choose tag, not branch. HEAD is at tag v1.2. Equivalent in Android tag model.
branch_at test_branch exists and excludes "Updating file1 again". test_branch points at commit index 2. Equivalent.
delete_branch delete_me branch no longer exists. Same. Equivalent.
push_branch Remote has pushed test_branch but not all branches. origin/test_branch pushed and master/other not pushed. Equivalent.
merge file1 and file2 exist. Current branch is master, a merge action occurred, and file2 is tracked. Deliberately stricter than upstream to avoid git switch feature falsely solving on Android.
fetch Local branch count is one and .git/FETCH_HEAD has two entries. branches.size == 1, fetchHeadCount == 2, and no recorded pull action. Mostly parity; Android adds the pull guard because real Git can leave two FETCH_HEAD lines after git pull, while the exercise wording explicitly says fetch without merging.
rebase feature commit messages are add feature, add content, init commit, and old hash changed. Current branch is feature and modeled commit messages match. Equivalent, except Android does not compare the old hash.
rebase_onto readme-update has four commits, excludes "Wrong changes", and preserves authors. Current branch is readme-update and rebase-onto action occurred. Known gap: Android validation is looser than upstream content/commit checks.
repack git count-objects -v includes packed/pruned object evidence. repack action recorded. Equivalent action-level validation; Android does not model object database packing stats.
cherry-pick Top commits are "Filled in README..." then "Added fancy branded output". Same commit message order plus README.md tracked. Equivalent.
grep Answer is TODO count 4. Answer is 4. Equivalent.
rename_commit Parent commit message is corrected to First commit. No coommit remains and First commit exists; the in-app rebase editor uses the subject text on a reword line as the replacement message. Equivalent outcome with a single mobile editor step.
squash Commit count is two. Commit count at most two and "Adding README" remains. Slightly stricter on preserving the base README commit.
merge_squash Commit count is three and all long-feature changes are included. Squash action recorded and a commit exists. Known gap: Android does not yet verify all squash file/content effects.
reorder git log subject order matches Third.*Second.*First.*Initial. Modeled commit order becomes First, Second, Third. Equivalent relative to Android's oldest-first commit list.
bisect Answer is hash prefix 18ed2ac after using Ruby/make fixture. Learner can run git bisect start, mark HEAD bad and known-good good, run git bisect run ./test-balance.sh, then answer the last good commit hash. Same bisect lesson, different fixture and final answer target to keep the Android flow clear without Ruby/make.
stage_lines Staged diff contains first feature line; unstaged diff contains second feature line. feature.rb is staged. Known gap: Android does not yet model partial hunk staging.
find_old_branch Current branch is solve_world_hunger. Same. Equivalent.
revert More than three commits and a revert of "Bad commit" exists. A commit message starts with Revert. Slightly looser; sufficient for current fixture.
restore file3 exists. file3 is tracked. Equivalent.
conflict On master, merge commit has two parents, conflict markers removed, both poem lines preserved. Requires the latest commit on master to be a two-parent merge commit, conflict markers removed, and the correct Sat on a wall poem line preserved. Equivalent.
submodule githug-include-me directory exists, has README, and is a gitlink/submodule. submodules contains githug-include-me URL. Equivalent state projection.

Focused Source-To-Android Checks

fetch

Upstream Ruby (levels/fetch.rb) Android Kotlin (FetchLevel.kt)
Counts local branches with repo.branches.size. Uses repo.branches.size.
Counts .git/FETCH_HEAD lines after fetch; success requires num_remote == 2. GitRuntime now reads .git/FETCH_HEAD into RepoState.fetchHeadCount; success requires fetchHeadCount == 2.
Success requires exactly one local branch and two fetched heads. Success requires exactly one local branch and two fetched heads. Android also rejects a recorded pull action to preserve the exercise instruction "without merging" under native Git behavior.

status

Upstream Ruby (levels/status.rb) Android Kotlin (StatusLevel.kt)
Stages config.rb, README, setup.rb, deploy.rb, and Guardfile. Native setup now creates and stages those same five files.
Leaves database.yml untracked. Leaves database.yml untracked.
Validates answer database.yml. Validates answer database.yml.

merge

Upstream Ruby (levels/merge.rb) Android Kotlin (MergeLevel.kt)
Validates File.exists?("file1") && File.exists?("file2"). Validates master, a recorded merge action, and tracked file2.
Upstream is filesystem-only and loose. Android is intentionally stricter because git switch feature otherwise produces the same visible file state and falsely solves the level.

Follow-Up Gaps

These are the remaining known non-parity items that need additional model support if exact upstream validation is required:

  • stage_lines: model partial staged vs unstaged hunks.
  • merge_squash: verify the exact squashed file/content effects.
  • rebase_onto: verify final commit count/content and removal of "Wrong changes".
  • clone, clone_to_folder: current Android behavior intentionally avoids real network-dependent validation.

The upstream contribute call to action is intentionally not implemented as a level because it asks learners to contribute to the original GitHug repository rather than teaching or validating a Git operation.