{"id":25432013,"url":"https://github.com/vojtechmares/git-training","last_synced_at":"2025-05-14T15:32:00.721Z","repository":{"id":126543750,"uuid":"465735063","full_name":"vojtechmares/git-training","owner":"vojtechmares","description":"My course on Git","archived":false,"fork":false,"pushed_at":"2025-03-10T20:45:49.000Z","size":72,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-10T21:33:00.678Z","etag":null,"topics":["git","git-training"],"latest_commit_sha":null,"homepage":"","language":null,"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/vojtechmares.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-03-03T13:41:43.000Z","updated_at":"2025-03-10T20:45:52.000Z","dependencies_parsed_at":"2025-03-10T21:26:56.591Z","dependency_job_id":"fa2e472b-588f-4d92-945a-4932e74a8d1c","html_url":"https://github.com/vojtechmares/git-training","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/vojtechmares%2Fgit-training","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vojtechmares%2Fgit-training/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vojtechmares%2Fgit-training/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vojtechmares%2Fgit-training/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vojtechmares","download_url":"https://codeload.github.com/vojtechmares/git-training/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254171608,"owners_count":22026473,"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":["git","git-training"],"created_at":"2025-02-17T04:42:45.333Z","updated_at":"2025-05-14T15:32:00.704Z","avatar_url":"https://github.com/vojtechmares.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003ch1 align=\"center\" style=\"font-size: 4rem;\"\u003eGit Training\u003c/h1\u003e\n  \u003cp align=\"center\" style=\"font-size: 1.5rem;\"\u003eManage your source code like a pro with best version control system!\u003c/p\u003e\n  \u003cp align=\"center\"\u003e\n    \u003ca href=\"https://git-scm.com\"\u003e\u003cimg alt=\"Git\" src=\"https://img.shields.io/badge/TRAINING ON-GIT-F05032?style=for-the-badge\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://www.mares.cz\"\u003e\u003cimg alt=\"Vojtěch Mareš\" src=\"https://img.shields.io/badge/TRAINING BY-Vojtěch Mareš-fd9a00?style=for-the-badge\"\u003e\u003c/a\u003e\n  \u003c/p\u003e\n  \u003cp align=\"center\"\u003e\u003ca href=\"https://www.mares.cz\"\u003eVojtěch Mareš\u003c/a\u003e | \u003ca href=\"mailto:vojtech@mares.cz\"\u003evojtech@mares.cz\u003c/a\u003e\u003c/p\u003e\n\u003c/p\u003e\n\n## Install Git\n\nDownload installer from https://git-scm.com or use package manager.\n\n### macOS\n\n```bash\nbrew install git\n```\n\n### Linux\n\n```bash\n# Debian/Ubuntu\napt install git\n\n# Fedora and RHEL-family\ndnf install git\n\n# Alpine\napk add git\n```\n\n### Windows\n\n```powershell\nchoco install git\n```\n\n## Basic configuration\n\nI prefer global configuration (using --global) stored in your home directory\napplied to all repositories, the global config is located at `~/.gitconfig`.\n\nYou can configure just one repo, you can call git config from you repository\nwith flag --local. Or edit `.git/config` file.\n\n```bash\ngit config --global user.name \"Vojtěch Mareš\"\ngit config --global user.email \"vojtech@mares.cz\"\n```\n\n### Commit signing\n\nTo ensure the authenticity of commits and prove that the author is actually the\nauthor and that the commits are not spoofed, consider signing commits with GPG\nor SSH.\n\n**GPG commit signing**:\n\n```bash\n# Tell Git, which GPG key to use\ngit config --global user.signingkey \u003ckey\u003e\n\n# Which program to use to sign commits and tags\ngit config --global gpg.program gpg\n\n# Sign commits and tags\ngit config --global commit.gpgsign true\ngit config --global tag.gpgsign true\n```\n\n**SSH commit signing**:\n\n```bash\n# Tell Git to use SSH to sign commits and tags\ngit config --global gpg.format ssh\n\ngit config --global user.signingkey /PATH/TO/.SSH/KEY.PUB # Path is usually ~/.ssh/id_rsa.pub or id_ed25519.pub (depending on SSH key algorithm)\n```\n\n**Signed-off-by**:\n\nFrom Git docs:\n\n\u003e Add a Signed-off-by trailer by the committer at the end of the commit log\n\u003e message. The meaning of a signoff depends on the project to which you’re\n\u003e committing. For example, it may certify that the committer has the rights to\n\u003e submit the work under the project’s license or agrees to some contributor\n\u003e representation, such as a Developer Certificate of Origin. (See\n\u003e https://developercertificate.org for the one used by the Linux kernel and Git\n\u003e projects.) Consult the documentation or leadership of the project to which\n\u003e you’re contributing to understand how the signoffs are used in that project.\n\n```bash\ngit commit -s\ngit commit --signoff\n```\n\n### Rebase workflow (if you want to use rebase workflow)\n\n**WARNING**: Apply only if you want to use rebase workflow!\n\n```bash\ngit config --global pull.ff only\ngit config --global merge.ff only\ngit config --global pull.rebase true\n```\n\n## Git Editor\n\nGit use by default Vim or editor from EDITOR environment variable. If you want\nto use different editor, you can configure it.\n\n```bash\ngit config --global core.editor emacs\n```\n\nYou can use GUI editors like VS Code too:\n\n```bash\ngit config --global core.editor \"code --wait\"\n```\n\nSee Associating text editors with Git on GitHub Help to use your editor on your\nplatform.\n\n## Git within your prompt\n\n### Git PS1\n\nIf you want to see your branch in terminal prompt you have to use git-prompt.sh.\n\nIt works on Unix (ZSH \u0026 Bash). If you use Windows, it works by default in Git\nBash and there is no way how add it into CMD or PowerShell.\n\nInstall On Unix:\n\n```bash\nwget https://github.com/git/git/raw/master/contrib/completion/git-prompt.sh\nmv git-prompt.sh ~/.git-prompt.sh\necho \". ~/.git-prompt.sh \" \u003e\u003e ~/.bashrc\n```\n\nYou have to add `__git_ps1` to your `PS1` variable.\n\nBash Example:\n\n```bash\nexport PS1=\"\\033[01;32m\\]\\u@\\h\\[\\033[00m\\]:\\[\\033[01;34m\\]\\w\\[\\033[00m\\]$(__git_ps1)\\$ \"\n```\n\nSave it to .bashrc:\n\n```bash\necho 'export PS1=\"\\033[01;32m\\]\\u@\\h\\[\\033[00m\\]:\\[\\033[01;34m\\]\\w\\[\\033[00m\\]$(__git_ps1)\\$ \"' \u003e\u003e ~/.bashrc\n```\n\n### Oh My ZSH\n\nhttps://ohmyz.sh/\n\nGit plugin is enabled by default, no need to configure anything. It is ready to\ngo.\n\nMaybe configure a theme of your own choosing or create your own to suit all your\nwishes.\n\n## Aliases\n\nYou can create own git aliases:\n\n```bash\ngit config --global alias.\u003calias\u003e \u003ccommand\u003e\n```\n\nExamle:\n\n```bash\ngit config --global alias.co checkout\ngit config --global alias.br branch\ngit config --global alias.cm commit\ngit config --global alias.st status\n```\n\nUsage of aliases is `git co` for `git checkout`, `git cm` for `git commit`, ...\n\nThose aliases work on every platform (even Windows).\n\n### My aliases\n\nSaved inside global git config `~/.gitconfig`\n\n```ini\n[alias]\n  fetch = fetch -p\n  f = fetch -p\n  m = merge\n  mom = merge origin/master\n  p = push\n  pf = push --force-with-lease\n  st = status -s\n  sts = status\n  cm = commit\n  cma = commit --amend\n  fixup = commit --fixup\n  unstage = reset HEAD\n  br = branch\n  co = checkout\n  rh = reset --hard\n  rs = reset --soft\n  stash = stash --keep-index\n  wip = !git add $(git rev-parse --show-toplevel) \u0026\u0026 git commit -m WIP\n  su = submodule update --recursive\n  df = diff\n  dfc = diff --cached\n  dfs = diff --staged\n  l = log --graph --decorate --pretty=oneline --abbrev-commit\n  ll = log --graph --decorate --pretty=oneline --abbrev-commit --all\n  ld = log -p\n  ls = log --stat\n  test = push -f origin HEAD:test\n  selenium = push -f origin HEAD:selenium\n  stats = shortlog -n -s --no-merges\n  review = !git ld $1..HEAD --reverse\n  rmb = !sh -c 'git push origin :$1' -\n  rb = rebase\n  rbi = rebase -i\n  rbc = rebase --continue\n  rba = rebase --abort\n  rbs = rebase --skip\n  rbo = rebase --onto\n  rbom = rebase origin/main\n  rbiom = rebase -i origin/main\n  cp = cherry-pick\n  optimize = !git prune \u0026\u0026 git gc --aggressive \u0026\u0026 git repack -a \u0026\u0026 git prune-packed\n  fml = !git commit -m \\\"$(curl -s whatthecommit.com/index.txt)\\\"\n  gone = \"!git fetch --prune \u0026\u0026 git for-each-ref --format '%(refname) %(upstream:track)' refs/heads | awk '$2 == \\\"[gone]\\\" {sub(\\\"refs/heads/\\\", \\\"\\\", $1); print $1}' | xargs git branch -D\"\n```\n\nE.g.: `git fml`\n\n## Ignoring files\n\nYou can configure git to ignore files (or paths) using the `.gitignore` file.\n\nExample:\n\n```gitignore\nvendor\nphpstan-local.neon\n**/some-random-file.txt # file with such name will be ignored in every directory\nlog\ntemp\nwww/assets/dist\n```\n\n### Keeping empty directories\n\nThis goes hand to hand with `.gitignore`, just add an empty `.gitkeep` file to\nthe directory you wish to keep.\n\n```bash\ntouch directory-i-want-to-track-in-git/.gitkeep\n```\n\n### Default branch\n\nA few years ago, GitHub and GitLab moved from `master` to `main` as the default\nbranch. If you create a repository locally, configure Git to create correct\ndefault branch to save you some time.\n\n```bash\ngit config --global init.defaultBranch main\n\ngit config --global init.defaultBranch master\n```\n\n## Editor behavior\n\nThis is not a git feature, but is really help full.\n\n**EditorConfig!** Do not forget to commit it. `.editorconfig`\n\nExample:\n\n```editorconfig\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\nend_of_line = lf\nmax_line_length = off\n```\n\nThe most important are `charset` and `end_of_line`. Since git is sensitive to\nthose and it is really great to unify this behavior, so you won't have to deal\nwith such issues in the future, for example related to `CRLF` vs `CR` vs `LF`\nissues. Since this is a huge trouble when mixed.\n\nI personally use and recommend `insert_final_newline` and\n`trim_trailing_whitespace` set to `true`. It also helps with unifying the file\nformat.\n\n`insert_final_newline` make diffs easier to read, since the previous line is not\nmodified (added new line).\n\nThere is a VS Code extension and Jet Brains plugin.\n\n## Basic Commands\n\n### `git init`\n\nInitialize empty (with no history) Git repository in current working directory.\n\n```bash\ngit init\n```\n\n### `git clone`\n\nClone a remote repository from remote server and work on it locally and then\npush changes back to the remote repository.\n\nFor more see [Remote Repository (GitHub, GitLab)](#remote-repository-github-gitlab).\n\n```bash\ngit clone \u003cURL\u003e [\u003ctarget dir\u003e]\n\n# Clone via HTTPS\ngit clone https://github.com/vojtechmares/git-training.git\n\n# Clone via SSH\ngit clone git@github.com:vojtechmares/git-training.git\n```\n\n### `git status`\n\nShow status of repository. See which files are edited or want to be committed.\n\n```bash\ngit status\n```\n\nShow all untracked files in status\n\n```bash\ngit status --untracked-files=all\n```\n\n### `git add`\n\nAdd file to next commit\n\n```bash\ngit add \u003cpath\u003e\n```\n\nExamples\n\n```bash\ngit add index.html\ngit add .\n```\n\n### Partial `git add`\n\nYou can use `-p` to switch into interactive mode and select part of changed\nfile, which you want to commit.\n\n```bash\ngit add -p \u003cpath\u003e\n```\n\n### `git diff` for new changes\n\nYou can see changes before `git add` or `git commit`.\n\nSee new changes in files managed by Git (not in new files):\n\n```bash\ngit diff\n```\n\nIf you want to see staged changes (added, prepared for commit), you have to use:\n\n```bash\ngit diff --staged\n```\n\n### Unstage\n\nRemove changes from next commit:\n\n```bash\n# Unstage all changes\ngit reset\n\n# Unstage file\ngit reset -- \u003cpath\u003e\n```\n\n### `git commit`\n\nSave prepared changes to repository:\n\n**Create commit from all staged changes**:\n\n```bash\ngit commit\n```\n\n**Create commit form all changes (not new files)**:\n\n```bash\ngit commit -a\n```\n\n**Commit one file (not new files)**:\n\n```bash\ngit commit \u003cfile\u003e\n```\n\n**Specify message in parameter instead of open vim**:\n\n```bash\ngit commit -m \"\u003cmessage\u003e\"\n```\n\n**Combination of -a -m params**:\n\n```bash\ngit commit -am \"\u003cmessage\u003e\"\n```\n\nHow to write commit messages: https://cbea.ms/git-commit/\n\nCommit messages and their format are explored later in chapter\n[Conventional Commits](#conventional-commits).\n\n**Update latest commit**:\n\n```bash\ngit commit --amend\n```\n\n**Fixup**:\n\n```bash\ngit commit --fixup\n```\n\n**Empty commit (no changes)**:\n\n```bash\ngit commit --allow-empty\n```\n\n### `git log`\n\nShow history of commits\n\n```bash\ngit log\ngit log --oneline\ngit log --oneline --graph --all\n```\n\n### Browsing history\n\n#### Tig\n\nSimple terminal history browser for Git\n\n##### Install\n\nMac\n\n```bash\nbrew install tig\n```\n\nLinux\n\n```bash\napt install tig\n```\n\n##### Usage\n\n```bash\n# only actual branch\ntig\n\n# all branches\ntig --all\n```\n\n#### Gitk\n\nGraphic commit log. Distributed with Git.\n\n```bash\n# only actual branch\ngitk\n\n# all branch\ngitk --all\n```\n\n### Remote Repository (GitHub, GitLab)\n\nIf you have clonned repository, `git clone` has added configuration of\nrepository.\n\nCheck it by:\n\n```bash\ngit remote -v\n```\n\nand you will see:\n\n```bash\n$ git remote -v\norigin git@github.com:vojtechmares-training/example-repository.git (fetch)\norigin\n git@github.com:vojtechmares-training/example-repository.git (push)\n```\n\nIf you've created repository by `git init` you see nothing.\n\n### Add Remote Repository\n\nTo add remote repository, you have to use:\n\n```bash\ngit remote add \u003cname\u003e \u003curl\u003e\n```\n\nFor example:\n\n```bash\ngit remote add origin git@github.com:vojtechmares-training/example-repository.git\n```\n\nNow you can push \u0026 share your code with collaborators. Check `git remote -v`.\n\n### Rename \u0026 Remove Remote Repository\n\nIf you want to rename remote repository, use:\n\n```bash\ngit remote rename \u003cname\u003e \u003cnew name\u003e\n```\n\nIf you want delete remote, use:\n\n```bash\ngit remote remove \u003cname\u003e\n```\n\n### Cleanup local branches which has remote deleted\n\n```bash\ngit fetch --prune \u0026\u0026 git for-each-ref --format '%(refname) %(upstream:track)' refs/heads | awk '$2 == \\\"[gone]\\\" {sub(\\\"refs/heads/\\\", \\\"\\\", $1); print $1}' | xargs git branch -D\n```\n\nOr use an alias\n\n```ini\n[alias]\n  # ...\n  gone = \"!git fetch --prune \u0026\u0026 git for-each-ref --format '%(refname) %(upstream:track)' refs/heads | awk '$2 == \\\"[gone]\\\" {sub(\\\"refs/heads/\\\", \\\"\\\", $1); print $1}' | xargs git branch -D\"\n```\n\nUse like any other alias\n\n```bash\ngit gone\n```\n\n### `git push`\n\nPush your commits to remote repository (GitHub).\n\n```bash\n# Push new branch to repository\ngit push \u003cremote\u003e \u003cbranch\u003e -u\n\n# Push commit\ngit push\n```\n\n### `git pull`\n\nPull new commits from remote repository (GitHub).\n\n```bash\ngit pull\n```\n\n### `git fetch`\n\nPull changes from remote repository without applying the changes.\n\n```bash\ngit fetch\n```\n\n## Working with Branches\n\n### Stash\n\nGit stash is used for temporarily postpone your changes to make your working\ndirectory clean.\n\nThat's required by some Git commands like `git rebase`, ... or sometimes for\n`git checkout`, `git cherry-pick`, ...\n\nIf you want to stash changes, use:\n\n```bash\ngit stash\n```\n\nAnd check status using `git status`.\n\nIf you want to see, which files are stashed, use:\n\n```bash\ngit stash show\n```\n\nIf you want to see patch, add `-p`:\n\n```bash\ngit stash show -p\n```\n\nIf you want to apply stashed changes and remove stash, use:\n\n```bash\ngit stash pop\n```\n\nAnd check `git diff` and `git stash show`.\n\nIf you have multiple stashes you work only with the latest.\n\nList all stashes:\n\n```bash\ngit stash list\n```\n\nIf you want to specify other stash you can use `stash@{0}`. For example:\n\n```bash\ngit stash show stash@{1}\ngit stash show -p stash@{1}\n```\n\nMore about stash in offical documentation - \u003chttps://git-scm.com/docs/git-stash\u003e\n\n### List Branches\n\n```bash\n# Show local branches\ngit branch\n\n# Show all branches (with the branches of remote repository - on GitHub)\ngit branch --all\n```\n\n### Create a Branch\n\n```bash\n# Create branch (and dont switch to it)\ngit branch \u003cnew_branch\u003e [\u003cbranch_from\u003e]\n\n# Switch branch\ngit checkout \u003cbranch\u003e\n\n# Create branch and switch to it\ngit checkout -b \u003cnew_branch\u003e [\u003cbranch_from\u003e]\n\n# Create branch with switch and switch to it\ngit switch -c \u003cnew_branch\u003e\n```\n\n### Switch Branch\n\n```bash\ngit checkout \u003cbranch\u003e\n\n# switch\ngit switch \u003cbranch\u003e\n```\n\n### Switch vs Checkout\n\nSwitch is new feature to Git, added after checkout.\n\nSwitch is designed only to switch between branches and/or create one. Meanwhile\ncheckout can do more. Switch is here to do only one thing.\n\n### Push \u0026 Pull Branch\n\n```bash\n# Push commits to remote repository (GitHub)\ngit push \u003cremote\u003e \u003cbranch\u003e -u\n\n# Pull new commits to my branch\ngit pull\n```\n\n### Merging Branches\n\nYou can merge branches locally or on GitHub / GitLab using Pull / Merge\nRequests.\n\n#### Merge commits\n\n![Merge commit on master](images/mc_master.png)\n![Merge commit on branch](images/mc_branch.png)\n\n### Rebase\n\nA Czech article from [Ondrej Sika](https://ondrej-sika.cz): https://ondrej-sika.cz/git/rebase/\n\n![Rebase on master](images/rebase.png)\n\n## Git Reset\n\nReset HEAD (current brach) to specific state.\n\nSet HEAD to specific state, but don't change files in working directory.\n\n```bash\ngit reset \u003ccommit\u003e\n```\n\nIf you want also reset files, use `--hard`:\n\n```bash\ngit reset --hard \u003ccommit\u003e\n```\n\n### Remove Last Commit\n\nFor example, you want to remove last commit but want to keep changes:\n\n```bash\ngit reset HEAD~1\n```\n\nSee `git status` and `git diff`, files from last commit are now in changed.\n\nIf you want remove last commit with its changes, use:\n\n```bash\ngit reset --hard HEAD~1\n```\n\nIf you want to reset to upstream master\n\n```bash\ngit fetch\ngit reset --hard FETCH_HEAD\n```\n\nAnd see (`git status`, `git diff`), no changes.\n\n### Interactive Rebase\n\nCreate some demo commits:\n\n```bash\ntouch A\ngit add A\ngit commit -m A\ntouch B\ngit add B\ngit commit -m B\ntouch C\ngit add C\ngit commit -m C\ntouch D\ngit add D\ngit commit -m D\ntouch E\ngit add E\ngit commit -m E\ntouch F\ngit add F\ngit commit -m F\ntouch G\ngit add G\ngit commit -m G\ntouch H\ngit add G\ngit commit -m H\n```\n\nYou rewrite history, join commits, update messages, reorder commits, ...\n\n```bash\ngit rebase -i \u003cref\u003e\n```\n\nExample:\n\n```bash\ngit rebase -i HEAD~6\n```\n\n## Cherry Pick\n\nCopy commit (ref) to actual HEAD.\n\n```bash\ngit cherry-pick \u003cref\u003e\n```\n\nExample:\n\n```bash\ngit cherry-pick v1.0.x\ngit cherry-pick 47bdfb7\n```\n\n## `git reflog`\n\nReflog shows a history of refference. By default shows a `HEAD`. You can undo\nany git operations even reset.\n\n```bash\ngit reflog\n```\n\n```bash\ngit reflog \u003cbranch\u003e\n```\n\n## `git tag`\n\nCreate tag:\n\n```bash\ngit tag \u003ctag\u003e [\u003cref\u003e]\n```\n\nExample:\n\n```bash\ngit tag v1.0.0\ngit tag v1.0.0 HEAD~1\ngit tag v1.0.0 master\ngit tag v1.0.0 075615a\n```\n\nList tags:\n\n```bash\ngit tag\n```\n\nPush tag:\n\n```bash\ngit push \u003cremote\u003e \u003ctag\u003e\n```\n\nExample:\n\n```bash\ngit push origin v1.0.0\n```\n\nPush all tags:\n\n```bash\ngit push \u003cremote\u003e --tags\n```\n\nExample:\n\n```bash\ngit push origin --tags\n```\n\nDelete tag (not recommended):\n\n```bash\ngit tag -d \u003ctag\u003e\n```\n\nExample:\n\n```bash\ngit tag -d v1.0.1\n```\n\nDelete tag from server:\n\n```bash\ngit push \u003cremote\u003e :\u003ctag\u003e\n```\n\nExample:\n\n```bash\ngit push origin :v1.0.2\n```\n\n## `git blame`\n\nSee authors of actual code\n\n```bash\ngit blame \u003cfile\u003e\n```\n\nSee authors of code in specific revision\n\n```bash\ngit blame \u003crev\u003e \u003cfile\u003e\n```\n\nSee only lines from 1 to 10\n\n```bash\ngit blame -L 1,10 \u003cfile\u003e\n```\n\n## Submodules\n\nClone repository with submodules:\n\n```bash\ngit clone --recursive \u003crepo_url\u003e\n```\n\nIf you have cloned repository without `--recursive` you have to:\n\n```bash\ngit submodule update --init\n# for nested submodules\ngit submodule update --init --recursive\n```\n\nAdd submodule to repository:\n\n```bash\ngit submodule init\ngit submodule add \u003csubmodule_repo_url\u003e [\u003cpath\u003e]\n```\n\nAdd submodule and track specific branch:\n\n```bash\ngit submodule add -b \u003cbranch\u003e \u003csubmodule_repo_url\u003e [\u003cpath\u003e]\n```\n\nUpdate tracked branch:\n\n```bash\ngit submodule set-branch --branch \u003cbranch\u003e \u003cpath\u003e\n```\n\nUpdate remote repository:\n\n```bash\ngit submodule set-url \u003cpath\u003e \u003cnewurl\u003e\n```\n\nUpdate submodule from remote repository\n\n```bash\ngit submodule update --remote\n```\n\nPull changes \u0026 pull submodules\n\n```bash\ngit pull --recurse-submodules\n```\n\nExecute command for each submodule:\n\n```bash\ngit submodule foreach 'git reset --hard'\n# including nested submodules\ngit submodule foreach --recursive 'git reset --hard'\n```\n\n## Conventional Commits\n\n[Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) are an\nopinionated way of writing commit messages.\n\nEach commit message should adhere the following format:\n\n```text\n\u003ctype\u003e[optional scope]: \u003cdescription\u003e\n\n[optional body]\n\n[optional footer(s)]\n```\n\n**Breaking changes**:\n\nBreaking changes are marked with a `[type]` followed by exclamation (e.g. `feat!`\nor with scope `refactor(api)!: remove v1`).\n\nOr within `[body]` with `BREAKING CHANGE:` string.\n\nCommit message example:\n\n```text\nrefactor(api): remove v1\n\nBREAKING CHANGE: This marks removal of REST API v1. Endpoints return **404 Not found** from now on.\n\n[optional footer(s)]\n```\n\nConventional Commits itself are quite minimalistic, common approach is to use\nsomething like [Angular convention](https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#-commit-message-guidelines).\n\n**Type**:\n\n- **feat** - adding new features/functionality\n- **fix** - fixing a bug\n- **refactor** - refactoring existing code without a change of it's behavior\n  (then it would be fix or feat)\n- **chore** - no changes to the program (changes to editorconfig, updating\n  dependencies (`chore(deps)`),...)\n- **docs** - updating/adding to documentation including README\n- **build** - changes to how program is build (e.g. `Dockerfile`)\n- **ci** - GitHub Actions/GitLab CI/... changes to running tests, automated\n  builds,...\n- **style** - running a code formatter (`go fmt`, `terraform fmt`, Prettier,...)\n- **test** - changes to program tests, but no changes to the program (e.g.\n  faulty test)\n\n_Types mentioned above are adopted from the Angular convention._\n\n**Scope**:\n\nScope is optional information, like context. Providing additional information\nfrom the commit message in simple and structured way.\n\n### Semantic Versioning and Conventional Commits\n\nThanks to the Conventional Commits types, it is easy to programmatically\ndetermine (generate) next version for [Semantic Versioning](https://semver.org/).\n\nThis eliminates debates on the topic of what the next version should be. But the\nConventional Commits must be followed thoroughly.\n\n\u003e [!NOTE]\n\u003e Given a version number MAJOR.MINOR.PATCH, increment the:\n\u003e\n\u003e MAJOR version when you make incompatible API changes\n\u003e MINOR version when you add functionality in a backward compatible manner\n\u003e PATCH version when you make backward compatible bug fixes\n\u003e Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.\n\n## Thank you! \u0026 Questions?\n\nThat's all, thank you for your attention.\n\nQuestions?\n\nLet's go for a beer :beers:.\n\n## Vojtěch Mareš\n\n- email: [vojtech@mares.cz](mailto:vojtech@mares.cz)\n- web: [mares.cz](https://www.mares.cz)\n- x (twitter): [@vojtechmares_](https://x.com/vojtechmares_)\n- linkedin: [/in/vojtech-mares](https://www.linkedin.com/in/vojtech-mares/)\n\nDid you like the course? Tweet a recommendation on X (Twitter) and tag me\n(`@vojtechmares_`) and/or add me on Linked In and I will send you a request for\nrecommendation. Thanks!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvojtechmares%2Fgit-training","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvojtechmares%2Fgit-training","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvojtechmares%2Fgit-training/lists"}