Giter VIP home page Giter VIP logo

git-gud's Introduction

Git Gud

Demonstration

What is it?

Welcome to Git Gud, a command line game designed to help you learn how to use the popular version control system known as Git! As levels progress, you will know more and more about git, and eventually become a git grandmaster!

If something's missing feel free to add an issue, or if you're interested, view the contributors file and add something yourself! The project is intentially structured to make it very easy to add new levels!

If you're more of a visual learner, you should start with "Learn Git Branching", and and then give Git Gud a try. Learn Git Branching is more visual, but with Git Gud, you're actually using git to complete the levels.

How do I use it?

For install instructions, see below.

Once Git Gud is installed, typing "git gud" will produce output and will start telling you what to do. Git Gud is meant to be like a game, and like a game, it has levels. The levels are divided up into skills, each of which will introduce you to a new topic in Git. It start off, assuming you have zero knowledge, and then builds up. For each level, it will give you a goal and will explain what's going on. Ideally, the game will teach you everything you need to know to beat it, but you're still encouraged to use other resources to learn as much as you want.

The beginning levels of the game start by getting you accustomed to the Git Gud interface, but later on, the training wheels come off, and you'll have to remember to type in the commands. If you ever forget which commands there are, or if you want to start on a later level, you can always run "git gud help" The most important commands are git gud goal, git gud status, git gud explain git gud test, and git gud load next. Other commands are also useful, but the output of those commands should be enough to guide you through the level.

To get started, you need to initialize Git Gud in an empty directory. Once Git Gud is initialized, it'll have full control over that directory, and it will start adding/removing commits and files. There will normally be multiple branches, and you'll be expected to use Git commands to solve each level. The levels range in difficulty, and require you to do different things. Some levels are really easy and only require you to read the explanation, but others just give you a situation and you'll need to use what you've learned to solve the level.

How to install

Git Gud is written in Python 3. You'll need to have Python >=3.6 installed in your system for Git Gud to work. I prefer using Anaconda to make sure everything works correctly, but you can also install with pip if you now what you're doing.

Once your environment is set up with Python >=3.6, installing is simple:

pip3 install git-gud

Getting started is also simple:

git gud

Git Gud will guide you through what to do

If either of those command don't work, there are verious things you can try:

  • Use pip instead of pip3
  • Make sure your PATH variable includes Python executables
  • User install: pip3 install --user git-gud
  • Use Anaconda

git-gud's People

Contributors

attard-andrew avatar benthayer avatar cheedep avatar e-leclercq avatar elandt avatar fiss-and-fuse avatar github-actions[bot] avatar hwabis avatar jakeduo avatar julianrendell avatar lundwall avatar parkmichael777 avatar rblcoder avatar sahansk2 avatar simonbreum avatar udhayacommits avatar vjb3 avatar vmdhhh avatar wertydoo avatar zac-sanchez avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

git-gud's Issues

Make `git gud levels` look pretty

I'd like to have some pretty output for git gud levels that displays the name of all levels in git gud.

Right now it's just a series of print statements with the number of challenges. If it could be something that looked nicer and displayed more information, that would be great.

The method is already there in __main__.py, so all that you'd need to do is find a way to make it pretty.

`git gud <command> oaiwthont 23q858ingg2` should run as if we entered `git gud <command>`

Right now, when there's random extra input, git gud won't run any command, but it would be good if it still worked.

For example git status i1h5y98agnvaguhewai still outputs the status of the git repo. Likewise, if someone runs a command like git gud load intro committing 32o85yoijsghoisegh, then we should behave as if they ran git gud load intro committing.

This shouldn't be too hard. We just have to keep removing arguments from the input list until we get something that works, or we'll just get down to git gud and we'll output the help message anyways.

The current parsers will handle bad input as opposed to extra input. For example, git gud load intro notalevel will be handled by handle_load and state that "notalevel is not a level".

Relevant function is parse in gitgud/__main__

Allow loading by level/challenge numbers

Right now, we just load challenges by their names, but it might be useful to load them by their challenge numbers in addition to by name.

This issue can't be fixed until #23 is complete.

Tag Merges

Might be unnecessary, see #87

Similar to #34 but allows naming commits to continue working when there are merge commits.

Name the merges in the order that they are done: First merge gets stored in the json file with the name 'M1', 'M2', etc. Hook name is post-merge

https://git-scm.com/docs/githooks

Disable committing in favor of using git gud commit using git hooks

When users are using git gud, we want more control over what they're committing so that we can track their progress, so we should disable the git commit command. We can do this using the pre-commit git hook and exiting with a non-zero value. It can be anything, but let's use 1.

We'll also want a log message that tells the user what happend, so we can make a simple file that prints out a log message, then calls exit(1)

See gitgud/hooks/ for examples

This is also useful reference, but you shouldn't need it here: https://git-scm.com/docs/githooks

Test Suites

  • Famework for testing

Complete test suites for the following levels

Basics

  • Introduction to Git Commits
  • Branching in Git
  • Merging in Git
  • Rebase Introduction

Ramping Up

  • Detached HEAD
  • Relative Refs
  • Relative Refs 2
  • Reversing Changes

Extras

  • Octopus

Add Challenges from learngitbranching.js.org

Learn Git Branching is a great resource that we're trying to emulate and extend. To get Git Gud up and running, our first step is to copy all of their levels, and then we can start thinking about more interesting situations and build up a repository of tougher and more in depth git challenges and guides to practice on.

To be clear about our place relative to Learn Git Branching: I absolutely love it, and think it is great for visualizing everything that's happening, especially if you're new to Git. I would not have learned Git as well without it. When I was first learning Git, it really helped clarify exactly what was happening, and I didn't feel like I truly understood what was going on until I used Learn Git Branching. I created Git Gud in the same spirit, but with the goal of covering more advanced topics, the kinds of things that can really only be done from the command line because they're so complicated. Sometimes, you don't want a pretty interface, you want the commands to run quickly, and you want access to every command and all of its functionality. In Git Gud, we're going to deal with merge conflicts, multiple remotes, merges gone wrong, rebases gone horribly wrong and attempts to fix it that went even worse. We're going to show you how to set your remote to a tag and check out a branch in the process. Ever heard of plumbing? We're going to learn about it. We're going to break it. We're going to be confused the whole time. Put short: We're going to Git Dirty. That's what makes us different.

In the meantime, comment here if you plan on working on a level or a set of levels and I'll mark it down here as we go through and implement them all.

Introduction

  • Introduction to Git Commits
  • Branching in Git
  • Merging in Git
  • Rebase Introduction

Ramping Up

  • Detached HEAD
  • Introduce ^
  • Introduce ~
  • Reversing Changes

Moving Work Around

  • Cherry-picking Intro
  • Interactive Rebase Intro

A Mixed Bag

  • Grabbing just 1 commit
  • Juggling Commits
  • Juggling Commits 2
  • Tags
  • Describe

Advanced Topics

  • Rebasing over 9000 times
  • Multiple Parents
  • Branch Spaghetti

Remotes

Push and Pull

  • Clone intro
  • Remote Branches
  • Fetchin'
  • Pullin'
  • Faking Teamwork
  • Pushin'
  • Diverged History

Advanced Remotes

  • Push Master
  • Merging with Remotes
  • Remote tracking
  • Git Push Arguments
  • More Push Arguments
  • Fetch Arguments
  • Source of Nothing
  • Pull Arguments

Global config parameters

In setup.py, we use the command create_alias, which utilized GitPython's config_writer, but currently, we can't just get the global config_writer if there's not an alias. Once the issue is fixed, we should change our work-around and use GitPython directly instead

gitpython-developers/GitPython#775

Add support for git remotes

For now, this is just meant to be a note. When someone starts working on a level that requires remotes, we can talk about it here.

Eventually, we're going to need to have levels that support using remote repositories so users can practice clone/fetch/push/pull etc. We'll probably need a set of commands to go along with this and simulate actions on the remote repository, just like Learn Git Branching does. It would also be cool if we could add support for multiple repositories to simulate things like merge conflicts and whatnot

Ideally, we also make the remote name look clean so users can do something like git remote add origin gitgud:user1/repo.git or something. Maybe we can use file descriptors or symbolic links for that. Later on, we might want to do some funky stuff like practicing interactions with GitHub. Once this issues is closed, we can open up another one that starts thinking about how to do these other things.

Store merge hashes

Once we complete #40, we'll want to also keep track of the hashes of the merges. We'll also want to give them names like "M1", "M2", etc. as defined in #38. We can do this using the post-merge hook. See #40 for the details of the .json file.

#38 is similar, but these two issues can be completed in any order.

This resource will be helpful:
https://git-scm.com/docs/githooks

Change the data structure for all_levels and all_challenges to allow indexing

all_levels is defined in levels/__init__.py
all_challenges is defined in levels/intro/__init__.py and in levels/merging/__init__.py

Currently, they're both implemented using OrderedDict, but that's not as useful as it could be. Dicts allow us to access levels/challenges by name and preserving the order allows us to know which one comes after the next (duh).

Currently, we run into situations, where we need to run

level1 = next(iter(all_levels))
challenge1 = next(iter(level1.challenges))

but this is hard to read, so I would like that same code to look like

level1 = all_levels[0]
challenges = level1.challenges[0]

OrderedDict doesn't let us do that because it uses a linked list internally, which allows for fast insertion, deletion and iteration, but makes accessing elements by index very challenging. I'd like to use a different data structure that allows for both indexing like a list and key/value lookups like a dictionary.

There should be something in Python's standard library that we can use, so we should not have to implement our own. If for some reason there isn't anything in the standard library, you can comment here and we can figure something else out.

After changing the data structure, we should go and change all the code that uses next(iter(...))

Rename the `merging` level to `extras`

We're going to add the ability to run git gud load <challenge>, but in order for that to work, we need to first make sure there are no naming collisions between levels and challenges, so for the meantime, I think it makes sense to put the octopus merging challenge in the extras level until we have more levels that it might make sense to group it with.

We should also update CONTRIBUTING.md, which has a reference to that level with the new path.

The level is located under gitgud/levels/merging/

Clean up `test_level` code and add full support for merges

Currently the code in test_level in gitgud/util.py Does some hacky stuff to determine which merges correspond to the merges in the test.spec file. This code needs cleaning, and also currently doesn't handle merge commits that have merge commits as their parents. We'll want to fix both things. It is smartest to use the features built out in #87, so we can wait until those issues are complete before tackling this one.

The changes were introduced in b67c, so if you want to see the changes introduced, you can run git diff b67c~, with ~ meaning the commit before b67c

Update get_current_tree to use an efficient traversal

Right now get_current_tree in gitgud/operations.py has extra traversals. We can implement this more efficiently and avoid some of the traversals. This will be especially useful if there are a lot of tags or a lot of commits.

Also great experience if there's anyone interested in learning about algorithms and actually implementing one in production!

Add `git gud goal`

To do this, let's create a git repo in the .git/gud/ folder and then running git gud goal would do the same thing as git gud show-tree, but with the test directory, which would be have the create_tree method run on it, and no commit hashes since they might be different, as is the case in intro committing and other levels that require new commits/merges

Git.AutoInterrupt.__del__() OSError: [WinError 6] The handle is invalid

Unfortunately on Windows, we're getting this beastly error, which is caused by GitPython, not by Git Gud. If someone wants to go there and fix the issue, that would be terrific, but it seems like a tough issue. I may take it on myself at some point.

If someone would like to find a workaround for us specifically, that would also be helpful.

Here's the link to the issue on the GitPython repo: gitpython-developers/GitPython#935

Implement `git gud show-tree` to display tree in `.spec` format

It would be great for the user to have a simple way to display the current tree. Simply display the current tree in the spec format this project uses when specifying levels.

The spec format can be seen in the level directories ie 'levels/merging/_octopus/test.spec'

To do this, you may also want to implement operations.get_topology(), which may be used for other functions, but this is not necessary.

Add full names to levels

It would be nice to display full, stylized names like "Getting started" instead of "intro committing". You'll need to add a parameter to the Challenge class, call it something like self.human_name. Then, go through the existing challenge and add fun/creative names to each of the levels and then output the human name of the challenge when loading it.

Add `git gud help <command>`

This shouldn't be that hard. ArgParse parsers have a .show_help() method. Just add a subparser that uses the help command then display the appropriate help message.

Pseudocode should be something like git gud help <command> and then run <command>_parser.show_help()

Relevant file is gitgud/main.py

Instead of just instructions, also show a simulation

Sometimes words can get to be too much, so I think watching the commands in action might be the most helpful way to learn. Alternate between running a command, then showing the tree, possibly with brief explanations. It might be worth it to do this as part of the instructions or maybe as something different.

Change the contributing file so that every sentence is on its own line

Markdown allows you to write a paragraph with using mutliple lines. It'll automatically put text that are on new lines right after one another. View the raw text in CONTRIBUTING.md to see how I've gotten started.

You should be able to do the pull request directly on github.

This is useful because git shows that a line is changed, and if a line is an entire paragraph, then it might not be clear what the exact change is.

Hooks being ignored due to them not being marked as executable

Describe the bug
Git hooks do not run when their corresponding git commands are executed in a git-gud directory.

To Reproduce
Run git commit --amend in an initialized git-gud directory to test the post-rewrite hook.

I have run git gud start in multiple fresh directories to see if it was a problem with directories already initialized and manipulated with other git commands, but it appears in the fresh directories as well.

Expected behavior
The git hooks should run without any problem, and without the user running the suggested command from git to ignore the corresponding warning.

Screenshots/Output
$ git commit --amend

hint: The '.git/hooks/post-rewrite' hook was ignored because it's not set as executable.
hint: You can disable this warning with `git config advice.ignoredHook false`.
[master 194c4cd] first commit
 Author: Git Gud <[email protected]>
 Date: Sat Oct 26 21:20:50 2019 -0500
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 1

Environment
OS: Ubuntu 18.04.3 LTS, 64-bit
python Version: 3.6.8
git Version: 2.17.1

Add a whitelist and a blacklist for allowed commands (hooks)

It would be nice to be able to specify which commands are allowed and which are not to complete a given challenge.

This will be a general framework that we should include with every challenge. For different challenges, we may want to whitelist or blacklist different commands, so I think it would make sense to have a base class of AllowedCommands along with two subclasses Blacklist and Whitelist. Git hooks will then look up the challenge using an Operator (defined in gitgud/operations.py) and then access that challenge and use a challenge.commands.allows(command) where command is the git command currently being called.

There may be other ways of defining this that make more sense. For example, almost all levels will disallow committing. The only obvious exception is git commit --amend, but there might be other things. We can create other classes that would accomodate this or change the initialization to automatically block git commit and things like that. It might be useful to put all these in their own file eventually, if there gets to be a lot, but until then, they can live in util.py

Implement `git gud challenges` (displays name of all challenges)

I'd like to have some pretty output for git gud levels that displays the name of all levels in git gud.

The skeleton method is already there in main.py, so you'd need to do is write some print statements and traverse a list to output all the level names. This method is slightly more complicated than git gud levels because it needs to accept the optional input git gud challenges <level>. This argument is supplied using argparse.

If <level> is blank (None), then just look up the current level and then output all challenges in the current level. If <level> is supplied, then use the specified level. Write an appropriate print statement if the level cannot be found.

Allow git hooks to accept a varying amount of arguments

Right now, git hooks only accept one argument. That's because I've only tested with the post-rewrite hook, which accepts one argument. It's unclear whether hooks with a different number of arguments actually work right now. To solve this issue, you should test it and see.

You'll need to do some work with bash to solve this issue since the script that calls the git hooks is written in bash.

To see the created file, just run git gud start and see the created post-rewrite file in the .git/hooks directory. If I were solving this issue, I would make a script that looks similar and a python script to work with it and see what you get, but do it however you'd like.

Autocomplete commands

In bash, you can autocomplete commands so that you can hit tab when writing git gud load int and it'll fill it in with git gud load intro.

@e-leclercq is currently working on this.

Git Grief - Rant and post about your Git problems here!

Git grief gotcha goin? Rant for relief or kick back and relax your feet because this is the time for theatrics. If you've got a problem with Git or just want to read about other's problems, then you're in the right place. Entertain us with a gnarly issue, and you and your experience will be forever memorialized in the form of a git gud challenge or god forbid an entire level...

Issue not so gnarly? Post it here too and we'll help you fix it.

Log commit hashes when creating commits

This is applicable to git gud commit and calls to create_tree(). This should be done inside the create_tree and inside the handle_commit method.

This is useful because it gives the user information about the events that are happening to create the current tree.

Edit: logging for git gud commit is complete due to #71. We still need to do this for create_tree()

KeyError when using `git gud load`

I'd like to have this fail gracefully instead of just showing the stack trace for the KeyError.

The KeyErrors happen when providing a level name or a challenge name that doesn't exist.

Instead of showing the KeyError, we should provide a message that says "Level X doesn't exist" or "Challenge Y doesn't exist" and something like "To view challenges/levels, use git gud challenges or git gud levels"

Remove f-strings to allow installs from python<3.6

As much as I love f-strings, I think we're going to have to remove them.

An f-string is a string that looks like this:

location = 'World'
f'Hello {location}!'

For Git Gud to work on versions of python < 3.6, we need to make it look like this

location = 'World'
'Hello {location}!'.format(location=location)

When setting up level, order commits using timestamps

When we create the commits during the level setup process right now, they're all made at the same time and some of them end up with the same timestamp. If we run git log, then commits show up out of order.

To fix, we can just set the time. When looking at the spec file, that should be the order of the timestamps and all timestamps should come before the time at which create_tree is called so that any commits created later on by the user don't end up with a timestamp before the commits Git Gud created

Relevant method is create_tree in gitgud/operations.py

Assign tags to commits based on their names

Might be unnecessary, see #87

In spec files, we name each of our commits, and it would be nice to be able to check them out using git checkout C1

Commit tags should be a capital "C" followed with the number, no spaces. Merge commits should follow the same pattern but with an "M", just as it looks in the spec files.

We'll need to make modifications to create_tree and add_and_commit in gitgud/operations.py

Keep track of commit hashes using a .json file

We should keep track of the hashes of the commits we create using git gud commit and git gud load. Each one of these commits will a name, as defined in #34, but we should create a file, .git/gud/commits.json and store the hashes of the commits that we create. This will be useful for checking if the level is complete and validating what we think happened happened. The json should look like this:

{
'commit_name': 'hash'
...
}

Where the hash is what shows up when we run git log and commit_name is something like C1, C2, M1

Don't forget about Python's json module

Complete the `post-rewrite` hook to keep track which commits have been rebased

We'll need to put this information in the json file created by #40. When a commit is rebased, we'll want to remember the hash of the previous commit, and we'll want to remember the new commit so we can check if the commit was actually rebased. Once this is implemented, we'll want to update the levels that involve rebasing to take advantage of the newly defined git hook.

Learn Git Branching represents rebased commits with an apostrophe, such that after a rebase, 1 would become 1'. It's interesting to note that the command line doesn't get rid of the single quote while the double-quote is treated like a special character and isn't allowed to be used in a commit name.

If rebasing a rebased commit, add another ', so 1' rebased is 1''

Add internationalization

I'm not quite sure how to do this, so I'm open to suggestions if someone else wants to tackle it. The idea would be to take the instructions and logging and allow users to change their language so they can read the instructions in their native language.

It would also be nice to look up their language and change it for them.

Track which levels have been completed

Since users can complete challenges out of order, it might be fun to save which challenges have been beaten. It would probably make the most sense to store this information in a json file in the .git/gud directory that is created after we run git gud start. It might be good to name it progress.json and store three values so we know whether a level has been attempted yet

The structure of the json in progress.json would be like this

{
'intro commits': 'complete',
'intro branching': 'incomplete',
'intro merging': 'unviewed',
...
} 

We may want to add more later on, but this is a good start and will allow us to just use the full names of the challenges when determining whether they're complete.

When loading levels, we can output something like "This level has already been complete" or "This level has not yet been completed", probably something more fun.

If someone wants to check their level progress, they can type in git gud progress or it might make sense to show the progress when using git gud levels. I'll let whoever works on this issue decide what to do there.
If we use git gud progress, we'll need to wait for #31 to be complete since we're going to be using the same command.

We will also have to be conscious of new levels being added, so if a key is not in that file, we should add it.

Relevant method is handle_progress in gitgud/__main__.py

Remove `git gud progress` and replace with `git gud load next`

People read progress as if it is the noun, when I originally meant it to be the verb. That is confusing, so I think it would be good to make loading the next level a special case of the load subcommand.

We'll also need to make sure we change the instructions to match this change, so nobody types in git gud progress expecting to load the next level

Relevant methods are handle_progress and handle_load in gitgud/__main__.py

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.