diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5a3f2943..efbd0df6 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -26,6 +26,19 @@ Added * πŸ“ Add csv.Sniffer methods * πŸ“ Add the removal of git lfs + +Changed +~~~~~~~ + +* πŸ“ Update git section + + * Add diff source and destination prefix + * Add default branch config for init + * Add git-symbolic-ref + * Add Git Credential Store for Linux + * Update shallow clones + * Add shell config and command line tools + `24.3.0 `_: 2024-11-03 -------------------------------------------------------------------------------------------- diff --git a/docs/productive/git/advanced/batch.rst b/docs/productive/git/advanced/batch.rst index fb93f062..124957b1 100644 --- a/docs/productive/git/advanced/batch.rst +++ b/docs/productive/git/advanced/batch.rst @@ -24,6 +24,8 @@ Example changes the permissions for all files with the suffix ``.py`` from ``100644`` to ``100755``, if necessary, so that they become executable. +.. _git-name-only: + All files changed in the working or staging area ------------------------------------------------ @@ -35,9 +37,26 @@ All files changed in the working or staging area :samp:`git diff --staged --name-only "*.{SUFFIX}"` also filters for a specific file extension. +.. _list-changed: + +:samp:`git diff --name-only --diff-filter d` + excludes deleted files. + + This is the most common case for me, which is why I have created a + ``list-changed`` alias for this: ``git config --global alias.list-changed + 'diff --name-only --diff-filter d'``. + Example ~~~~~~~ -:samp:`pytest $(git diff --staged --name-only "tests/test_*.py")` +To execute commands for the changed file list, you can use the shell `Command +Substitution +`_: + +:samp:`$ uv run codespell $(git list-changed '*.py')` + The shell executes the ``git list-changed`` in brackets and inserts its + output into the outer command. ``codespell`` therefore receives the list of + changed text files as an argument. +:samp:`uv run pytest $(git diff --staged --name-only "tests/*test_*.py")` calls :doc:`python-basics:test/pytest/index` to execute only those test modules that have been changed in the working directory. diff --git a/docs/productive/git/advanced/binary-files.rst b/docs/productive/git/advanced/binary-files.rst index be3a3709..03a04d10 100644 --- a/docs/productive/git/advanced/binary-files.rst +++ b/docs/productive/git/advanced/binary-files.rst @@ -24,7 +24,7 @@ Then we can use :doc:`pandas:reference/api/pandas.DataFrame.to_csv` in :language: python Now add the following section to your global Git configuration -:file:`~/.gitconfig`: +:file:`~/.config/git/config`: .. code-block:: ini @@ -32,8 +32,8 @@ Now add the following section to your global Git configuration textconv=python3 /PATH/TO/exceltocsv.py binary=true -Finally, in the global :file:`~/.gitattributes` file, our ``excel`` converter is -linked to :file:`*.xlsx` files: +Finally, in the global :file:`~/.config/git/attributes` file, our ``excel`` +converter is linked to :file:`*.xlsx` files: .. code-block:: ini @@ -56,15 +56,16 @@ For this, ``pdftohtml`` is additionally required. It can be installed with $ brew install pdftohtml -Add the following section to the global Git configuration :file:`~/.gitconfig`: +Add the following section to the global Git configuration +:file:`~/.config/git/config`: .. code-block:: ini [diff "pdf"] textconv=pdftohtml -stdout -Finally, in the global :file:`~/.gitattributes` file, our ``pdf`` converter is -linked to :file:`*.pdf` files: +Finally, in the global :file:`~/.config/git/attributes` file, our ``pdf`` +converter is linked to :file:`*.pdf` files: .. code-block:: ini @@ -73,10 +74,12 @@ linked to :file:`*.pdf` files: Now, when ``git diff`` is called, the PDF files are first converted and then a diff is performed over the outputs of the converter. -… for Word documents --------------------- +.. _pandoc-to-markdown: -Differences in Word documents can also be displayed. For this purpose `Pandoc +… for documents +--------------- + +Differences in documents can also be displayed. For this purpose `Pandoc `_ can be used, which can be easily installed with .. tab:: Debian/Ubuntu @@ -97,24 +100,92 @@ Differences in Word documents can also be displayed. For this purpose `Pandoc `_. Then add the following section to your global Git configuration -:file:`~/.gitconfig`: +:file:`~/.config/git/attributes`: .. code-block:: ini - [diff "word"] - textconv=pandoc --to=markdown - binary=true - prompt=false + [diff "pandoc-to-markdown"] + textconv = pandoc --to markdown + cachetextconv = true -Finally, in the global :file:`~/.gitattributes` file, our ``word`` converter is -linked to :file:`*.docx` files: +Finally, in the global :file:`~/.config/git/attributes` file, our +``pandoc-to-markdown`` converter is linked to :file:`*.docx`, :file:`*.odt` and +:file:`*.rtf` files: .. code-block:: ini - *.docx diff=word + *.docx diff=pandoc-to-markdown + *.odt diff=pandoc-to-markdown + *.rtf diff=pandoc-to-markdown + +.. tip:: + :doc:`Jupyter Notebooks ` write to a JSON + file :ref:`*.ipynb `, which is quite + dense and difficult to read, especially with diffs. The Markdown + representation of Pandoc simplifies this: + + .. code-block:: ini + + *.ipynb diff=pandoc-to-markdown The same procedure can be used to obtain useful diffs from other binaries, for example ``*.zip``, ``*.jar`` and other archives with ``unzip`` or for changes in the meta information of images with ``exiv2``. There are also conversion tools for converting ``*.odt``, ``*.doc`` and other document formats into plain text. For binary files for which there is no converter, strings are often sufficient. + +.. _exiftool: + +… for media files +----------------- + +`ExifTool `_ can be used to convert the metadata of media +files to text. + +.. tab:: Debian/Ubuntu + + .. code-block:: console + + $ sudo apt install libimage-exiftool-perl + +.. tab:: macOS + + .. code-block:: console + + $ brew install exiftool + +.. tab:: Windows + + .. code-block:: ps1 + + > choco install exiftool + +.. seealso:: + * `Installing ExifTool `_ + +You can then add the following section to the global Git configuration file +:file:`~/.config/git/config`: + +.. code-block:: ini + + [diff "exiftool"] + textconv = exiftool --composite -x 'Exiftool:*' + cachetextconv = true + xfuncname = "^-.*$" + +Finally, in :file:`~/.config/git/attributes` the ``exiftool`` converter is +linked to file endings of media files: + +.. code-block:: ini + + *.avif diff=exiftool + *.bmp diff=exiftool + *.gif diff=exiftool + *.jpeg diff=exiftool + *.jpg diff=exiftool + *.png diff=exiftool + *.webp diff=exiftool + +.. seealso:: + ``exiftool`` can process many more media files. You can find a complete list + in `Supported File Types `_. diff --git a/docs/productive/git/advanced/delta-side-by-side-diff.png b/docs/productive/git/advanced/delta-side-by-side-diff.png new file mode 100644 index 00000000..6708e546 Binary files /dev/null and b/docs/productive/git/advanced/delta-side-by-side-diff.png differ diff --git a/docs/productive/git/advanced/delta.png b/docs/productive/git/advanced/delta.png new file mode 100644 index 00000000..25546cee Binary files /dev/null and b/docs/productive/git/advanced/delta.png differ diff --git a/docs/productive/git/advanced/hooks/advanced.rst b/docs/productive/git/advanced/hooks/advanced.rst index 2ed474fb..033889f1 100644 --- a/docs/productive/git/advanced/hooks/advanced.rst +++ b/docs/productive/git/advanced/hooks/advanced.rst @@ -2,44 +2,82 @@ .. .. SPDX-License-Identifier: BSD-3-Clause -Other pre-commit hooks -====================== +Supported git hooks +=================== The hooks managed by the pre-commit framework are not limited to being executed before commits; they can also be used for other Git hooks: -``post-commit`` - As of version 2.4.0, the framework can also execute `post-commit - `_ hooks with: +* :ref:`commit-msg ` +* :ref:`post-checkout ` +* :ref:`post-commit ` +* :ref:`post-merge ` +* :ref:`post-rewrite ` +* :ref:`pre-merge-commit ` +* :ref:`pre-push ` +* :ref:`pre-rebase ` +* :ref:`prepare-commit-msg ` + +.. _commit-msg-hook: + +``commit-msg`` + `commit-msg `_ can be used + with: .. code-block:: console - $ uv run pre-commit install --hook-type post-commit - pre-commit installed at .git/hooks/post-commit + $ uv run pre-commit install --hook-type commit-msg + pre-commit installed at .git/hooks/commit-msg - However, since ``post-commit`` does not work on files, all these hooks must - set ``always_run``: + The ``commit-msg`` hook can be configured with ``stages: [commit-msg]``, + passing the name of a file containing the current contents of the commit + message that can be checked. + +.. _post-checkout-hook: + +``post-checkout`` + The `post-checkout `_ hook + is called when ``git checkout`` or ``git switch`` is executed. + + The ``post-checkout`` hook can be used for example for + + * checking repositories + * viewing differences from the previous ``HEAD`` + * changing the metadata of the working directory. + + In pre-commit it can be used with: + + .. code-block:: console + + $ uv run pre-commit install --hook-type post-checkout + pre-commit installed at .git/hooks/post-checkout + + Since ``post-checkout does`` not act on files, ``always_run`` must be set + for all ``post-checkout`` scripts, for example: .. code-block:: yaml - repo: local hooks: - - id: post-commit-local - name: post commit + - id: post-checkout-local + name: Post checkout always_run: true - stages: [post-commit] + stages: [post-checkout] # … -``pre-merge`` - As of Git 2.24, there is a `pre-merge-commit - `_ hook that is - triggered after a merge is successful but before the merge commit is - created. You can use it with the pre-commit framework with: + There are three environment variables that correspond to the three arguments + of ``post-checkout``: - .. code-block:: console + ``$PRE_COMMIT_FROM_REF`` + returns the reference of the previous ``HEAD`` + ``$PRE_COMMIT_TO_REF`` + returns the reference of the new ``HEAD``, which may or may not have + changed. + ``$PRE_COMMIT_CHECKOUT_TYPE`` + returns ``Flag=1`` if it was a branch checkout and ``Flag=0`` if it was + a file checkout. - $ pre-commit install --hook-type pre-merge-commit - pre-commit installed at .git/hooks/pre-merge-commit +.. _post-merge-hook: ``post-merge`` As of version 2.11.0, the framework can also execute scripts for the @@ -53,13 +91,46 @@ before commits; they can also be used for other Git hooks: With ``$PRE_COMMIT_IS_SQUASH_MERGE`` you can find out if it was a squash merge. +.. _post-rewrite-hook: + +``post-rewrite`` + `post-rewrite `_ is called + when commits are rewritten, for example from ``git commit --amend`` or from + ``git rebase``. + + .. code-block:: console + + $ uv run pre-commit install --hook-type post-rewrite + pre-commit installed at .git/hooks/post-rewrite + + Since ``post-rewrite`` does not affect files, ``always_run: true`` must be + set. + + Git tells the ``post-rewrite`` hook which command triggered the rewrite. + ``pre-commit`` outputs this as ``$PRE_COMMIT_REWRITE_COMMAND``. + +.. _pre-merge-commit-hook: + +``pre-merge-commit`` + As of Git 2.24, there is a `pre-merge-commit + `_ hook that is + triggered after a merge is successful but before the merge commit is + created. You can use it with the pre-commit framework with: + + .. code-block:: console + + $ uv run pre-commit install --hook-type pre-merge-commit + pre-commit installed at .git/hooks/pre-merge-commit + +.. _pre-push-hook: + ``pre-push`` To use the `pre-push `_ hook with the pre-commit framework, enter the following: .. code-block:: console - $ pre-commit install --hook-type pre-push + $ uv run pre-commit install --hook-type pre-push pre-commit installed at .git/hooks/pre-push The following environment variables are provided for this purpose: @@ -81,89 +152,58 @@ before commits; they can also be used for other Git hooks: The name of the local branch that was pushed to the remote branch, for example :samp:`{HEAD}`. -``commit-msg`` - `commit-msg `_ can be used - with: - - .. code-block:: console - - $ pre-commit install --hook-type commit-msg - pre-commit installed at .git/hooks/commit-msg - - The ``commit-msg`` hook can be configured with ``stages: [commit-msg]``, - passing the name of a file containing the current contents of the commit - message that can be checked. +.. _pre-rebase-hook: -``prepare-commit-msg`` - `prepare-commit-msg - `_ can be used with - pre-commit with: +``pre-rebase`` + Since version 3.2.0, the framework also supports `pre-rebase + `_ hooks: .. code-block:: console - $ pre-commit install --hook-type prepare-commit-msg - pre-commit installed at .git/hooks/prepare-commit-msg + $ uv run pre-commit install --hook-type pre-rebase + pre-rebase installed at .git/hooks/pre-rebase - The ``prepare-commit-msg`` hook is configured with ``stages: - [prepare-commit-msg]``, passing the name of a file that contains the initial - commit message, for example from :samp:`git commit -m "{COMMIT-MESSAGE}"` to - create a dynamic template from it that is displayed in the editor. Finally, - the hook should check that no editor is started with ``GIT_EDITOR=:``. - -``post-checkout`` - The `post-checkout `_ hook - is called when ``git checkout`` or ``git switch`` is executed. + ``pre-rebase`` hooks cannot be applied to files, and therefore they must be + set as ``always_run: true``, otherwise they will always be skipped. - The ``post-checkout`` hook can be used for example for +.. _post-commit-hook: - * checking repositories - * viewing differences from the previous ``HEAD`` - * changing the metadata of the working directory. - - In pre-commit it can be used with: +``post-commit`` + As of version 2.4.0, the framework can also execute `post-commit + `_ hooks with: .. code-block:: console - $ pre-commit install --hook-type post-checkout - pre-commit installed at .git/hooks/post-checkout + $ uv run pre-commit install --hook-type post-commit + pre-commit installed at .git/hooks/post-commit - Since ``post-checkout does`` not act on files, ``always_run`` must be set - for all ``post-checkout`` scripts, for example: + However, since ``post-commit`` does not work on files, all these hooks must + set ``always_run``: .. code-block:: yaml - repo: local hooks: - - id: post-checkout-local - name: Post checkout + - id: post-commit-local + name: post commit always_run: true - stages: [post-checkout] + stages: [post-commit] # … - There are three environment variables that correspond to the three arguments - of ``post-checkout``: - - ``$PRE_COMMIT_FROM_REF`` - returns the reference of the previous ``HEAD`` - ``$PRE_COMMIT_TO_REF`` - returns the reference of the new ``HEAD``, which may or may not have - changed. - ``$PRE_COMMIT_CHECKOUT_TYPE`` - returns ``Flag=1`` if it was a branch checkout and ``Flag=0`` if it was - a file checkout. +.. _prepare-commit-msg-hook: -``post-rewrite`` - `post-rewrite `_ is called - when commits are rewritten, for example from ``git commit --amend`` or from - ``git rebase``. +``prepare-commit-msg`` + `prepare-commit-msg + `_ can be used with + pre-commit with: .. code-block:: console - $ pre-commit install --hook-type post-rewrite - pre-commit installed at .git/hooks/post-rewrite - - Since ``post-rewrite`` does not affect files, ``always_run: true`` must be - set. + $ uv run pre-commit install --hook-type prepare-commit-msg + pre-commit installed at .git/hooks/prepare-commit-msg - Git tells the ``post-rewrite`` hook which command triggered the rewrite. - ``pre-commit`` outputs this as ``$PRE_COMMIT_REWRITE_COMMAND``. + The ``prepare-commit-msg`` hook is configured with ``stages: + [prepare-commit-msg]``, passing the name of a file that contains the initial + commit message, for example from :samp:`git commit -m "{COMMIT-MESSAGE}"` to + create a dynamic template from it that is displayed in the editor. Finally, + the hook should check that no editor is started with ``GIT_EDITOR=:``. diff --git a/docs/productive/git/advanced/hooks/index.rst b/docs/productive/git/advanced/hooks/index.rst index 1460c2ee..b2a2bdc1 100644 --- a/docs/productive/git/advanced/hooks/index.rst +++ b/docs/productive/git/advanced/hooks/index.rst @@ -9,17 +9,20 @@ Git hooks are scripts that are automatically executed when certain events occur in a Git repository, including: +---------------+-------------------------------------------------------+ -| Command | Hook | +| Command | Hooks | +===============+=======================================================+ -| ``commit`` | ``commit-msg``, ``pre-commit`` | +| ``git commit``| `prepare-commit-msg`_, `pre-commit`_, `commit-msg`_, | +| | `post-commit`_ | +---------------+-------------------------------------------------------+ -| ``merge`` | ``pre-merge``, ``commit-msg`` | +| ``git merge`` | `pre-merge-commit`_, `commit-msg`_, `post-merge`_ | +---------------+-------------------------------------------------------+ -| ``rebase`` | ``pre-rebase`` | +| ``git rebase``| `pre-rebase`_, `post-rewrite`_ | +---------------+-------------------------------------------------------+ -| ``pull`` | ``pre-merge``, ``commit-msg`` | +| ``git pull`` | `post-merge`_ | +---------------+-------------------------------------------------------+ -| ``push`` | ``pre-push`` | +| ``git push`` | `pre-push`_, `pre-receive`_, `update`_, | +| | `post-update`_, `proc-receive`_, `post-receive`_, | +| | `push-to-checkout`_ | +---------------+-------------------------------------------------------+ They can be located either in local or server-side repositories. This allows Git @@ -30,19 +33,21 @@ created, some sample scripts are already created there: .. code-block:: console - .git/hooks/ - β”œβ”€β”€ applypatch-msg.sample - β”œβ”€β”€ commit-msg.sample - β”œβ”€β”€ fsmonitor-watchman.sample - β”œβ”€β”€ post-update.sample - β”œβ”€β”€ pre-applypatch.sample - β”œβ”€β”€ pre-commit.sample - β”œβ”€β”€ pre-merge-commit.sample - β”œβ”€β”€ prepare-commit-msg.sample - β”œβ”€β”€ pre-push.sample - β”œβ”€β”€ pre-rebase.sample - β”œβ”€β”€ pre-receive.sample - └── update.sample + .git/hooks + β”œβ”€β”€ applypatch-msg.sample + β”œβ”€β”€ commit-msg.sample + β”œβ”€β”€ fsmonitor-watchman.sample + β”œβ”€β”€ post-update.sample + β”œβ”€β”€ pre-applypatch.sample + β”œβ”€β”€ pre-commit.sample + β”œβ”€β”€ pre-merge-commit.sample + β”œβ”€β”€ pre-push.sample + β”œβ”€β”€ pre-rebase.sample + β”œβ”€β”€ pre-receive.sample + β”œβ”€β”€ prepare-commit-msg.sample + β”œβ”€β”€ push-to-checkout.sample + β”œβ”€β”€ sendemail-validate.sample + └── update.sample For the scripts to be executed, only the suffix ``.sample`` must be removed and, if necessary, the file permission must be executable, for example with @@ -54,6 +59,9 @@ be interpreted. However, the scripts cannot be copied into the server-side repository. +.. seealso:: + * `Hooks `_ + .. toctree:: :hidden: @@ -63,3 +71,19 @@ However, the scripts cannot be copied into the server-side repository. ci skip template + +.. _`prepare-commit-msg`: https://git-scm.com/docs/githooks#_prepare_commit_msg +.. _`pre-commit`: https://git-scm.com/docs/githooks#_pre_commit +.. _`post-commit`: https://git-scm.com/docs/githooks#_post_commit +.. _`commit-msg`: https://git-scm.com/docs/githooks#_commit_msg +.. _`pre-merge-commit`: https://git-scm.com/docs/githooks#_pre_merge_commit +.. _`post-merge`: https://git-scm.com/docs/githooks#_post_merge +.. _`pre-rebase`: https://git-scm.com/docs/githooks#_pre_rebase +.. _`post-rewrite`: https://git-scm.com/docs/githooks#_post_rewrite +.. _`pre-push`: https://git-scm.com/docs/githooks#_pre_push +.. _`pre-receive`: https://git-scm.com/docs/githooks#pre-receive +.. _`update`: https://git-scm.com/docs/githooks#update +.. _`post-update`: https://git-scm.com/docs/githooks#post-update +.. _`proc-receive`: https://git-scm.com/docs/githooks#proc-receive +.. _`post-receive`: https://git-scm.com/docs/githooks#post-receive +.. _`push-to-checkout`: https://git-scm.com/docs/githooks#_push_to_checkout diff --git a/docs/productive/git/advanced/index.rst b/docs/productive/git/advanced/index.rst index 8841ba1c..ef7ec329 100644 --- a/docs/productive/git/advanced/index.rst +++ b/docs/productive/git/advanced/index.rst @@ -42,8 +42,9 @@ Advanced Git notes hooks/index jupyter-notebooks - binary-files + shell batch + binary-files lfs vs-code/index gitlab/index diff --git a/docs/productive/git/advanced/jupyter-notebooks.rst b/docs/productive/git/advanced/jupyter-notebooks.rst index 9994fa9b..b655f060 100644 --- a/docs/productive/git/advanced/jupyter-notebooks.rst +++ b/docs/productive/git/advanced/jupyter-notebooks.rst @@ -77,6 +77,7 @@ environment: To get started, follow the instructions in `Git-Friendly Jupyter `_. +.. _nbstrip_jq: ``jq`` ------ @@ -163,12 +164,12 @@ Set up #. If you want to use this filter for all Git repositories, you can also configure your Git globally: - #. First you add the following to your ``~/.gitconfig`` file: + #. First you add the following to your :file:`~/.config/git/config` file: .. code-block:: ini [core] - attributesfile = ~/.gitattributes + attributesfile = ~/.config/git/attributes [filter "nbstrip_jq"] clean = "jq --indent 1 \ @@ -185,7 +186,8 @@ Set up ``smudge`` is used when resetting the workspace by changes from the stage area. - #. Then you have to specify the following in the ``~/.gitattributes`` file: + #. Then you have to specify the following in the ``~/.config/git/attributes`` + file: .. code-block:: ini diff --git a/docs/productive/git/advanced/shell.rst b/docs/productive/git/advanced/shell.rst new file mode 100644 index 00000000..ff1af59d --- /dev/null +++ b/docs/productive/git/advanced/shell.rst @@ -0,0 +1,199 @@ +Shell configuration and command line tools +========================================== + +In this chapter I would like to introduce you to two powerful shell extensions: + +.. tab:: oh-my-zsh + + `oh-my-zsh `_ can be used for the `Z Shell + `_. + + .. seealso:: + * `Getting Started `_ + * `Plugins `_ + * `Git Plugin Aliases + `_ + * `zsh-you-should-use + `_ + +.. tab:: Starship + + `Starship `_ is a fast tool that you can use with any + shell. + + * `git_branch-Modul `_ + * `git_commit-Modul `_ + * `git_state `_ + * `git_status-Modul `_ + +Pipes (``|``) +------------- + +Git never uses `less `_ if you redirect +the output to another programme, for example + +.. code-block:: console + + $ git log --oneline | grep Jupyter + +However, you can pass the output back to ``less``: + +.. code-block:: console + + $ git log --oneline | grep Jupyter | less + +.. _git-delta: + +delta +----- + +`delta `_ is a smart diff display, see for +example: + +.. figure:: delta.png + :alt: Schicke Diff-Anzeige mit delta + +Installation +~~~~~~~~~~~~ + +.. tab:: Debian/Ubuntu + + The :file:`.deb` files can be found on the `Release + `_ page. + +.. tab:: macOS + + .. code-block:: console + + $ brew install git-delta + +.. tab:: Windows + + .. code-block:: ps1 + + > choco install delta + +.. _delta_config: + +Configuration +~~~~~~~~~~~~~ + +An example configuration can be found in `Git config file +`_: + +.. code-block:: ini + + [core] + pager = delta + + [interactive] + diffFilter = delta --color-only + + [delta] + navigate = true # use n and N to move between diff sections + + [merge] + conflictstyle = zdiff3 + +However, delta not only extends the display of ``git diff``, but also that of +``git add --patch``, ``git log --patch``, ``git blame``, ``git rebase`` merge +conflicts and ``git show``. In addition, delta can also display side-by-side +diffs, for example: + +.. figure:: delta-side-by-side-diff.png + :alt: Side-by-Side-Diffs mit delta + +You can also configure this globally with: + +.. code-block:: console + + $ git config --global delta.side-by-side true + +ripgrep +------- + +Installation +~~~~~~~~~~~~ + +.. tab:: Debian/Ubuntu + + You can install ripgrep with a binary :file:`.deb` file, which is included in + every `ripgrep release `_. + + .. code-block:: console + + $ curl -LO https://github.com/BurntSushi/ripgrep/releases/download/14.1.0/ripgrep_14.1.0-1_amd64.deb + $ sudo dpkg -i ripgrep_14.1.0-1_amd64.deb + +.. tab:: macOS + + .. code-block:: console + + $ brew install ripgrep + +.. tab:: Windows + + .. code-block:: ps1 + + > choco install ripgrep + +.. seealso:: + * `rpgrep Installation + `_ + +Examples +~~~~~~~~ + +.. note:: + The package is called ``ripgrep``, but the command is ``rg``. + +:samp:`$ rg {PATTERN}` + searches for regexes, whereby you should often use inverted commas to + prevent the shell from interpreting special characters. +:samp:`$ rg {PATTERN} {FILENAMES}` + restricts the search to certain files by naming them according to the + pattern. +:samp:`$ rg -g|--glob {PATTERN}` + filters files according to so-called `globbing + `_ patterns. +:samp:`$ rg -t {SUFFIX} {PATTERN}` + searches for files with certain file extensions. + + With ``rg --type-list`` you get all possible file extensions. + +:samp:`$ rg -i|--ignore-case {PATTERN}` + ignores upper and lower case. +:samp:`$ rg --hyperlink-format {EDITOR} {PATTERN}` + creates file paths as terminal hyperlinks that can be opened by holding down + the :kbd:`Strg` or :kbd:`⌘` key. Possible editors can be obtained with + ``man rg``. +:samp:`$ rg --no-ignore {PATTERN}`, :samp:`$ rg -.|--hidden {-.PATTERN}`, :samp:`$ rg --binary {PATTERN}` or :samp:`$ rg -u |--unrestricted {PATTERN}` + also displays results in files that are usually filtered out by + ``.gitignore`` statements, by ``.`` hidden files or binary files. + + .. tip:: + :samp:`$ rg -.|--hidden {-.PATTERN}` also displays results in the + :file:`.git` directory. To exclude this directory from the search, you + can exclude this directory with the :samp:`-g|--glob` option and a ``!``, + for example :samp:`rg -. -g '!.git' {PATTERN}`. + +Configuration +~~~~~~~~~~~~~ + +You can create a configuration file for ripgrep in :file:`~/.config/ripgreprc`, +for example: + +.. code-block:: console + + --hyperlink-format + default + --smart-case + --hidden + --glob + !.git + +You can then define the ``RIPGREP_CONFIG_PATH`` environment variable with + +.. code-block:: console + + $ export RIPGREP_CONFIG_PATH=~/.config/ripgreprc diff --git a/docs/productive/git/best-practices.rst b/docs/productive/git/best-practices.rst index 902221e7..c6d3fd36 100644 --- a/docs/productive/git/best-practices.rst +++ b/docs/productive/git/best-practices.rst @@ -176,6 +176,11 @@ the commit later. * `Visual Studio Code Extension `_ +.. _gitlab-references: + +GitLab-specific references +~~~~~~~~~~~~~~~~~~~~~~~~~~ + GitLab also interprets certain commit messages as links, for example: .. code-block:: console @@ -255,6 +260,10 @@ Git then starts each new commit message with the *Scissors* line: # ... # +.. seealso:: + * `GitLab-specific references + `_ + Specify co-authors ~~~~~~~~~~~~~~~~~~ @@ -295,6 +304,8 @@ Save storage space with the command ``git gc`` or ``git gc --aggressive``. * `Git Internals - Maintenance and Data Recovery `_ + .. _fetch-prune: + Clean up remote tracking branches ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -347,5 +358,5 @@ following in the :file:`.pre-commit-config.yaml` file: class MyClass: client_secret = "Srtub6pZcTSET9V4vUpUg7xPi64sh3NV" #gitleaks:allow -With :ref:`git-filter-repo ` you can remove unwanted files -from your Git history. +With :ref:`git-filter-repo ` you can remove unwanted files from +your Git history. diff --git a/docs/productive/git/branch.rst b/docs/productive/git/branch.rst index a876de04..81082922 100644 --- a/docs/productive/git/branch.rst +++ b/docs/productive/git/branch.rst @@ -13,6 +13,8 @@ Git branches ``-l`` restricts the branches to those that correspond to a specific pattern. +.. _committerdate: + :samp:`$ git branch --sort=-committerdate` sorts the branches according to the commit date. @@ -106,6 +108,8 @@ The history can then look like this, for example: * `Git Tools - Advanced Merging `_ +.. _merge-conflictstyle: + Improved conflict display with zdiff3 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -162,6 +166,8 @@ The common base is now displayed between the markers ``|||||||`` and ``=======`` with the SHA value of the common base. This additional context is often useful for resolving a conflict. +.. _rerere: + ``rerere`` to reuse recorded conflict resolutions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -246,6 +252,44 @@ repository in an :file:`rr-cache` directory. You should note two things here: determines how long entries for unresolved conflicts are kept. The default value is 15 days. +.. _merge-aliases: + +Aliases for faster resolution of merge conflicts +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Resolving conflicts when merging can be time-consuming, but aliases can speed up +the process. + +You can use the `--diff-filter +`_ +option for ``git diff`` to display only the files that are not merged: + +.. code-block:: console + + $ git diff --name-only --diff-filter U + +You can also create a `Git command alias +`_: + +.. code-block:: console + + $ git config --global alias.list-unmerged '!git diff --name-only --diff-filter U' + +And to edit the non-merged files, you can create a `Git command alias +`_: + +.. code-block:: console + + $ git config --global alias.edit-unmerged '!git diff --name-only --diff-filter U | xargs -r $(git var GIT_EDITOR)' + +Now you can edit all unmerged files with ``git edit-unmerged`` and then add all +files to the staging area with ``git add -u``. + +.. seealso:: + I took the editor variable from the `gitalias + `_ project. And maybe you’ll + find more ideas for your alias there. + Delete branches --------------- @@ -285,6 +329,8 @@ can do this with: :samp:`$ git push --set-upstream origin --all` +.. _push-autoSetupRemote: + You can configure the following so that this happens automatically for branches without a tracking upstream: @@ -363,3 +409,12 @@ Team members can delete their locally still existing references to the .. code-block:: console $ git fetch origin --prune + +.. tip:: + With `git symbolic-ref `_ you can + create aliases, for example: + + .. code-block:: console + + $ git symbolic-ref refs/heads/main refs/heads/master + $ git symbolic-ref refs/remotes/origin/main refs/remotes/origin/master diff --git a/docs/productive/git/install-config.rst b/docs/productive/git/install-config.rst index 53a37ecb..9ab893d3 100644 --- a/docs/productive/git/install-config.rst +++ b/docs/productive/git/install-config.rst @@ -8,7 +8,7 @@ Git installation and configuration Installation ------------ -For iX distributions, Git should be in the standard repository. +For ix distributions, Git should be in the standard repository. .. tab:: Debian/Ubuntu @@ -33,7 +33,7 @@ For iX distributions, Git should be in the standard repository. .. code-block:: console - $ sudo apt install bash-completion + $ sudo apt install bash-completion .. tab:: macOS @@ -64,130 +64,208 @@ For iX distributions, Git should be in the standard repository. Configuration ------------- -The author of every change needs to be transparent. -Specify your name and email address as follows: +Save the global configuration in :file:`~/.config/git/` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Git uses three levels of configuration files, which are applied in this order: -:samp:`$ git config --global user.name "{NAME}"` - defines the name :samp:`{NAME}` associated with your commit transactions. -:samp:`$ git config --global user.email "{EMAIL-ADDRESS}"` - defines the email address :samp:`{EMAIL-ADDRESS}` that will be linked to your commit transactions. +``system`` + applies to all users on your computer, but it’s unlikely you’ll ever use + this. +``global`` + applies to all repositories of a single user and we will look at this in + more detail here. +``local`` + applies to a single repository and is only suitable for a few + repository-specific options. -For better readability, activate the colouring of the command line output: +Git searches for a global configuration file in two places: :file:`~/.config/git/config` and :file:`~/.gitconfig`. The first location is the default location +for configuration files while the second is the legacy option. -:samp:`$ git config --global color.ui auto` +.. note:: + On Linux machines, :file:`~/.config` can sometimes be a different path set by + the environment variable ``XDG_CONFIG_HOME``. This behaviour is part of the + `X Desktop Group (XDG) specification + `_. You + can get the other path with: + .. code-block:: ini -The :file:`~/.gitconfig` file -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + $ echo $XDG_CONFIG_HOME -For example, the following file can be created with the commands given above: + If this does not result in anything, then your system will use + :file:`~/.config`, otherwise it will use the path shown. For the sake of + simplicity, we will only refer to :file:`~/.config` from now on. -.. code-block:: ini +.. seealso:: + * `git config files `_ - [user] - name = veit - email = veit@cusy.io +Since you can set options at multiple levels, you may want to keep track of +where Git reads a particular value from. With ``git config --list`` [#]_ you can +list all the overridden options and values. You can combine this with +``--show-scope`` [#]_ to see where Git is getting the value from: - [color] - ui = auto +.. code-block:: console -However, aliases can also be specified in the :file:`~/.gitconfig` file: + $ git config --list --show-scope + system credential.helper=osxkeychain + global user.name=veit + global user.email=veit@cusy.io + … -.. code-block:: ini +You can also use ``--show-origin`` [#]_ to list the names of the configuration +files: - [alias] - st = status - ci = commit - br = branch - co = checkout - df = diff - dfs = diff --staged +.. code-block:: console -.. seealso:: - Shell-Konfiguration: + $ git config --list --show-origin + file:/opt/homebrew/etc/gitconfig credential.helper=osxkeychain + file:/Users/veit/.config/git/config user.name=veit + file:/Users/veit/.config/git/config user.email=veit@cusy.io + … - * `oh-my-zsh `_ +.. note:: + You can find a comprehensive example of a configuration file in my `dotfiles + `_ repository: `.gitconfig + `_. - * `Git plugin aliases - `_ - * `zsh-you-should-use - `_ +.. _migrate-git-config: - * `Starship `_ +Migrate from :file:`~/.gitconfig` to :file:`~/.config/git/config` +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: - * `git_branch-Modul `_ - * `git_commit-Modul `_ - * `git_state `_ - * `git_status-Modul `_ +If you are currently using the old file name :file:`~/.gitconfig`, you can move +it to the :file:`~/.config` directory in just a few steps: -The editor can also be specified, for example with: +#. Make sure that the :file:`~/.config` directory exists. +#. Move your existing configuration file to its place: -.. code-block:: ini + .. code-block:: console - [core] - editor = vim + $ mv ~/.gitconfig ~/.config/git/config -or for Visual Studio Code: +#. Check whether Git can still read the configuration file by asking for your + user name: -.. code-block:: ini + .. code-block:: console - [core] - editor = code --wait + $ git config --global user.name + Veit Schiele -.. note:: - On macOS, you must first start Visual Studio Code, then open the command - palette with :kbd:`⌘+⇧-p` and finally execute the ``Install 'code' command in - PATH``. +#. You may then have to move other files, for example :file:`~/.gitattributes` + and :file:`~/.gitignore`. You can check whether these files are available + with -The highlighting of space errors in ``git diff`` can also be configured: + .. code-block:: console -.. code-block:: ini + $ git config --global core.excludesFile + ~/.gitignore + $ git config --global core.attributesFile + ~/.gitattributes - [core] - # Highlight whitespace errors in git diff: - whitespace = tabwidth=4,tab-in-indent,cr-at-eol,trailing-space + You must then move the files and delete the associated configuration entries: -.. note:: - In addition to :file:`~/.gitconfig`, since version 1.17.12 Git also looks in - :file:`~/.config/git/config` for a global configuration file. + .. code-block:: console - Under Linux, :file:`~/.config` can sometimes be a different path set by the - environment variable ``XDG_CONFIG_HOME``. This behaviour is part of the `X - Desktop Group (XDG) specification - `_. You - can get the other path with: + $ mv ~/.gitignore_global ~/.config/git/ignore + $ git config --global --unset core.excludesFile + $ mv ~/.gitattributes ~/.config/git/attributes + $ git config --global --unset core.attributesFile - .. code-block:: ini +Read and write configuration entries +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - $ echo $XDG_CONFIG_HOME +As we have already seen above, configuration entries can be read with `git +config `_, for example: -.. seealso:: - * `git config files `_ +.. code-block:: console -Since you can set options at multiple levels, you may want to keep track of -where Git reads a particular value from. With ``git config --list`` [#]_ you can -list all the overridden options and values. You can combine this with -``--show-scope`` [#]_ to see where Git is getting the value from: + $ git config --global user.name + Veit Schiele + +… and to change it .. code-block:: console - $ git config --list --show-scope - system credential.helper=osxkeychain - global user.name=veit - global user.email=veit@cusy.io - … + $ git config --global user.name 'veit' -You can also use ``--show-origin`` [#]_ to list the names of the configuration -files: +You can also edit the configuration file directly by calling ``git config`` with +the ``-e|--edit`` option: .. code-block:: console - $ git config --list --show-origin - file:/opt/homebrew/etc/gitconfig credential.helper=osxkeychain - file:/Users/veit/.config/git/config user.name=veit - file:/Users/veit/.config/git/config user.email=veit@cusy.io - … + $ git config --global -e + +This opens the :file:`~/.config/git/config` file in your default editor: + +.. code-block:: ini + + [user] + name = veit + email = veit@cusy.io + +Git saves its configuration in `INI `_ +files. + +The default editor for Git is defined in the ``GIT_EDITOR`` environment variable +or in Git’s ``core.editor`` option or in the ``VISUAL`` or ``EDITOR`` +environment variable. You can query the values with + +.. code-block:: console + + $ echo $GIT_EDITOR + $ git config core.editor + $ echo $VISUAL + $ echo $EDITOR + +Normally you always want to use the same editor and therefore the ``EDITOR`` +environment variable should be set. To do this, you can enter the following in +:file:`~/.bash_profile` or :file:`~/.zprofile`, for example: + +.. code-block:: sh + + export EDITOR='C:\Program Files (x86)\Microsoft VS Code\code.exe --wait' + +.. note:: + On macOS, you must first start Visual Studio Code, then open the command + palette with :kbd:`⌘+⇧-p` and finally execute the *Install 'code' command in + PATH*. + +or + +.. code-block:: sh + + export EDITOR='vim' + +.. _basic-git-config: + +Basic configuration +~~~~~~~~~~~~~~~~~~~ + +Git commits have two mandatory fields that refer to employees: the author who +wrote the code change and the committer who submitted the code to the +repository. For most workflows, this is the same person. With the options +``user.name`` and ``user.email`` you can configure information for the ``author`` and ``committer``. + +:samp:`$ git config --global user.name "{NAME}"` + defines the name :samp:`{NAME}` associated with your commit transactions. +:samp:`$ git config --global user.email "{EMAIL-ADDRESS}"` + defines the email address :samp:`{EMAIL-ADDRESS}` that will be linked to + your commit transactions. + +.. seealso:: + * `user.name + `_ + +.. tip:: + Git hosts, such as `GitHub `_ or + :doc:`advanced/gitlab/index`, link commits to your profile via the email + address. If your configured email address does not match your profile, your + commits will not be assigned. This makes it difficult for team members to + determine that you have written a specific commit. Therefore, check your + configured name and your e-mail address. + +.. _includeif: Alternative configuration file ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -199,10 +277,10 @@ local configuration in your repository or `conditional includes global configuration: .. code-block:: ini + :caption: ~/.config/git/config - … - [includeIf "gitdir:~/private"] - path = ~/.config/git/config-private + [includeIf "gitdir:~/private"] + path = ~/.config/git/config-private This construct ensures that Git includes additional configurations or overwrites existing ones when you work in :file:`~/private`. @@ -211,6 +289,7 @@ Now create the file :file:`~/.config/git/config-private` and define your alternative configuration there, for example: .. code-block:: ini + :caption: ~/.config/git/config-private [user] email = kontakt@veit-schiele.de @@ -221,6 +300,103 @@ alternative configuration there, for example: * `core.sshCommand `_ +.. _git-colouring: + +Colouring +~~~~~~~~~ + +By default, Git uses your terminal’s ability to colour and format different +types of text. Such colouring allows you to analyse the output more quickly. +However, the default colours are suboptimal: for example, ``git status`` marks +changed files in red, a colour generally associated with errors; however, +changing files is not an error, but perfectly normal in any Git process. You can +use the ``color.*`` options to adjust the colours per command. I have been using +the `cheat sheet colours +`_ +for a long time: + +.. code-block:: ini + + [color "branch"] + current = yellow reverse + local = yellow + remote = green + + [color "status"] + added = yellow + changed = green + untracked = cyan + +.. note:: + Later we will look at :ref:`git-delta`, a tool to better visualise + differences. Its colouring would overwrite information from ``[colour + β€˜diff’]`` and therefore we have not added this section. + +.. _git-autocorrect: + +Correcting commands +~~~~~~~~~~~~~~~~~~~ + +If you make a mistake when entering a Git command, similar commands are listed +by default and the programme is terminated: + +.. code-block:: console + + $ git comit -m ':wrench: Update git config' + git: 'comit' is not a git command. See 'git --help'. + + The most similar command is + commit + +However, you can also configure Git with ``git config --global help.autoCorrect +immediate`` [#]_ so that the first hit is executed automatically: + +.. code-block:: console + + $ git comit -m ':wrench: Update git config' + WARNING: You called a Git command named 'comit', which does not exist. + Continuing under the assumption that you meant 'commit'. + [main 48cafbf5f] :wrench: Update git config + +However, Git only corrects automatically if a command has a sufficiently large +match. If there are several potential matches, these are listed and the +correction is cancelled: + +.. code-block:: console + + $ git co -m ':wrench: Update git config' + git: 'co' is not a git command. See 'git --help'. + + The most similar commands are + commit + clone + log + +If the automatic correction of an command is too much for you, you can use the +*Prompt* mode instead: + +.. code-block:: console + + $ git config --global help.autoCorrect prompt + $ git comit -m ':wrench: Update git config' + WARNING: You called a Git command named 'comit', which does not exist. + Run 'commit' instead [y/N]? y + [main 48cafbf5f] :wrench: Update git config + +.. _git-pagination: + +Pagination +~~~~~~~~~~ + +You can activate pagination by default for a command by setting the +corresponding option: :samp:`pager.{CMD} = true`. [#]_ For example, to switch +git status to pagination: + +.. code-block:: console + + $ git config --global pager.status true + +.. _credential-helper: Manage login data ~~~~~~~~~~~~~~~~~ @@ -240,74 +416,86 @@ If necessary, the timeout can be increased, for example with: $ git config --global credential.helper 'cache --timeout=3600' +.. tab:: Debian/Ubuntu + + With Linux you have to select a so-called: `Credential Store + `_. + In most cases, you will opt for the *Secret Service API*, such as + ``libsecret`` from Git, which you can select with: + + .. code-block:: console + + $ git config --global credential.credentialStore secretservice .. tab:: macOS - With macOS you can use `osxkeychain` to store the login information. - `osxkeychain` requires Git version 1.7.10 or newer and can be installed in - the same directory as Git with: + With macOS you can use ``osxkeychain`` to store the login information. + ``osxkeychain`` requires Git version 1.7.10 or newer and can be installed in + the same directory as Git with: - .. code-block:: console + .. code-block:: console - $ git credential-osxkeychain - git: 'credential-osxkeychain' is not a git command. See 'git --help'. - $ curl -s -O http://github-media-downloads.s3.amazonaws.com/osx/git-credential-osxkeychain - $ chmod u+x git-credential-osxkeychain - $ sudo mv git-credential-osxkeychain /usr/bin/ - Password: - git config --global credential.helper osxkeychain + $ git credential-osxkeychain + git: 'credential-osxkeychain' is not a git command. See 'git --help'. + $ curl -s -O http://github-media-downloads.s3.amazonaws.com/osx/git-credential-osxkeychain + $ chmod u+x git-credential-osxkeychain + $ sudo mv git-credential-osxkeychain /usr/bin/ + Password: + git config --global credential.helper osxkeychain - This enters the following in the :file:`~/.gitconfig` file: + This enters the following in the :file:`~/.gitconfig` file: - .. code-block:: ini + .. code-block:: ini - [credential] - helper = osxkeychain + [credential] + helper = osxkeychain -.. tab:: Windows + Alternatively, you can also install the `Git Credential Manager + `_ with + + .. code-block:: console + + brew install --cask git-credential-manager - For Windows, `Git Credential Manager (GCM) - `_ is available. It - is integrated in `Git for Windows `_ and - is installed by default. However, there is also a standalone Installer in - `Releases - `_. +.. tab:: Windows - It is configured with + For Windows, `Git Credential Manager (GCM) + `_ is available. It + is integrated in `Git for Windows `_ and + is installed by default. However, there is also a standalone Installer in + `Releases + `_. - .. code-block:: console + It is configured with - $ git credential-manager configure - Configuring component 'Git Credential Manager'... - Configuring component 'Azure Repos provider'... + .. code-block:: console - This will add the ``[credential]`` section to your :file:`~.gitconfig` file: + $ git credential-manager configure + Configuring component 'Git Credential Manager'... + Configuring component 'Azure Repos provider'... - .. code-block:: ini + This will add the ``[credential]`` section to your :file:`~.gitconfig` file: - [credential] - helper = - helper = C:/Program\\ Files/Git/mingw64/bin/git-credential-manager.exe + .. code-block:: ini - Now, when cloning a repository, a *Git Credential Manager* window opens and asks you - to enter your credentials. + [credential] + helper = + helper = C:/Program\\ Files/Git/mingw64/bin/git-credential-manager.exe - In addition, the :file:`~/.gitconfig` file is supplemented, for example by - the following two lines: + Now, when cloning a repository, a *Git Credential Manager* window opens and + asks you to enter your credentials. - .. code-block:: ini + In addition, the :file:`~/.gitconfig` file is supplemented, for example by + the following two lines: - [credential "https://ce.cusy.io"] - provider = generic + .. code-block:: ini -.. note:: - You can find a comprehensive example of a :file:`~/.gitconfig` file in my - `dotfiles `__ repository: `.gitconfig - `__. + [credential "https://ce.cusy.io"] + provider = generic .. seealso:: - * `Git Credential Manager: authentication for everyone - `_ + * `Git Credential Manager: authentication for everyone + `_ .. _gitignore: @@ -319,10 +507,10 @@ typical :file:`.gitignore` file can look like this: .. code-block:: ini - /logs/* - !logs/.gitkeep - /tmp - *.swp + /logs/* + !logs/.gitkeep + /tmp + *.swp In doing so, Git uses `Globbing `_ patterns, among others: @@ -437,27 +625,28 @@ content in an empty directory: .. code-block:: ini - # ignore everything except .gitignore - * - !.gitignore + # ignore everything except .gitignore + * + !.gitignore .. seealso: - * `Can I add empty directories? - `_ + * `Can I add empty directories? + `_ + +.. _excludesfile: ``excludesfile`` :::::::::::::::: However, you can also exclude files centrally for all Git repositories. For this -purpose, you can set ``excludesfile`` in the :file:`~/.gitconfig` file: +purpose, you can set ``excludesfile`` in the :file:`~/.config/git/config` file: .. code-block:: ini - [core] - - # Use custom `.gitignore` - excludesfile = ~/.gitignore - … + [core] + # Use custom ignore file + excludesfile = ~/.config/git/ignore + … .. note:: You can find helpful templates in my `dotfiles @@ -476,14 +665,14 @@ working directory as an ignored file. .. code-block:: console - $ echo *.log >> .gitignore - $ git rm --cached *.log - rm 'instance.log' - $ git commit -m "Remove log files" + $ echo *.log >> .gitignore + $ git rm --cached *.log + rm 'instance.log' + $ git commit -m "Remove log files" .. note:: - You can omit the ``--cached`` option if you want to remove the file from - both the repository and your local file system. + You can omit the ``--cached`` option if you want to remove the file from both + the repository and your local file system. Commit an ignored file :::::::::::::::::::::: @@ -493,10 +682,10 @@ It is possible to force the commit of an ignored file to the repository with the .. code-block:: console - $ cat data/.gitignore - * - $ git add -f data/iris.csv - $ git commit -m "Force add iris.csv" + $ cat data/.gitignore + * + $ git add -f data/iris.csv + $ git commit -m "Force add iris.csv" You might consider this if you have a general pattern (like ``*``) defined, but want to commit a specific file. However, a better solution is usually to define @@ -504,12 +693,12 @@ an exception to the general rule: .. code-block:: console - $ echo '!iris.csv' >> data/.gitignore - $ cat data/.gitignore - * - !iris.csv - $ git add data/iris.csv - $ git commit -m "Add iris.csv" + $ echo '!iris.csv' >> data/.gitignore + $ cat data/.gitignore + * + !iris.csv + $ git add data/iris.csv + $ git commit -m "Add iris.csv" This approach should be more obvious and less confusing for your team. @@ -609,6 +798,9 @@ delete it: `_ .. [#] `git config --show-origin `_ +.. [#] `help.autoCorrect + `_ +.. [#] `pager.cmd `_ .. [#] `git status --ignored `_ .. [#] `git check-ignore diff --git a/docs/productive/git/rebase.rst b/docs/productive/git/rebase.rst index 60df3e77..a97ba004 100644 --- a/docs/productive/git/rebase.rst +++ b/docs/productive/git/rebase.rst @@ -60,6 +60,8 @@ Git 2.38 ships with a new ``--update-refs`` option for ``git rebase`` that will perform such updates for you without you having to manually update each branch and without subsequent branches losing their history. +.. _rebase-updaterefs: + If you want to use this option on every rebase, you can run ``git config --global rebase.updateRefs true`` to make Git behave as if the ``--update-refs`` option is always specified. diff --git a/docs/productive/git/tag.rst b/docs/productive/git/tag.rst index 0e0fcda9..5cbe295f 100644 --- a/docs/productive/git/tag.rst +++ b/docs/productive/git/tag.rst @@ -10,6 +10,9 @@ allows certain points in the history to be marked for a particular version, for example :samp:`v3.9.16`. Tags are like :doc:`branch` that do not change, so have no further history of commits. +``git tag`` +----------- + :samp:`$ git tag {TAGNAME}` creates a tag, where :samp:`{TAGNAME}` is a semantic label for the current state of the Git repository. Git distinguishes between two different types @@ -116,3 +119,18 @@ no further history of commits. $ git tag -d v3.9.16 $ git push origin --delete v3.9.16 + +``git describe`` +---------------- + +The :samp:`git describe {SH}` command finds the most recent tag that can be +reached from a commit. If the tag points to the commit, only the tag is +displayed, otherwise the number of additional commits is appended to the tag +name. The result is an object name that can be used by other Git commands to +identify the commit. Assuming you have a commit SHA and want to know in which +version it was first published, you can use the following command: + +.. code-block:: console + + $ git describe --contains 39ff38d | sed -E 's/[~^][0-9]*//g' + 24.1.0 diff --git a/docs/productive/git/work.rst b/docs/productive/git/work.rst index bd8f8bff..7b7697ab 100644 --- a/docs/productive/git/work.rst +++ b/docs/productive/git/work.rst @@ -7,6 +7,7 @@ Working with Git Start working on a project -------------------------- +.. _git-init: Start your own project ~~~~~~~~~~~~~~~~~~~~~~ @@ -20,12 +21,34 @@ Start your own project If no project name is given, the current directory is initialised. + .. tip:: + The default branch in Git is ``master``. However, as `this term is + offensive to some people + `_, the + default branch name can be configured in Git β‰₯ 2.28: + + .. code-block:: console + + $ git config --global init.defaultBranch main + + Most Git hosts also use *main* as the standard for new repositories. + Work on a project ~~~~~~~~~~~~~~~~~ -:samp:`$ git clone {PROJECT_URL}` +:samp:`$ git clone {SOURCE}` downloads a project with all branches and the entire history from the remote - repository. + repository, for example: + + .. code-block:: console + + $ git clone https://github.com/cusyio/Python4DataScience.git + + or + + .. code-block:: console + + $ git clone git@github.com:cusyio/Python4DataScience.git ``--depth`` indicates the number of commits to be downloaded. @@ -49,6 +72,73 @@ Work on a project `git status -v `_ + ``git status -s|--short`` + shows the status in short format, for example + + .. code-block:: console + + $ git status -s + M docs/productive/git/work.rst + ?? Python4DataScience.txt + + The preceding letters indicate the status of the file. + + ``git status`` gives a lot of advice on what to do with the files in the + individual states: + + .. code-block:: console + + $ git status + On branch main + Your branch and 'origin/main' have diverged, + and have 1 and 1 different commits each, respectively. + (use "git pull" if you want to integrate the remote branch with yours) + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git restore ..." to discard changes in working directory) + modified: docs/productive/git/work.rst + Untracked files: + (use "git add ..." to include in what will be committed) + Python4DataScience.txt + + no changes added to commit (use "git add" and/or "git commit -a") + + .. _git-statushints: + + If you are familiar with Git, you may find these hints unnecessary. Then you + can deactivate these messages with the ``advice.statusHints`` option: + + .. code-block:: console + + $ git config --global advice.statusHints false + + From now on, calling ``git status`` will no longer display any hints: + + .. code-block:: console + + $ git status + On branch main + Your branch and 'origin/main' have diverged, + and have 1 and 1 different commits each, respectively. + + Changes not staged for commit: + modified: docs/productive/git/work.rst + + Untracked files: + Python4DataScience.txt + + no changes added to commit (use "git add" and/or "git commit -a") + + Also when calling ``git-switch`` and ``git-checkout`` as well as when + writing commit messages, no more hints are displayed. + + .. tip:: + Although there are many other `advice.* + `_ + options, most of them are quite insignificant, so they should only be + excluded when they start to interfere. + :samp:`$ git add {PATH}` adds one or more files to the stage area. @@ -62,16 +152,30 @@ Work on a project .. code-block:: console - $ git diff docs/productive/git/work.rst - diff --git a/docs/productive/git/work.rst b/docs/productive/git/work.rst - index e2a5ea6..fd84434 100644 - --- a/docs/productive/git/work.rst - +++ b/docs/productive/git/work.rst - @@ -46,7 +46,7 @@ + $ git diff docs/productive/git/work.rst + diff --git a/docs/productive/git/work.rst b/docs/productive/git/work.rst + index e2a5ea6..fd84434 100644 + --- a/docs/productive/git/work.rst + +++ b/docs/productive/git/work.rst + @@ -46,7 +46,7 @@ + + :samp:`$ git diff {FILE}` + - shows differences between work and stage areas. + + shows differences between work and stage areas, for example: + + By default, Git adds the prefixes ``a/`` and ``b/`` in front of the file + paths to the diff format. + + .. tip:: + These prefixes are intended to mark the paths as * old* and * new* , but + they prevent the file paths from being easily copied – some terminals + also allow you to click on file paths to open them – but the prefixes + prevent this. You can change this with a new function in Git 2.45: - :samp:`$ git diff {FILE}` - - shows differences between work and stage areas. - + shows differences between work and stage areas, for example: + .. code-block:: console + + $ git config --global diff.srcPrefix './' + $ git config --global diff.dstPrefix './' ``index e2a5ea6..fd84434 100644`` displays some internal Git metadata that you will probably never need. The numbers correspond to the hash @@ -112,6 +216,9 @@ Work on a project ``--word-diff`` shows the changed words. + .. seealso:: + * :ref:`git-name-only` + :samp:`$ git restore {FILE}` changes files in the working directory to a state previously known to Git. By default, Git checks out ``HEAD``, the last commit of the current branch. @@ -130,8 +237,13 @@ Work on a project writes a commit message directly from the command line. ``--dry-run --short`` shows what would be committed with the status in short format. + :samp:`-m '{FILE}'` + passes file names or `globbing + `_ patterns to ``git + commit`` to commit changes to these files, skipping any changes that + already exist in the staging area with git add. -``$ git reset [--hard|--soft] [TARGET_REFERENCE]`` +:samp:`$ git reset [--hard|--soft] [{TARGET_REFERENCE}]` resets the history to an earlier commit. :samp:`$ git rm {PATH}` removes a file from the work and stage areas. @@ -178,6 +290,25 @@ Work on a project | ``?`` | Help | +---------------+-----------------------------------------------+ + .. _git-singlekey: + + .. tip:: + Usually you have to press the :kbd:`β†©οΈŽ` key after every command with a + letter. However, you can switch off this overhead: + + .. code-block:: console + + $ git config --global interactive.singleKey true + + .. _git-autostash: + + You can also automatically apply stash for merge and rebase: + + .. code-block:: console + + $ git config --global merge.autoStash true + $ git config --global rebase.autoStash true + ``branch`` creates a branch from hidden files, for example: diff --git a/docs/productive/git/workflows/ci.rst b/docs/productive/git/workflows/ci.rst index 6bc06755..9f9629d5 100644 --- a/docs/productive/git/workflows/ci.rst +++ b/docs/productive/git/workflows/ci.rst @@ -30,21 +30,28 @@ the current working directory. Git usually clones the entire history of the repository, so this process takes longer and longer over time. Unless you use so-called shallow clones, where only the current snapshot of the repository is pulled down with :ref:`git-clone-depth` and only the relevant branch with -:ref:`git-clone-branch`. This shortens the build time, especially for -repositories with a long history and many branches. +:ref:`git-clone-branch`, for example :samp:`git clone --depth 1 -b {MYBRANCH} +{REPOSITORY-URL}`. This shortens the build time, especially for repositories +with a long history and many branches. -In doing so, since version 1.9, Git can make simple changes to files, such as -updating a version number, without pushing the entire history. +Alternatively, you can use ``--shallow-since`` to download repositories only +from a specific date, for example :samp:`git +clone --shallow-since {1.week.ago} {REPOSITORY-URL}` or :samp:`git clone +--shallow-since {2025-01-21}`. + +Since version 1.9, Git can also make simple changes to files, such as updating a +version number, in shallow clones without having to download the entire history. .. warning:: - In a shallow clone, git fetch can result in an almost complete commit - history being downloaded. Other git operations can also lead to unexpected - results and negate the supposed advantages of shallow clones, so we - recommend using shallow clones only for builds and deleting the repository - immediately afterwards. - -However, if you want to continue using the repositories, the following tip may -be helpful. + In a shallow clone, however, ``git fetch`` can lead to an almost complete + commit history being downloaded. Other Git operations can also lead to + unexpected results and cancel out the supposed advantages of shallow clones, + so we recommend completing your shallow clone repositories with ``git fetch + --unshallow`` for more extensive operations. You can then use ``git rev-parse + --is-shallow-repository`` to find out whether your repository is actually + complete. + +I will show you another way to reuse your repositories in the following section. Cache the repo on build servers ------------------------------- diff --git a/docs/productive/git/workflows/monorepos.rst b/docs/productive/git/workflows/monorepos.rst index 09e73f3d..5c7b1b81 100644 --- a/docs/productive/git/workflows/monorepos.rst +++ b/docs/productive/git/workflows/monorepos.rst @@ -256,6 +256,8 @@ the search: `_ * `Scaling monorepo maintenance `_ + * `fsmonitor-watchman + `_ Scalar ------ diff --git a/docs/productive/git/working-areas.rst b/docs/productive/git/working-areas.rst index fe48bb2d..364bd6e3 100644 --- a/docs/productive/git/working-areas.rst +++ b/docs/productive/git/working-areas.rst @@ -28,7 +28,30 @@ stash Basic Git commands ------------------ -The following basic Git commands move changes between these workspaces. +The following basic Git commands are used to move changes between these +workspaces. + + +.. hint:: + Shell commands use a Bash-compatible syntax. They should therefore be + compatible with the most common shells used for Git: + + * Windows: Git Bash + * WSL: Bash + * Linux: Bash or Zsh + * macOS: Zsh + + You may have to adjust the syntax slightly if you use a different shell, for + example PowerShell. + +.. hint:: + This book concentrates on the command line and only deals with :abbr:`GUI + (Graphical user interface)`’s in passing. The command line is the most + powerful way to use Git. GUIs implement only a subset of what is possible + with Git and the shell. Nevertheless, a hybrid approach is possible and + widely used with many GUIs: You can use a GUI for tasks, and the CLI for + full performance. You can select a suitable GUI tool in `GUI Clients + `_. ``git add`` adds files from the working directory to the staging area. diff --git a/pyproject.toml b/pyproject.toml index e075a26d..2b9a18a1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,4 +44,4 @@ packages = [] [tool.codespell] skip = "*.csv, *.pdf, *.ipynb, ./docs/_build/*, ./styles/*" -ignore-words-list = "fo, AAS, ans, Groth, Ned, Redict, redict, reStructedText, splitted" +ignore-words-list = "AAS, ans, comit, fo, Groth, Ned, Redict, redict, reStructedText, splitted"