{"id":17161319,"url":"https://github.com/andreas-bauer/git-101","last_synced_at":"2025-08-16T23:04:18.105Z","repository":{"id":39410545,"uuid":"494736726","full_name":"andreas-bauer/git-101","owner":"andreas-bauer","description":"Git tutorial","archived":false,"fork":false,"pushed_at":"2025-01-25T20:47:06.000Z","size":4804,"stargazers_count":16,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-08-16T23:02:17.471Z","etag":null,"topics":["git","git-tutorial","github"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"cc-by-sa-4.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/andreas-bauer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-05-21T09:23:07.000Z","updated_at":"2025-04-09T10:21:35.000Z","dependencies_parsed_at":"2025-04-13T14:21:51.406Z","dependency_job_id":null,"html_url":"https://github.com/andreas-bauer/git-101","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/andreas-bauer/git-101","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreas-bauer%2Fgit-101","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreas-bauer%2Fgit-101/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreas-bauer%2Fgit-101/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreas-bauer%2Fgit-101/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/andreas-bauer","download_url":"https://codeload.github.com/andreas-bauer/git-101/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreas-bauer%2Fgit-101/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270781393,"owners_count":24643820,"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","status":"online","status_checked_at":"2025-08-16T02:00:11.002Z","response_time":91,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["git","git-tutorial","github"],"created_at":"2024-10-14T22:27:54.800Z","updated_at":"2025-08-16T23:04:18.043Z","avatar_url":"https://github.com/andreas-bauer.png","language":null,"readme":"# Git 101\n\n## Configuration (global and project scope)\n\n### Global gitconfig\n\nConfigure non-default behavior once on a global scope to use it in all repositories.\n\nCreate the file `~/.gitconfig` or `~/.config/git/config`.\n\n```shell\n[user]\n  email = andreas.bauer@bth.se\n  name = Andreas Bauer\n[core]\n  autocrlf = input\n  excludesfile = ~/.gitignore\n```\n\nThis settings can also be set via the `git config` command:\n\n```shell\ngit config --global user.name \"Andreas Bauer\"\ngit config --global user.email andreas.bauer@bth.se\n```\n\n[Example global gitconfig](https://github.com/andreas-bauer/dotfiles/blob/master/gitconfig)\n\nFor more information see the [official documentation](https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration).\n\n### Repository gitconfig\n\nSometimes you want to use a different email addresses in different repositories,\ne.g., one for work related repositories and one for private repositories.\nYou can change (override) global settings on a repository level by\nusing the `--local` parameter when setting git configs.\n\n```shell\ngit config --local user.email myname@work.com\n```\n\nYou can check your local configuration by displaying the config file in the repository:\n\n```shell\ncat .git/config\n```\n\n## Gitignore\n\n### Global gitignore file\n\nA global `.gitignore` file allows you to ignore files and directories in all\nGit repositories.\nThis is especially useful when the OS creates files or directories that are not\nrelated to the Git project at all,\nlike the `.DS_Store` files in macOS or `.Trash` folder in Linux.\n\nCreate a `~/.gitignore` file and reference it in the global config (see example above).\n\n```gitignore\n# KDE directory preferences\n.directory\n\n# Linux trash folder\n.Trash-*\u003cPaste\u003e\n\n# macOS DS_Store files\n.DS_Store\n```\n\n[Example global gitignore file](https://github.com/andreas-bauer/dotfiles/blob/master/gitignore)\n\n### Gitignore templates\n\nIf you are not sure what the `.gitignore` file for a specific language/technology\nshould contain you either can use a generator or existing templates.\n\n- [gitignore-generator](https://mrkandreev.name/snippets/gitignore-generator/)\n- [collection of .gitignore templates](https://github.com/github/gitignore)\n\n## Commits\n\nGit commits represent atomic changes of the codebase.\nYou can commit staged files to the repository using `git commit`.\n\nIf you want to add changes to a previous commit without creating a new commit\nyou can use the `--ammend` argument.\nThis is helpful if you want to fix a typo you missed in the previous commit.\n\nWith the argument `--verbose` all changes will be presented as a diff and\nyou will be able to write commit messages that consist of multiple lines.\n\n```shell\n# stage a specific file\ngit add README.md\n\n# stage all files that are not ignored\ngit add *\n\n# stage all files of a folder\ngit add src/\n\n# stage parts of files for partial commits\ngit add -p\n\n# create commit with a commit message\ngit commit -m \"Add CI workflow\"\n\n# add changes to previous commit instead of creating a new commit\ngit commit --amend\n\n# show the full diff of the changes before commting\ngit commit --verbose\n\n```\n\n## Commit size\n\nBig changes are hard to understand and review by other developers.\nTherefore, you should make multiple small commits instead of one big commit.\nThese commits should also follow the Single Responsibility Principle (SRP)\nto further improve the understandability of changes.\n\nBest practices in code reviews regarding the size of code changes [1]:\n\n- \"Keep code changes small.\"\n- \"Keep one Pull Request per concern.\"\n\nReference:\n\n[1] Dong, L., Zhang, H., Yang, L., Weng, Z., Yang, X., Zhou, X., \u0026 Pan, Z. (2021).\nSurvey on Pains and Best Practices of Code Review.\n2021 28th Asia-Pacific Software Engineering Conference (APSEC), 482–491. [https://doi.org/10.1109/APSEC53868.2021.00055](https://doi.org/10.1109/APSEC53868.2021.00055)\n\n## Commit messages\n\nGood commit messages helps other developers to understand the changes in your codebase.\nTherefore, you should explain the what and the why of a change.\nAdditionally, commit messages should be consistent to improve the readability.\n\nThe commit message should be written in a way that it could\ncomplete the following sentence:\n\n*If applied, this commit will* `[commit message]`.\n\nExample: *If applied, this commit will* `Add Docker setup for server`.\n\nSome rules for good commit messages:\n\n- Keep subject line short (50 chars)\n- Consistent capitalization (preferred 'Refactor …' instead of 'refactor …')\n- Imperative mood ('Add' instead of 'added')\n\nIf you want to incorporate more information in a commit message use\nthe following format:\n\n```txt\nAdd Docker setup for server\n\n* add Dockerfile\n* add docker-compose file\n* remove obsolete Makefile\n```\n\nor\n\n```txt\nAdd Docker setup for server\n\nThe Docker setup will simplify the handling of the dev and prod environment.\n\n```\n\nIf you are working with issues (GitHub, Jira, etc.),\nyou should reference the issue if the commit closes an issue.\nThis helps to trace issues through the development process\nand gives the commit message more contextual information (why the change).\n\nExample: `Add validation to email input field (closes issue #42)`\n\nGood blog article with further information: [https://cbea.ms/git-commit/](https://cbea.ms/git-commit/).\n\n## Undo changes\n\nYou can undo changes on tracked files that are not commited yet with `git restore`.\n\n```shell\n# restore all files in the current folder and its sub-folders\ngit restore .\n\n# restore specific files\ngit restore README.md\ngit restore src/\ngit restore '*.js'\n\n# unstage a staged file\ngit restore --staged README.md\n```\n\nTo remove untracked files from the repository use `git clean`.\n\n```shell\n# remove all untracked files in the tracked directories\ngit clean -f\n\n# remove also all files from untracked directories\ngit clean -d -f\n```\n\n## Fix ups (rebase)\n\nA clean Git commit history helps to better understand the changes on the codebase.\nCommits that only fix other commits bloating the commit history.\nTypical examples are typo or code style fixes.\n\n```shell\n# BAD: The Git history is cluttered with commits that fix previous commits\n# git commit history (git log)\n# * 8d3f6c2 (HEAD -\u003e main) Change title\n# * 632d1a5 Fix linter issues for introduction section\n# * 9a1a989 Fix typos in introduction section\n# * adfe739 Add license section\n# * f37396e Add introduction section\n```\n\nTo maintain a clean Git commit history, you should mark fix commits with the\n`--fixup` argument and rebase the branch.\nWhereas fixup expects a reference (hash) to a previous commit.\n\n```shell\n# create a fixup for commit f37396e\ngit commit --fixup f37396e\n\n# git commit history (git log)\n# * 8d3f6c2 (HEAD -\u003e main) Change title\n# * 632d1a5 Fixup! add introduction section\n# * 9a1a989 Fixup! add introduction section\n# * adfe739 Add license section\n# * f37396e Add introduction section\n\n# rebase last 4 commits\ngit rebase --autosquash --interactive HEAD~4\n\n# Rebase resulted in a clean commit history\n# git commit history (git log)\n# * 8d3f6c2 (HEAD -\u003e main) Change title\n# * adfe739 Add license section\n# * f37396e Add introduction section\n```\n\n❗️Don't rebase already pushed commits.\n\n## Aliases\n\nMake you life easier by creating aliases for often used Git commands.\n\n```bash\nalias gs='git status'\nalias ga='git add '\nalias gb='git branch '\nalias gc='git commit --verbose'\nalias gd='git diff'\nalias gco='git checkout '\nalias gl='git log --graph --decorate --pretty=oneline --abbrev-commit'\nalias gr='git restore '\n```\n\nAdd Linux aliases to your shell configuration:\n\n- Bash shell: `~/.bashrc`\n- Zsh shell: `~/.zshrc`\n- Fish shell: `~/.config/fish/config.fish`\n\n[My git aliases](https://github.com/andreas-bauer/dotfiles/blob/1140290787b326b5b685cc68ee63955d4f633de4/zsh/aliases.zsh#L50)\n\nGit itself has a build-in support for aliases.\n\n```shell\n# configuration\ngit config --global alias.co checkout\n\n# usage\ngit co\n```\n\nFor more information about aliases in Git see the [official documentation](https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases).\n\n## Workflows with GitHub\n\n### Working in branches\n\nGit enables complex branching models as demonstrated [here](./assets/Git-branching-model.pdf),\nbut you shouldn't introduce a complex branching model in your project if not necessary.\n\nA simple branching strategy based on `dev` and `feature` branches is sufficient\nin most cases.\n\nIn a `dev` (development) branch …\n\n```mermaid\ngitGraph\ncommit\nbranch dev\ncommit\ncheckout main\nmerge dev\ncheckout dev\ncommit\ncommit\ncheckout main\nmerge dev\ncheckout dev\ncommit\ncheckout main\nmerge dev\n```\n\n*With a feature branch workflow* all development happens in\ndedicated branches instead of the `main` branch.\n\n```mermaid\ngitGraph\ncommit\ncommit\nbranch feature-1\nbranch feature-2\ncheckout feature-2\ncommit\ncheckout feature-1\ncommit\ncommit\ncheckout main\nmerge feature-1\ncheckout feature-2\ncommit\ncheckout main\nmerge feature-2\ncommit\nbranch bugfix\ncommit\ncheckout main\nmerge bugfix\n```\n\nFeature branches should …\n\n- have a clear focus or purpose (single-responsibility principle)\n- be small\n- have a short lifetime\n- be tested before merged into the `main` branch\n- be merged via a pull requests\n\nThis allows a collaborative workflow based on pull requests with code reviews.\n\n### Pull requests / merge requests\n\nGithub allows three different types to merge pull requests\nthat impact the Git history in different ways.\n\n- Merge commit\n- Rebase and merge\n- Squash and merge\n\nTo demonstrate the differences in merge outcome we will use the following setup:\nA feature branch with multiple commits shall be merged into the main branch.\n\n```mermaid\ngitGraph\ncommit id:\"a\"\ncommit id:\"b\"\nbranch feature\ncheckout feature\ncommit id:\"c\" type: HIGHLIGHT\ncommit id:\"d\" type: HIGHLIGHT\ncheckout main\n```\n\n#### Merge commit\n\nThe feature branch and its commits will be joined together with the main branch.\n\n- Github's default merge strategy\n- Git commit history is not as streamlined as with other merging strategies\n- uncomplicated roll back of features\n- default commit message “Merge pull request” is not helpful to understand changes\n\n```mermaid\ngitGraph\ncommit id:\"a\"\ncommit id:\"b\"\nbranch feature\ncheckout feature\ncommit id:\"c\" type: HIGHLIGHT\ncommit id:\"d\" type: HIGHLIGHT\ncheckout main\nmerge feature\n```\n\n#### Rebase and merge\n\nAll commits of the feature branch will be added to the\nmain branch individually without a merge commit.\n\n- rewrites Git commit history\n- maintains a linear commit history\n- force-push is sometimes required due to the rewrite of the commit history\n- force-push on public repositories is not recommended\n- most flexible solution\n\n```mermaid\ngitGraph\ncommit id:\"a\"\ncommit id:\"b\"\ncommit id:\"c\" type: HIGHLIGHT\ncommit id:\"d\" type: HIGHLIGHT\n```\n\n#### Squash and merge\n\nAll commits of the feature branch will be squashed into a\nsingle commit that will be added to the main branch.\n\n- maintains a linear commit history\n- uncomplicated roll back of features\n- losing detailed commits in commit history\n- fine for small changes, but problematic for long-running branches\n\n```mermaid\ngitGraph\ncommit id:\"a\"\ncommit id:\"b\"\ncommit id:\"cd\" type: HIGHLIGHT\n```\n\n### WIP (Draft) pull requests\n\nYou can use a draft pull request to start an early discussion about a feature\nthat is work-in-progress (WIP).\nDraft pull requests cannot be merged.\n\nWhen creating a pull request, select `Create draft pull request` (see screenshot).\n\n![create draft pull request](./assets/github-create-draft-pr.png)\n\nAfter the author removes the draft status of the pull request, merging becomes possible.\n\n![draft pull request](./assets/github-draft-pr.png)\n\nIn Gitlab, the prefix `WIP:` marks merge requests (pull requests) as work-in-progress.\n\n### Keep a fork up-to-date\n\nIf you work on a repository fork, you need to fetch and merge upstream changes\nto keep your fork up-to-date with the repository you forked from.\n\nYou can use GitHub's UI (see screenshot), or Git commands (see code snippet)\nto fetch and merge changes from the upstream repository.\n\n![sync branch with fork](./assets/github-sync.png)\n\n```shell\n# add fork as remote with the name \"upstream\"\ngit remote add upstream https://github.com/andreas-bauer/git-101.git\n\n# to check all remote targets\ngit remote -v\n\n# fetch changes from remote\ngit fetch upstream\n\n# merge changes of a remote branch into the current branch\ngit merge upstream/main\n\n```\n\n### Commits by multiple authors\n\nIn cases where multiple authors worked together on a commit\n, like it is the case with pair programming,\nonly one person will be visible in the Git logs.\nTo make contributions of other authors visible in the GitHub stats\nyou can use the keyword `Co-authored-by:` as part of the commit message.\n\nThis is especially useful in team-based student projects.\n\nIncorporate multiple author information in a commit message use\nthe following format:\n\n```txt\nAdd integration tests for REST API\n\nCo-authored-by: NAME \u003cNAME@EXAMPLE.COM\u003e\nCo-authored-by: AUTHOR-NAME \u003cANOTHER-NAME@EXAMPLE.COM\u003e\"\n```\n\nSee the [GitHub Docs](https://docs.github.com/en/pull-requests/committing-changes-to-your-project/creating-and-editing-commits/creating-a-commit-with-multiple-authors) for more information.\n\n## License\n\nCopyright © 2022-2025 Andreas Bauer\n\nThis work is licensed under [CC BY-SA 4.0](./LICENSE).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandreas-bauer%2Fgit-101","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandreas-bauer%2Fgit-101","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandreas-bauer%2Fgit-101/lists"}