{"id":16417423,"url":"https://github.com/operatorequals/git-course","last_synced_at":"2026-01-16T12:29:57.731Z","repository":{"id":46755298,"uuid":"392655114","full_name":"operatorequals/git-course","owner":"operatorequals","description":"An interactive course to git","archived":false,"fork":false,"pushed_at":"2021-08-16T15:05:27.000Z","size":163,"stargazers_count":63,"open_issues_count":0,"forks_count":2,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-10-11T07:12:27.107Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/operatorequals.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-08-04T11:02:03.000Z","updated_at":"2023-04-18T06:06:29.000Z","dependencies_parsed_at":"2022-09-24T08:23:08.767Z","dependency_job_id":null,"html_url":"https://github.com/operatorequals/git-course","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/operatorequals%2Fgit-course","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/operatorequals%2Fgit-course/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/operatorequals%2Fgit-course/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/operatorequals%2Fgit-course/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/operatorequals","download_url":"https://codeload.github.com/operatorequals/git-course/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238394323,"owners_count":19464583,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-11T07:11:30.090Z","updated_at":"2025-10-26T20:30:36.548Z","avatar_url":"https://github.com/operatorequals.png","language":"Python","funding_links":["https://www.buymeacoffee.com/operatorequals"],"categories":["Python"],"sub_categories":[],"readme":"# OperatorEquals' Sandbox Git Course!\n\n## Preface\nThis Git course is an ongoing project containing use cases that I've met (and still meet) while working in the IT industry as\n*IT Security Consultant* (e.g Code Auditor) and *IT Security Engineer* (SecDevOps - Infrascode guy and CI/CD guy),\nas well as an independent software and security tool *Developer*.\n\nI struggled a lot learning Git (you can see my ongoing struggle in my [Public Repos](https://github.com/operatorequals?tab=repositories)), yet it amazes me.\nThe problem was always that as a newbie I never found a resource that actually helped me understand what I was doing, but only commands a guru wrote somewhere on\n[StackExchange](https://stackexchange.com/) to someone having some problem that seemed close to mine.\n\nWhat really happened and I learned Git is that after years, I failed in so many different ways that something clicked on my head.\nUnfortunately some of my failures were in Git repositories that I professionally maintained. And many of the failures were on the same scenarios:\n* I put *EVERYTHING* in one single commit - someone needs to `git revert`\n* I commited a *Super Importand Production Secret* - am I fired?\n\nAnd after a million `git rebase -i` and force-pushes (some of them in branches I wasn't supposed to push), I figured that if I had some sandboxed repositories that\nrecreated my problematic scenarios I would be able to fuck them up indefinitely and eventually succeed without spending hours on colleague Reviews and Q/A time.\nAnd if also there was a way that these sandboxed repositories could automatically examine my commits and -even poorly- give me some feedback, I would learn\nwithout asking about basics that I have missed, but make only targeted and well-educated questions!\n\nI couldn't find such a resource anywhere on the Internet (very possible that I didn't search too well). So -when I felt mature enough- I made it!\n\n\n## How to Use\n\n##### Attention: DO NOT browse this repository if you are NOT looking for challenge **spoilers**\n\nThis course comes with some Git repositories with names of `challenge1.git`, `challenge2.git` ... `challengeN.git`, hosted on Heroku using the code of this repository (later on that).\nTo start a challenge you need to clone it. Then read its `README.md` and `git log` (mostly the commit that has a title starting with `[Objectives]`).\n\nExample:\n```bash\ngit clone https://git-interactive-course.herokuapp.com/challenge1.git\ncd challenge1\ncat README.md\ngit log\n```\n\nWhat you have to do to solve the challenge should be clear by then!\n\nWhat is left is to create *a new branch*, do your magic and then `git push origin \u003cyourbranch\u003e` to get the feedback from the Git Course Server.\nThe Git Course Server checks each commit (message AND contents) for specific requirements, such as commit message conventions, expected code, file similarity,\nand others. Every challenge has a dedicated script checking pushed commits, as each time the objectives are different and need to be checked in specific ways.\n\nIf a commit (or the whole diff) does not pass the tests, an informative message with the commit hash appears as a result of `git push` and the upstream changes\nare discarded. You can `git push` your changes forever and check every part of your solution. There is no \"final\" push - it is no exam. It is a sandbox!\n\nFinally, there is no scoring, no leaderboard and no logs of what you do! Learning sometimes takes suffering and frustration and watching people suffer or rewarding frustration points has never worked as a teaching experience for me.\n\n\n## The Challenges\nThe implemented challenges up to now are:\n\n### Challenge 1 - Commit Message conventions\nThis challenge asks the solver to write about 5 super-simple lines of Python code (as this is no coding course) and commit the changes using the commit\nmessage convention already used in the repository. It is a warming up challenge, yet it shows the importance of adopting the style of something already present\nbefore us, which is the case when joining software organisations.\n\n```bash\ngit clone https://git-interactive-course.herokuapp.com/challenge1.git\n```\n\n### Challenge 2 - Atomic Commits\nThis challenge asks the solver to split an already existing commit to 2 commits. This involves rewriting history. The given commit is bloated in a sense that\ncontains changes that implement more than one feature, violating the principle of *1 thing per commit*. When maintaining big codebases, a change can always lead\nto a bug - sometimes a Prod breaking one or a Security bug. Ensuring that the bug resides in exactly one (well documented on why it happened) commit is\nessential in reverting the repository to a previous working state without side-affecting other useful changes.\n\n\n```bash\ngit clone https://git-interactive-course.herokuapp.com/challenge2.git\n```\n\n### Challenge 3 - The Secret in the History\nThis challenge asks the solver completely remove a secret value commited in the Git repository. The secret has been added as a feature, and has been\nfollowed by other commits, rendering it a bit low in commit history. This is a very common use cases that requires rewriting history. Solving such a\nchallenge does give great insight not only on correctly managing secrets in code, but also on how to undo changes long down in the `git log`.\n\n```bash\ngit clone https://git-interactive-course.herokuapp.com/challenge3.git\n```\n\n### Challenge 4 - *2 Devs - 1 Branch* (1)\nThis challenge asks the solver to follow the commit history of 2 Developer branches and create a branch containing all implemented features.\nA very real scenario, as in this case, the implemented features were developed simultaneously, so changing Feature1 renders Feature2 outdated.\n\n```bash\ngit clone https://git-interactive-course.herokuapp.com/challenge4.git\n```\n\n### More to come...\n\n## Run Locally\nIf you feel like hosting the whole project on your premises you can easily do so using Containers.\nThere are two Git repository connectivity options, the `http` and the `ssh`.\nThe `Makefile` residing in this repository will create a container image by just issuing `make image` - the `TYPE` parameter accepts both `ssh` and `http`(default),\nand from there the sky is the limit!\n\nYou can go with `docker run ...` or even use Kubernetes and host it company-wide for a training session, or anything that runs containers basically.\n\n\n## Feedback and *Dev-Mode*\nThis is an Open-Source Project hosted on Free services and under Public Domain. Any feedback on it, such as bugs on challenge checks or repositories,\nrecommendations for new challenges, typos and all else, are all welcome under the [*Issues* section of this repository](https://github.com/operatorequals/git-course/issues).\nAlso Pull Requests are very welcome and will be greatly appreciated!\n\n\n## This Repository\nCreating a Git course and explaining techniques and best-practices in a repository that does not use them itself does not make sense.\nSo this Git repository follows Git message conventions and does have atomic commits (as much as possible). Also, in case you go\n*Dev-mode* you can ALWAYS find information on commit messages! Writing the commit message sometimes takes as much as the code\nitself. Also, they are all writen with explaining to others (+ future self) everything that is getting done *and why* in mind.\n\n## Implementation\nThe challenge feedback is solely based on the Git mechanism of [Server-Side hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks#_server_side_hooks). Specifically, `update` is used for branch-protection and `post-update` for the challenge checks.\nThe challenge checks are implemented in Python3 using [PyGit2](https://www.pygit2.org) to programmatically inspect Git objects (analyze commits, diffs, refs/branches, etc).\n\nA small Python3 module is sloppily getting developed for generic commit checks ([gitcourselib.py](https://github.com/operatorequals/git-course/blob/master/generic/gitcourselib.py)) that could maybe be used independently.\n\nGit Transports that are supported are `ssh` and `http`, implemented with basic OpenSSH with `git-shell` startup shell for `ssh`\nand a custom Apache2 configuration for `http`. All parts of the implementation are Open-Source and available under `deploy/`.\n\n## References\nStuff that helped me get things done with Git:\n* https://githowto.com\n* https://ohshitgit.com\n\nStuff that helped me visualize what's going on:\n* https://git-school.github.io/visualizing-git/\n* https://learngitbranching.js.org/\n* https://marklodato.github.io/visual-git-guide/index-en.html\n* https://agripongit.vincenttunru.com/\n\n## Donations\nIn case my work helped you, you can always buy me a beer or a liter of gas [through the Internet](https://www.buymeacoffee.com/operatorequals) or in case you meet me personally.\nIn the second case we can talk about privacy (during drinking the beer or driving somewhere), about the funny idea that\n[Git resembles the Human Psychology](https://securosophy.com/2017/04/01/a-git-tutorial-of-human-psychology/), about self-organized communes\nor anything you bring up :)\n\n[![donation](https://cdn-images-1.medium.com/max/738/1*G95uyokAH4JC5Ppvx4LmoQ@2x.png)](https://www.buymeacoffee.com/operatorequals)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foperatorequals%2Fgit-course","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foperatorequals%2Fgit-course","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foperatorequals%2Fgit-course/lists"}