Git pro mě/Rebase je základ

Teďka poznámky k vytvoření repozitáře pro workshop rebase is base. Úkol zní jasně: Vytvořte Python3 balíček args, který obsahuje modul evaluator s procedurouev.

def ev(op, *args):
    """Return value computed from ``args`` based on ``op``.

    Procedure ``ev`` returns:
    - sum of arguments for ``op == "+"``,
    - product of arguments for ``op == "*"``,
    - true if arguments are non-descending for ``op == "<"``,
    - true if arguments are non-increasing for ``op == ">"``.

    :param op: An operator (as string) to be applied to ``args``.
    :param args: The list (of numbers) to apply ``op`` to.
    """
    pass  # TODO

Výpisy příkazů se často opakují a jsou dlouhé. Je to proto, že jsem zaznamenával příkazy (včetně výpisů) tak, jak jsem historii tvořil. Často se ujišťuji o stavu repozitáře a často výpisy příkazů jen prolétnu, než abych je četl. Všechny příkazy píšu do příkazové řádky v adresáři args (root repozitáře).

Inicializace repozitáře

editovat

Před zaznamenáváním historie je potřeba připravit repozitář pro sledování změn:

$ git init
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint:
hint:   git config --global init.defaultBranch <name>
hint:
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint:
hint:   git branch -m <name>
Initialized empty Git repository in /full/path/to/args/.git/

a nastavit základní informace o autorovi změn:

$ git config user.email 'foo@bar.buzz'
$ git config --global user.name 'Foo Bar'

Přidání licence a readme

editovat

Jako první přidám soubory s licencí a readme. Licence je důležitá proto, aby kód mohl znovupoužít někdo další. Často používám MIT Licenci.

Readme píšu pro sebe. Chci vědět, CO je pointa, protože to do zítra zapomenu. Občas to, co si napíšu, zní dost divně, takže přidám PROČ zrovna to. Navíc do readme přidám JAK dělat věci, které dělám pořád (třeba jak projekt zkompilovat) a v neposlední řadě KAM a KOMU napsat dotaz či bug report (komunikační kanál).

$ git status
On branch master

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        LICENSE
        README

nothing added to commit but untracked files present (use "git add" to track)
$ git add LICENSE README
$ git status
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   LICENSE
        new file:   README
$ git diff --cached
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..5fd1bda
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2023 Foo Bar
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README b/README
new file mode 100644
index 0000000..4e3d26f
--- /dev/null
+++ b/README
@@ -0,0 +1,2 @@
+Python3 package with the procedure evaluating arguments based on the
+operator.

Pokud jsem spokojený s výsledkem příkazu git diff --cached, přidám změnu do historie:

$ git commit

Tim se otevře okno výchozího editoru, napíšu stručně co přidávám a zavřu jej.

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# On branch master
#
# Initial commit
#
# Changes to be committed:
#	new file:   LICENSE
#	new file:   README
#

Vim se zavírá ZZ (tedy "shift" a dvakrát "z"). Výchozí editor se dá nastavit:

git config --global core.editor 'vim'

Jde použít i jiný editor:

git config --global core.editor 'gedit'
git config --global core.editor 'notepad'

Při práci na Windows je vhodné vynutit stejné zakončení řádků, jaké používá git:

git config core.autocrlf false
git config core.eol lf

Stručné zprávě se říká commit message. Může mít více řádků, kde první řádek začíná velkým pismenem, má maximálně 52 znaků, nepíše se tečka a je to imperativní pokračování věty "When applied, this patch will ...". Pak jeden prázdný řádek a nakonec zbytek textu, popisující CO a PROČ, zarovnaný na 72 znaků. JAK je v kódu.

Add license, readme

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# On branch master
#
# Initial commit
#
# Changes to be committed:
#	new file:   LICENSE
#	new file:   README
#
$ git commit
[master (root-commit) 8dc1c0a] Add license, readme
 2 files changed, 21 insertions(+)
 create mode 100644 LICENSE
 create mode 100644 README
$ git status
On branch master
nothing to commit, working tree clean

Prohlédnu a zkontroluji historii změn:

$ git log
commit 8dc1c0a0e483227c03810acbc6a52882492d0012 (HEAD -> master)
Author: Foo Bar <foo@bar.buzz>
Date:   Mon Jun 26 22:39:23 2023 +0200

    Add license, readme
$ git show
commit 8dc1c0a0e483227c03810acbc6a52882492d0012 (HEAD -> master)
Author: Foo Bar <foo@bar.buzz>
Date:   Mon Jun 26 22:39:23 2023 +0200

    Add license, readme

diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..5fd1bda
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2023 Foo Bar
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README b/README
new file mode 100644
index 0000000..4e3d26f
--- /dev/null
+++ b/README
@@ -0,0 +1,2 @@
+Python3 package with the procedure evaluating arguments based on the
+operator.

Dost často, a to i v dalších sekcích, kontroluji repozitář pomocí příkazů:

git status
git diff
git diff --cached
git log
git show
git logg

Ten poslední je alias pro git log --oneline --graph --decorate --all, který můžu nastavit příkazem:

git config --global --add alias.logg 'log --oneline --graph --decorate --all'
$ git logg
* d0dbc16 (HEAD -> master) Add license, readme

Přidání operátoru "+"

editovat

Nejprve je potřeba přidat Python3 balíček args.

$ git status
On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        args/

nothing added to commit but untracked files present (use "git add" to track)
$ tree
.
├── args
│   └── __init__.py
├── LICENSE
└── README

1 directory, 3 files
$ git add args/
$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   args/__init__.py
$ git commit
[master d26defa] Add args package
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 args/__init__.py
$ git show
commit d26defa80cf953415b2b826825c2d641fa28960a (HEAD -> master)
Author: Foo Bar <foo@bar.buzz>
Date:   Tue Jun 27 00:56:49 2023 +0200

    Add args Python3 package

diff --git a/args/__init__.py b/args/__init__.py
new file mode 100644
index 0000000..e69de29

Potom přidat evaluator modul s procedurou ev; není čas ztrácet čas, takže rovnou s implementací operátoru "+".

$ git status
On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        args/evaluator.py

nothing added to commit but untracked files present (use "git add" to track)
$ tree
.
├── args
│   ├── evaluator.py
│   └── __init__.py
├── LICENSE
└── README

1 directory, 4 files
$ cat args/evaluator.py
def ev(op, *args):
    if "+" == op:
        s = 0
        for a in args:
            s += a
        return s
$ git add args/evaluator.py
$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   args/evaluator.py
$ git commit
[master 0da38ec] Add evaluator module, operator "+"
1 file changed, 6 insertions(+)
create mode 100644 args/evaluator.py
$ git show
commit 0da38ece7090b024298053cc6ee7fba1c4b05b3d (HEAD -> master)
Author: Foo Bar <foo@bar.buzz>
Date:   Tue Jun 27 01:10:10 2023 +0200

    Add evaluator module, operator "+"

diff --git a/args/evaluator.py b/args/evaluator.py
new file mode 100644
index 0000000..13c2609
--- /dev/null
+++ b/args/evaluator.py
@@ -0,0 +1,6 @@
+def ev(op, *args):
+    if "+" == op:
+        s = 0
+        for a in args:
+            s += a
+        return s

Nakonec přidat unit testy ...

$ git status
On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        tests/

nothing added to commit but untracked files present (use "git add" to track)
$ tree
.
├── args
│   ├── evaluator.py
│   └── __init__.py
├── LICENSE
├── README
└── tests
    └── test_sum.py

2 directories, 5 files
$ cat tests/test_sum.py
from unittest import TestCase

from args.evaluator import ev


class TestEvaluator(TestCase):
    def test_sum(self):
        assert 6 == ev("+", 1, 2, 3)
$ git add tests/
$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   tests/test_sum.py
$ git commit
[master 2bd56ca] Add operator "+" unit test
 1 file changed, 8 insertions(+)
 create mode 100644 tests/test_sum.py
$ git show
commit 2bd56ca80495fd03819b7a6fe842136593a2343d (HEAD -> master)
Author: Foo Bar <foo@bar.buzz>
Date:   Tue Jun 27 01:20:38 2023 +0200

    Add operator "+" unit test

diff --git a/tests/test_sum.py b/tests/test_sum.py
new file mode 100644
index 0000000..9699439
--- /dev/null
+++ b/tests/test_sum.py
@@ -0,0 +1,8 @@
+from unittest import TestCase
+
+from args.evaluator import ev
+
+
+class TestEvaluator(TestCase):
+    def test_sum(self):
+        assert 6 == ev("+", 1, 2, 3)
$ python3 -m unittest discover tests
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

... a prozkoumat aktuální stav repozitáře.

$ git status
On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        args/__pycache__/
        tests/__pycache__/

nothing added to commit but untracked files present (use "git add" to track)
$ tree
.
├── args
│   ├── evaluator.py
│   ├── __init__.py
│   └── __pycache__
│       ├── evaluator.cpython-39.pyc
│       └── __init__.cpython-39.pyc
├── LICENSE
├── README
└── tests
    ├── __pycache__
    │   └── test_sum.cpython-39.pyc
    └── test_sum.py

4 directories, 8 files
$ git log
commit 2bd56ca80495fd03819b7a6fe842136593a2343d (HEAD -> master)
Author: Foo Bar <foo@bar.buzz>
Date:   Tue Jun 27 01:20:38 2023 +0200

    Add operator "+" unit test

commit 0da38ece7090b024298053cc6ee7fba1c4b05b3d
Author: Foo Bar <foo@bar.buzz>
Date:   Tue Jun 27 01:10:10 2023 +0200

    Add evaluator module, operator "+"

commit fe22dec52bb37dba41e0f211c2c5ab9a0a90720d
Author: Foo Bar <foo@bar.buzz>
Date:   Tue Jun 27 00:56:49 2023 +0200

    Add args Python3 package

commit d0dbc16408ef5bbe2c2949c8a123185ee3e2614c
Author: Foo Bar <foo@bar.buzz>
Date:   Mon Jun 26 22:59:20 2023 +0200

    Add license, readme
$ git show
commit 2bd56ca80495fd03819b7a6fe842136593a2343d (HEAD -> master)
Author: Foo Bar <foo@bar.buzz>
Date:   Tue Jun 27 01:20:38 2023 +0200

    Add operator "+" unit test

diff --git a/tests/test_sum.py b/tests/test_sum.py
new file mode 100644
index 0000000..9699439
--- /dev/null
+++ b/tests/test_sum.py
@@ -0,0 +1,8 @@
+from unittest import TestCase
+
+from args.evaluator import ev
+
+
+class TestEvaluator(TestCase):
+    def test_sum(self):
+        assert 6 == ev("+", 1, 2, 3)
$ git show HEAD^
commit 0da38ece7090b024298053cc6ee7fba1c4b05b3d
Author: Foo Bar <foo@bar.buzz>
Date:   Tue Jun 27 01:10:10 2023 +0200

    Add evaluator module, operator "+"

diff --git a/args/evaluator.py b/args/evaluator.py
new file mode 100644
index 0000000..13c2609
--- /dev/null
+++ b/args/evaluator.py
@@ -0,0 +1,6 @@
+def ev(op, *args):
+    if "+" == op:
+        s = 0
+        for a in args:
+            s += a
+        return s
$ git logg
* 2bd56ca (HEAD -> master) Add operator "+" unit test
* 0da38ec Add evaluator module, operator "+"
* fe22dec Add args Python3 package
* d0dbc16 Add license, readme

A ještě schovám generované soubory, aby se mi nepletly.

$ git status
On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        .gitignore

nothing added to commit but untracked files present (use "git add" to track)
$ cat .gitignore
__pycache__
$ git add .gitignore
$ git commit -m'Add gitignore'
[master 1fe5611] Add gitignore
 1 file changed, 1 insertion(+)
 create mode 100644 .gitignore
$ git show
commit 1fe561194e50072a9895f44dc0ebec84a70b1faf (HEAD -> master)
Author: Foo Bar <foo@bar.buzz>
Date:   Tue Jun 27 01:44:13 2023 +0200

    Add gitignore

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..bee8a64
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+__pycache__
$ git logg
* 1fe5611 (HEAD -> master) Add gitignore
* 096d3c8 Add operator "+" unit test
* 0da38ec Add evaluator module, operator "+"
* fe22dec Add args Python3 package
* d0dbc16 Add license, readme
$ git status
On branch master
nothing to commit, working tree clean

Přidání operátoru "*"

editovat

Trochu přeskupím historii -- když přidávám Python3 balíček, je jasné, že budu mít nějaké vygenerované soubory, které nechci ukládat do historie. Commit, který přidává .gitignore přesunu těsně za commit s přidáním balíčku.

$ git rebase -i d0dbc16

Původní historii (zhora dolů) ...

pick fe22dec Add args Python3 package
pick 0da38ec Add evaluator module, operator "+"
pick 5d73571 Add operator "+" unit test
pick 4450ade Add gitignore

# Rebase d0dbc16..4450ade onto d0dbc16 (4 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#

... upravím přehozením řádků.

pick fe22dec Add args Python3 package
pick 4450ade Add gitignore
pick 0da38ec Add evaluator module, operator "+"
pick 5d73571 Add operator "+" unit test

# Rebase d0dbc16..4450ade onto d0dbc16 (4 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
$ git rebase -i d0dbc16
Successfully rebased and updated refs/heads/master.
$ git logg
* ac5242f (HEAD -> master) Add operator "+" unit test
* 4cae1c7 Add evaluator module, operator "+"
* 24784c8 Add gitignore
* fe22dec Add args Python3 package
* d0dbc16 Add license, readme

Asi bude lepší dát testy do jednoho souboru, kde se otestují všechny operátory. Opravím poslední commit.

$ git mv tests/test_sum.py tests/test_operators.py
$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        renamed:    tests/test_sum.py -> tests/test_operators.py
$ git commit --amend

Commit zprávu nechám.

Add operator "+" unit test

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Tue Jun 27 01:20:38 2023 +0200
#
# On branch master
# Changes to be committed:
#	new file:   tests/test_operators.py
#
$ git commit --amend
[master fdebe49] Add operator "+" unit test
 Date: Tue Jun 27 01:20:38 2023 +0200
 1 file changed, 8 insertions(+)
 create mode 100644 tests/test_operators.py
$ git status
On branch master
nothing to commit, working tree clean
$ tree
.
├── args
│   ├── evaluator.py
│   ├── __init__.py
│   └── __pycache__
│       ├── evaluator.cpython-39.pyc
│       └── __init__.cpython-39.pyc
├── LICENSE
├── README
└── tests
    ├── __pycache__
    │   └── test_sum.cpython-39.pyc
    └── test_operators.py

4 directories, 8 files

Přidám unit testy pro operátor "*".

$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   tests/test_operators.py

no changes added to commit (use "git add" and/or "git commit -a")
$ git add tests/test_operators.py
$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   tests/test_operators.py
$ git diff
$ git diff --cached
diff --git a/tests/test_operators.py b/tests/test_operators.py
index 9699439..b57f0f3 100644
--- a/tests/test_operators.py
+++ b/tests/test_operators.py
@@ -6,3 +6,6 @@ from args.evaluator import ev
 class TestEvaluator(TestCase):
     def test_sum(self):
         assert 6 == ev("+", 1, 2, 3)
+
+    def test_prod(self):
+        assert 6 == ev("*", 1, 2, 3)
$ python3 -m unittest discover tests
F.
======================================================================
FAIL: test_prod (test_operators.TestEvaluator)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/jiri/args/tests/test_operators.py", line 11, in test_prod
    assert 6 == ev("*", 1, 2, 3)
AssertionError

----------------------------------------------------------------------
Ran 2 tests in 0.000s

FAILED (failures=1)
$ git commit -m'Add operator "*" unit test'
[master 865b12b] Add operator "*" unit test
 1 file changed, 3 insertions(+)
$ git logg
* 865b12b (HEAD -> master) Add operator "*" unit test
* 44eda15 Add operator "+" unit test
* 4cae1c7 Add evaluator module, operator "+"
* 24784c8 Add gitignore
* fe22dec Add args Python3 package
* d0dbc16 Add license, readme

Implementuji operátor "*".

$ git diff
diff --git a/args/evaluator.py b/args/evaluator.py
index 13c2609..d964dca 100644
--- a/args/evaluator.py
+++ b/args/evaluator.py
@@ -4,3 +4,8 @@ def ev(op, *args):
         for a in args:
             s += a
         return s
+    elif "*" == op:
+        p = 1
+        for a in args:
+            p *= a
+        return p
$ python3 -m unittest discover tests
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK
$ git add args/evaluator.py
$ git commit -m'Add operator "*"'
[master d9212c1] Add operator "*"
 1 file changed, 5 insertions(+)
$ git logg
* d9212c1 (HEAD -> master) Add operator "*"
* 865b12b Add operator "*" unit test
* 44eda15 Add operator "+" unit test
* 4cae1c7 Add evaluator module, operator "+"
* 24784c8 Add gitignore
* fe22dec Add args Python3 package
* d0dbc16 Add license, readme

Podle Test Driven Development se testy píší před implementací, tak ať je to alespoň v historii správně.

$ git rebase -i d0dbc16
pick fe22dec Add args Python3 package
pick 24784c8 Add gitignore
pick 4cae1c7 Add evaluator module, operator "+"
pick 44eda15 Add operator "+" unit test
pick 865b12b Add operator "*" unit test
pick d9212c1 Add operator "*"

# Rebase d0dbc16..d9212c1 onto d0dbc16 (6 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#

Přeskupit commity:

pick fe22dec Add args Python3 package
pick 24784c8 Add gitignore
pick 44eda15 Add operator "+" unit test
pick 4cae1c7 Add evaluator module, operator "+"
pick 865b12b Add operator "*" unit test
pick d9212c1 Add operator "*"

# Rebase d0dbc16..d9212c1 onto d0dbc16 (6 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#

Výsledek rebase:

$ git rebase -i d0dbc16
Successfully rebased and updated refs/heads/master.

Aktuální historie:

$ git logg
* 0681891 (HEAD -> master) Add operator "*"
* 03b9ab3 Add operator "*" unit test
* 5ed5048 Add evaluator module, operator "+"
* e77e2a0 Add operator "+" unit test
* 24784c8 Add gitignore
* fe22dec Add args Python3 package
* d0dbc16 Add license, readme

Nakonec ověřím, že všechny testy úspěšně projdou:

$ python3 -m unittest discover tests
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

Přidání docstringu pro "+" a "*" unit testy

editovat

Přidám docstring pro test_operators modul a pro test_sum a test_prod metody a změny přidám do historie.

$ git add -p tests/test_operators.py
diff --git a/tests/test_operators.py b/tests/test_operators.py
index b57f0f3..5dfc209 100644
--- a/tests/test_operators.py
+++ b/tests/test_operators.py
@@ -1,3 +1,4 @@
+"""Unit tests for the Evaluator's operators."""
 from unittest import TestCase

 from args.evaluator import ev
(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]? y
@@ -5,7 +6,9 @@ from args.evaluator import ev

 class TestEvaluator(TestCase):
     def test_sum(self):
+        """Test the operator "+"."""
         assert 6 == ev("+", 1, 2, 3)

     def test_prod(self):
+        """Test the operator "*"."""
         assert 6 == ev("*", 1, 2, 3)
(2/2) Stage this hunk [y,n,q,a,d,K,g,/,s,e,?]? s
Split into 2 hunks.
@@ -5,6 +6,7 @@

 class TestEvaluator(TestCase):
     def test_sum(self):
+        """Test the operator "+"."""
         assert 6 == ev("+", 1, 2, 3)

     def test_prod(self):
(2/3) Stage this hunk [y,n,q,a,d,K,j,J,g,/,e,?]? y
@@ -8,4 +10,5 @@
         assert 6 == ev("+", 1, 2, 3)

     def test_prod(self):
+        """Test the operator "*"."""
         assert 6 == ev("*", 1, 2, 3)
(3/3) Stage this hunk [y,n,q,a,d,K,g,/,e,?]? n

git add -p mi dovolí přidat jen některé změny v souboru. y změnu přidá, n změnu nepřidá a s změnu rozdělí na menší změny, pokud je to možné.

Mimochodem, na aktuálním stavu repozitáře, jmenovitě na souboru test_operators.py je krásně vidět rozdíl mezi změnami, které jsou připravené pro zápis do historie a mezi těmi, které ne.

$ git diff
diff --git a/tests/test_operators.py b/tests/test_operators.py
index a01cdb0..5dfc209 100644
--- a/tests/test_operators.py
+++ b/tests/test_operators.py
@@ -10,4 +10,5 @@ class TestEvaluator(TestCase):
         assert 6 == ev("+", 1, 2, 3)

     def test_prod(self):
+        """Test the operator "*"."""
         assert 6 == ev("*", 1, 2, 3)
$ git diff --cached
diff --git a/tests/test_operators.py b/tests/test_operators.py
index b57f0f3..a01cdb0 100644
--- a/tests/test_operators.py
+++ b/tests/test_operators.py
@@ -1,3 +1,4 @@
+"""Unit tests for the Evaluator's operators."""
 from unittest import TestCase

 from args.evaluator import ev
@@ -5,6 +6,7 @@ from args.evaluator import ev

 class TestEvaluator(TestCase):
     def test_sum(self):
+        """Test the operator "+"."""
         assert 6 == ev("+", 1, 2, 3)

     def test_prod(self):
$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   tests/test_operators.py

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   tests/test_operators.py

Změnu dělám proto, abych opravil změnu, která v historii už je -- docstring by měl být součástí změny, která přidává modul a testovací metodu. Proto vypadá zpráva změny trochu divně:

$ git commit -m'F e77e2a0'
[master c823f04] F e77e2a0
 1 file changed, 2 insertions(+)

Pak přidám druhou změnu, opravující druhou změnu v historii.

$ git add tests/test_operators.py
$ git diff --cached
diff --git a/tests/test_operators.py b/tests/test_operators.py
index a01cdb0..5dfc209 100644
--- a/tests/test_operators.py
+++ b/tests/test_operators.py
@@ -10,4 +10,5 @@ class TestEvaluator(TestCase):
         assert 6 == ev("+", 1, 2, 3)

     def test_prod(self):
+        """Test the operator "*"."""
         assert 6 == ev("*", 1, 2, 3)
$ git commit -m'F 03b9ab3'
[master a7f67a9] F 03b9ab3
 1 file changed, 1 insertion(+)
$ git status
On branch master
nothing to commit, working tree clean
$ git logg
* a7f67a9 (HEAD -> master) F 03b9ab3
* c823f04 F e77e2a0
* 0681891 Add operator "*"
* 03b9ab3 Add operator "*" unit test
* 5ed5048 Add evaluator module, operator "+"
* e77e2a0 Add operator "+" unit test
* 24784c8 Add gitignore
* fe22dec Add args Python3 package
* d0dbc16 Add license, readme

Nakonec přepíšu historii tak, aby obsahovala opravené změny.

$ git rebase -i 24784c8

V interaktivním rebase změním

pick e77e2a0 Add operator "+" unit test
pick 5ed5048 Add evaluator module, operator "+"
pick 03b9ab3 Add operator "*" unit test
pick 0681891 Add operator "*"
pick c823f04 F e77e2a0
pick a7f67a9 F 03b9ab3

# Rebase 24784c8..a7f67a9 onto 24784c8 (6 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#

na

pick e77e2a0 Add operator "+" unit test
f c823f04 F e77e2a0
pick 5ed5048 Add evaluator module, operator "+"
pick 03b9ab3 Add operator "*" unit test
f a7f67a9 F 03b9ab3
pick 0681891 Add operator "*"

# Rebase 24784c8..a7f67a9 onto 24784c8 (6 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#

což krásně ukazuje, proč jsou "divné" zprávy změn užitečné. (F je zkratka pro FIX.)

Při interaktivním rebase, tj. rebase -i IDENTIFIKATOR-ZMENY, se otevře textový editor se seznamem změn, které se aplikují na změnu IDENTIFIKATOR-ZMENY postupně zhora dolů. To, že se aplikují, je proto, že před každou změnou je pick. Další možnosti, které jde napsat místo pick, jsou uvedené jako komentář. Já použiji f (jako fixup). f začlení změnu (commit) do předchozí (změna na předchozím řádku) a nechá commit message stejnou (jako na předchozím řádku). Možná ještě jiný pohled -- při rebase se změny pick aplikují zhora dolů. Pokud je po pick změna f, je to jako bych v tu chvíli udělal git commit --amend. f změn může být pod sebou více.

$ git rebase -i 24784c8
Successfully rebased and updated refs/heads/master.
$ git status
On branch master
nothing to commit, working tree clean
$ git logg
* f8467dc (HEAD -> master) Add operator "*"
* 4e81de9 Add operator "*" unit test
* 2eaeb68 Add evaluator module, operator "+"
* 0715dc9 Add operator "+" unit test
* 24784c8 Add gitignore
* fe22dec Add args Python3 package
* d0dbc16 Add license, readme
$ git show 0715dc9
commit 0715dc9c3bae0e38f6e7498c9a363352855b14c6
Author: Foo Bar <foo@bar.buzz>
Date:   Tue Jun 27 01:20:38 2023 +0200

    Add operator "+" unit test

diff --git a/tests/test_operators.py b/tests/test_operators.py
new file mode 100644
index 0000000..a8f199e
--- /dev/null
+++ b/tests/test_operators.py
@@ -0,0 +1,10 @@
+"""Unit tests for the Evaluator's operators."""
+from unittest import TestCase
+
+from args.evaluator import ev
+
+
+class TestEvaluator(TestCase):
+    def test_sum(self):
+        """Test the operator "+"."""
+        assert 6 == ev("+", 1, 2, 3)
$ git show 4e81de9
commit 4e81de9f7c30480f3639e7822f233740f59be746
Author: Foo Bar <foo@bar.buzz>
Date:   Wed Jun 28 01:11:46 2023 +0200

    Add operator "*" unit test

diff --git a/tests/test_operators.py b/tests/test_operators.py
index a8f199e..5dfc209 100644
--- a/tests/test_operators.py
+++ b/tests/test_operators.py
@@ -8,3 +8,7 @@ class TestEvaluator(TestCase):
     def test_sum(self):
         """Test the operator "+"."""
         assert 6 == ev("+", 1, 2, 3)
+
+    def test_prod(self):
+        """Test the operator "*"."""
+        assert 6 == ev("*", 1, 2, 3)

Alternativní historie

editovat

Aktuálně je historie přímočará a můžu se v ní pohybovat.

$ git logg
* f8467dc (HEAD -> master) Add operator "*"
* 4e81de9 Add operator "*" unit test
* 2eaeb68 Add evaluator module, operator "+"
* 0715dc9 Add operator "+" unit test
* 24784c8 Add gitignore
* fe22dec Add args Python3 package
* d0dbc16 Add license, readme
$ tree
.
├── args
│   ├── evaluator.py
│   ├── __init__.py
│   └── __pycache__
│       ├── evaluator.cpython-39.pyc
│       └── __init__.cpython-39.pyc
├── LICENSE
├── README
└── tests
    ├── __pycache__
    │   ├── test_operators.cpython-39.pyc
    │   └── test_sum.cpython-39.pyc
    └── test_operators.py

4 directories, 9 files
$ git checkout 24784c8
Note: switching to '24784c8'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:

  git switch -c <new-branch-name>

Or undo this operation with:

  git switch -

Turn off this advice by setting config variable advice.detachedHead to false

HEAD is now at 24784c8 Add gitignore
$ git logg
* f8467dc (master) Add operator "*"
* 4e81de9 Add operator "*" unit test
* 2eaeb68 Add evaluator module, operator "+"
* 0715dc9 Add operator "+" unit test
* 24784c8 (HEAD) Add gitignore
* fe22dec Add args Python3 package
* d0dbc16 Add license, readme
$ tree
.
├── args
│   ├── __init__.py
│   └── __pycache__
│       ├── evaluator.cpython-39.pyc
│       └── __init__.cpython-39.pyc
├── LICENSE
├── README
└── tests
    └── __pycache__
        ├── test_operators.cpython-39.pyc
        └── test_sum.cpython-39.pyc

4 directories, 7 files

HEAD znamená změnu (commit), kde v historii právě jsem. master je větev -- jméno pro změnu (commit), ze které historii vytvářím (přidáním dalších změn). Větví, tedy změn, ze kterých vytvářím historii, může být více.

$ git checkout master
Previous HEAD position was 24784c8 Add gitignore
Switched to branch 'master'
$ git logg
* f8467dc (HEAD -> master) Add operator "*"
* 4e81de9 Add operator "*" unit test
* 2eaeb68 Add evaluator module, operator "+"
* 0715dc9 Add operator "+" unit test
* 24784c8 Add gitignore
* fe22dec Add args Python3 package
* d0dbc16 Add license, readme
$ git branch add-sum-and-prod-operators
$ git logg
* f8467dc (HEAD -> master, add-sum-and-prod-operators) Add operator "*"
* 4e81de9 Add operator "*" unit test
* 2eaeb68 Add evaluator module, operator "+"
* 0715dc9 Add operator "+" unit test
* 24784c8 Add gitignore
* fe22dec Add args Python3 package
* d0dbc16 Add license, readme

Větev mohu nastavit na libovolnou změnu v historii. (POZOR! Pokud jsou v repozitáři změny, které jsou vidět pomocí git diff nebo git diff --cached, tyto budou ztraceny!)

$ git reset --hard 24784c8
HEAD is now at 24784c8 Add gitignore
$ git logg
* f8467dc (add-sum-and-prod-operators) Add operator "*"
* 4e81de9 Add operator "*" unit test
* 2eaeb68 Add evaluator module, operator "+"
* 0715dc9 Add operator "+" unit test
* 24784c8 (HEAD -> master) Add gitignore
* fe22dec Add args Python3 package
* d0dbc16 Add license, readme

Mezi větvemi se mohu pohybovat, jako se mohu pohybovat mezi změnami (commit) v historii. Konec konců, větve jsou jména pro změny.

$ git checkout add-sum-and-prod-operators
Switched to branch 'add-sum-and-prod-operators'
$ git logg
* f8467dc (HEAD -> add-sum-and-prod-operators) Add operator "*"
* 4e81de9 Add operator "*" unit test
* 2eaeb68 Add evaluator module, operator "+"
* 0715dc9 Add operator "+" unit test
* 24784c8 (master) Add gitignore
* fe22dec Add args Python3 package
* d0dbc16 Add license, readme
$ git checkout master
Switched to branch 'master'
$ git logg
* f8467dc (add-sum-and-prod-operators) Add operator "*"
* 4e81de9 Add operator "*" unit test
* 2eaeb68 Add evaluator module, operator "+"
* 0715dc9 Add operator "+" unit test
* 24784c8 (HEAD -> master) Add gitignore
* fe22dec Add args Python3 package
* d0dbc16 Add license, readme

A konečně, větve mohu spojovat.

$ git merge --no-ff add-sum-and-prod-operators
Merge branch 'add-sum-and-prod-operators' 
# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
$ git merge --no-ff add-sum-and-prod-operators
Merge made by the 'recursive' strategy.
 args/evaluator.py       | 11 +++++++++++
 tests/test_operators.py | 14 ++++++++++++++
 2 files changed, 25 insertions(+)
 create mode 100644 args/evaluator.py
 create mode 100644 tests/test_operators.py
$ git logg
*   8febb4c (HEAD -> master) Merge branch 'add-sum-and-prod-operators'
|\
| * f8467dc (add-sum-and-prod-operators) Add operator "*"
| * 4e81de9 Add operator "*" unit test
| * 2eaeb68 Add evaluator module, operator "+"
| * 0715dc9 Add operator "+" unit test
|/
* 24784c8 Add gitignore
* fe22dec Add args Python3 package
* d0dbc16 Add license, readme

Přesnější je říci, že jednu větev (v tomto případě add-sum-and-prod-operators) začlením do jiné, aktuální větve (master).

Takovým způsobem většinou funguje vývoj nové funkce. Když je dočasná větev (add-sum-and-prod-operators) začleněna do hlavní větve (master), už není potřeba a smažu ji.

$ git branch -d add-sum-and-prod-operators
Deleted branch add-sum-and-prod-operators (was f8467dc).
$ git logg
*   8febb4c (HEAD -> master) Merge branch 'add-sum-and-prod-operators'
|\
| * f8467dc Add operator "*"
| * 4e81de9 Add operator "*" unit test
| * 2eaeb68 Add evaluator module, operator "+"
| * 0715dc9 Add operator "+" unit test
|/
* 24784c8 Add gitignore
* fe22dec Add args Python3 package
* d0dbc16 Add license, readme

Konfliktní historie

editovat

Zbývá přidat operátory "<" a ">". Vývoj provedu v nových větvích, vytvořím tedy dvě alternativní historie. Každá větev bude obsahovat dvě změny (commit) -- jednu pro unit test, druhou pro implementaci.

$ git branch add-non-desc-op
$ git checkout add-non-desc-op
Switched to branch 'add-non-desc-op'
$ git logg
*   8febb4c (HEAD -> add-non-desc-op, master) Merge branch 'add-sum-and-prod-operators'
|\
| * f8467dc Add operator "*"
| * 4e81de9 Add operator "*" unit test
| * 2eaeb68 Add evaluator module, operator "+"
| * 0715dc9 Add operator "+" unit test
|/
* 24784c8 Add gitignore
* fe22dec Add args Python3 package
* d0dbc16 Add license, readme
$ git diff
diff --git a/tests/test_operators.py b/tests/test_operators.py
index 5dfc209..0056ab1 100644
--- a/tests/test_operators.py
+++ b/tests/test_operators.py
@@ -12,3 +12,9 @@ class TestEvaluator(TestCase):
     def test_prod(self):
         """Test the operator "*"."""
         assert 6 == ev("*", 1, 2, 3)
+
+    def test_non_desc(self):
+        """Test the operator "<"."""
+        assert ev("<", 1, 2, 3)
+        assert ev("<", 1, 1, 3)
+        assert not ev("<", 3, 2, 1)
$ git add tests/test_operators.py
$ git commit -m'Add operator "<" unit test'
[add-non-desc-op 4d80713] Add operator "<" unit test
 1 file changed, 6 insertions(+)
$ git logg
* 4d80713 (HEAD -> add-non-desc-op) Add operator "<" unit test
*   8febb4c (master) Merge branch 'add-sum-and-prod-operators'
|\
| * f8467dc Add operator "*"
| * 4e81de9 Add operator "*" unit test
| * 2eaeb68 Add evaluator module, operator "+"
| * 0715dc9 Add operator "+" unit test
|/
* 24784c8 Add gitignore
* fe22dec Add args Python3 package
* d0dbc16 Add license, readme
$ python3 -m unittest discover tests
F..
======================================================================
FAIL: test_non_desc (test_operators.TestEvaluator)
Test the operator "<".
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/jiri/args/tests/test_operators.py", line 18, in test_non_desc
    assert ev("<", 1, 2, 3)
AssertionError

----------------------------------------------------------------------
Ran 3 tests in 0.001s

FAILED (failures=1)

Teď mě napadá, že jsem zapomněl do README napsat, jak se spouští testy. A to by mělo být v hlavní vývojové větvi.

$ git checkout master
Switched to branch 'master'
$ git diff
diff --git a/README b/README
index 4e3d26f..470c1a1 100644
--- a/README
+++ b/README
@@ -1,2 +1,6 @@
 Python3 package with the procedure evaluating arguments based on the
 operator.
+
+Run tests:
+
+       python3 -m unittest discover tests
$ git add README
$ git commit -m'Update README with how to run tests'
[master 250bc4e] Update README with how to run tests
 1 file changed, 4 insertions(+)
$ git logg
* 250bc4e (HEAD -> master) Update README with how to run tests
| * 4d80713 (add-non-desc-op) Add operator "<" unit test
|/
*   8febb4c Merge branch 'add-sum-and-prod-operators'
|\
| * f8467dc Add operator "*"
| * 4e81de9 Add operator "*" unit test
| * 2eaeb68 Add evaluator module, operator "+"
| * 0715dc9 Add operator "+" unit test
|/
* 24784c8 Add gitignore
* fe22dec Add args Python3 package
* d0dbc16 Add license, readme

A zpátky k operátoru "<".

$ git checkout add-non-desc-op
Switched to branch 'add-non-desc-op'
$ git logg
* 250bc4e (master) Update README with how to run tests
| * 4d80713 (HEAD -> add-non-desc-op) Add operator "<" unit test
|/
*   8febb4c Merge branch 'add-sum-and-prod-operators'
|\
| * f8467dc Add operator "*"
| * 4e81de9 Add operator "*" unit test
| * 2eaeb68 Add evaluator module, operator "+"
| * 0715dc9 Add operator "+" unit test
|/
* 24784c8 Add gitignore
* fe22dec Add args Python3 package
* d0dbc16 Add license, readme
$ git diff
diff --git a/args/evaluator.py b/args/evaluator.py
index d964dca..1397bec 100644
--- a/args/evaluator.py
+++ b/args/evaluator.py
@@ -9,3 +9,8 @@ def ev(op, *args):
         for a in args:
             p *= a
         return p
+    elif "<" == op:
+        for i in range(1, len(args)):
+            if args[i - 1] > args[i]:
+                return False
+        return True
$ git commit -m'Implement operator "<"'
On branch add-non-desc-op
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   args/evaluator.py

no changes added to commit (use "git add" and/or "git commit -a")

Vlastně ještě přidat soubor.

$ git add args/evaluator.py
$ git commit -m'Implement operator "<"'
[add-non-desc-op 715cfee] Implement operator "<"
 1 file changed, 5 insertions(+)
$ git logg
* 715cfee (HEAD -> add-non-desc-op) Implement operator "<"
* 4d80713 Add operator "<" unit test
| * 250bc4e (master) Update README with how to run tests
|/
*   8febb4c Merge branch 'add-sum-and-prod-operators'
|\
| * f8467dc Add operator "*"
| * 4e81de9 Add operator "*" unit test
| * 2eaeb68 Add evaluator module, operator "+"
| * 0715dc9 Add operator "+" unit test
|/
* 24784c8 Add gitignore
* fe22dec Add args Python3 package
* d0dbc16 Add license, readme
$ python3 -m unittest discover tests
...
----------------------------------------------------------------------
Ran 3 tests in 0.000s

OK

Nakonec operátor ">". Větev by měl začínat ze stejné změny jako operátor "<".

$ git branch add-non-incr-op 8febb4c
$ git checkout add-non-incr-op
Switched to branch 'add-non-incr-op'
$ git logg
* 715cfee (add-non-desc-op) Implement operator "<"
* 4d80713 Add operator "<" unit test
| * 250bc4e (master) Update README with how to run tests
|/
*   8febb4c (HEAD -> add-non-incr-op) Merge branch 'add-sum-and-prod-operators'
|\
| * f8467dc Add operator "*"
| * 4e81de9 Add operator "*" unit test
| * 2eaeb68 Add evaluator module, operator "+"
| * 0715dc9 Add operator "+" unit test
|/
* 24784c8 Add gitignore
* fe22dec Add args Python3 package
* d0dbc16 Add license, readme
$ git diff
diff --git a/args/evaluator.py b/args/evaluator.py
index d964dca..adfe8e2 100644
--- a/args/evaluator.py
+++ b/args/evaluator.py
@@ -9,3 +9,8 @@ def ev(op, *args):
         for a in args:
             p *= a
         return p
+    elif ">" == op:
+        for i in range(1, len(args)):
+            if args[i - 1] < args[i]:
+                return False
+        return True
diff --git a/tests/test_operators.py b/tests/test_operators.py
index 5dfc209..4c75980 100644
--- a/tests/test_operators.py
+++ b/tests/test_operators.py
@@ -12,3 +12,9 @@ class TestEvaluator(TestCase):
     def test_prod(self):
         """Test the operator "*"."""
         assert 6 == ev("*", 1, 2, 3)
+
+    def test_non_incr(self):
+        """Test the operator ">"."""
+        assert ev(">", 3, 2, 1)
+        assert ev(">", 3, 2, 2)
+        assert not ev(">", 1, 2, 3)
$ git add -p
diff --git a/args/evaluator.py b/args/evaluator.py
index d964dca..adfe8e2 100644
--- a/args/evaluator.py
+++ b/args/evaluator.py
@@ -9,3 +9,8 @@ def ev(op, *args):
         for a in args:
             p *= a
         return p
+    elif ">" == op:
+        for i in range(1, len(args)):
+            if args[i - 1] < args[i]:
+                return False
+        return True
(1/1) Stage this hunk [y,n,q,a,d,e,?]? n

diff --git a/tests/test_operators.py b/tests/test_operators.py
index 5dfc209..4c75980 100644
--- a/tests/test_operators.py
+++ b/tests/test_operators.py
@@ -12,3 +12,9 @@ class TestEvaluator(TestCase):
     def test_prod(self):
         """Test the operator "*"."""
         assert 6 == ev("*", 1, 2, 3)
+
+    def test_non_incr(self):
+        """Test the operator ">"."""
+        assert ev(">", 3, 2, 1)
+        assert ev(">", 3, 2, 2)
+        assert not ev(">", 1, 2, 3)
(1/1) Stage this hunk [y,n,q,a,d,e,?]? y
$ git diff --cached
diff --git a/tests/test_operators.py b/tests/test_operators.py
index 5dfc209..4c75980 100644
--- a/tests/test_operators.py
+++ b/tests/test_operators.py
@@ -12,3 +12,9 @@ class TestEvaluator(TestCase):
     def test_prod(self):
         """Test the operator "*"."""
         assert 6 == ev("*", 1, 2, 3)
+
+    def test_non_incr(self):
+        """Test the operator ">"."""
+        assert ev(">", 3, 2, 1)
+        assert ev(">", 3, 2, 2)
+        assert not ev(">", 1, 2, 3)
$ git commit -m'Add operator ">" unit test'
[add-non-incr-op 676ab0f] Add operator ">" unit test
 1 file changed, 6 insertions(+)
$ git diff
diff --git a/args/evaluator.py b/args/evaluator.py
index d964dca..adfe8e2 100644
--- a/args/evaluator.py
+++ b/args/evaluator.py
@@ -9,3 +9,8 @@ def ev(op, *args):
         for a in args:
             p *= a
         return p
+    elif ">" == op:
+        for i in range(1, len(args)):
+            if args[i - 1] < args[i]:
+                return False
+        return True
$ git add args/evaluator.py
$ git commit -m'Implement operator ">"'
[add-non-incr-op 7d1e491] Implement operator ">"
 1 file changed, 5 insertions(+)
$ git logg
* 7d1e491 (HEAD -> add-non-incr-op) Implement operator ">"
* 676ab0f Add operator ">" unit test
| * 715cfee (add-non-desc-op) Implement operator "<"
| * 4d80713 Add operator "<" unit test
|/
| * 250bc4e (master) Update README with how to run tests
|/
*   8febb4c Merge branch 'add-sum-and-prod-operators'
|\
| * f8467dc Add operator "*"
| * 4e81de9 Add operator "*" unit test
| * 2eaeb68 Add evaluator module, operator "+"
| * 0715dc9 Add operator "+" unit test
|/
* 24784c8 Add gitignore
* fe22dec Add args Python3 package
* d0dbc16 Add license, readme

Nezbývá než začlenit dočasné vývojové větve do hlavní větve. Každý, kdo vytváří větve, by měl pochopit, že cíl je větev začlenit.

$ git checkout master
Switched to branch 'master'
$ git logg
* 7d1e491 (add-non-incr-op) Implement operator ">"
* 676ab0f Add operator ">" unit test
| * 715cfee (add-non-desc-op) Implement operator "<"
| * 4d80713 Add operator "<" unit test
|/
| * 250bc4e (HEAD -> master) Update README with how to run tests
|/
*   8febb4c Merge branch 'add-sum-and-prod-operators'
|\
| * f8467dc Add operator "*"
| * 4e81de9 Add operator "*" unit test
| * 2eaeb68 Add evaluator module, operator "+"
| * 0715dc9 Add operator "+" unit test
|/
* 24784c8 Add gitignore
* fe22dec Add args Python3 package
* d0dbc16 Add license, readme
$ git merge --no-ff add-non-desc-op add-non-incr-op
Trying simple merge with add-non-desc-op
Trying simple merge with add-non-incr-op
Simple merge did not work, trying automatic merge.
Auto-merging args/evaluator.py
ERROR: content conflict in args/evaluator.py
Auto-merging tests/test_operators.py
ERROR: content conflict in tests/test_operators.py
fatal: merge program failed
Automatic merge failed; fix conflicts and then commit the result.

Konflikt znamená, že git si neví rady, jakým způsobem spojit alternativní historie. V tomhle případě je to jednoduché, protože chci oba dva operátory včetně unit testů.

$ git status
On branch master
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)
        both modified:   args/evaluator.py
        both modified:   tests/test_operators.py

no changes added to commit (use "git add" and/or "git commit -a")
$ git diff
diff --cc args/evaluator.py
index 1397bec,adfe8e2..0000000
--- a/args/evaluator.py
+++ b/args/evaluator.py
@@@ -9,8 -9,8 +9,14 @@@ def ev(op, *args)
          for a in args:
              p *= a
          return p
++<<<<<<< .merge_file_w7odEj
 +    elif "<" == op:
 +        for i in range(1, len(args)):
 +            if args[i - 1] > args[i]:
++=======
+     elif ">" == op:
+         for i in range(1, len(args)):
+             if args[i - 1] < args[i]:
++>>>>>>> .merge_file_sUueSl
                  return False
          return True
diff --cc tests/test_operators.py
index 0056ab1,4c75980..0000000
--- a/tests/test_operators.py
+++ b/tests/test_operators.py
@@@ -13,8 -13,8 +13,16 @@@ class TestEvaluator(TestCase)
          """Test the operator "*"."""
          assert 6 == ev("*", 1, 2, 3)

++<<<<<<< .merge_file_PX9087
 +    def test_non_desc(self):
 +        """Test the operator "<"."""
 +        assert ev("<", 1, 2, 3)
 +        assert ev("<", 1, 1, 3)
 +        assert not ev("<", 3, 2, 1)
++=======
+     def test_non_incr(self):
+         """Test the operator ">"."""
+         assert ev(">", 3, 2, 1)
+         assert ev(">", 3, 2, 2)
+         assert not ev(">", 1, 2, 3)
++>>>>>>> .merge_file_Tlr21b
$ git status
On branch master
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)
        both modified:   args/evaluator.py
        both modified:   tests/test_operators.py

no changes added to commit (use "git add" and/or "git commit -a")
$ git diff
diff --cc args/evaluator.py
index 1397bec,adfe8e2..0000000
--- a/args/evaluator.py
+++ b/args/evaluator.py
@@@ -9,8 -9,8 +9,13 @@@ def ev(op, *args)
          for a in args:
              p *= a
          return p
 +    elif "<" == op:
 +        for i in range(1, len(args)):
 +            if args[i - 1] > args[i]:
 +                return False
 +        return True
+     elif ">" == op:
+         for i in range(1, len(args)):
+             if args[i - 1] < args[i]:
+                 return False
+         return True
diff --cc tests/test_operators.py
index 0056ab1,4c75980..0000000
--- a/tests/test_operators.py
+++ b/tests/test_operators.py
@@@ -13,8 -13,8 +13,14 @@@ class TestEvaluator(TestCase)
          """Test the operator "*"."""
          assert 6 == ev("*", 1, 2, 3)

 +    def test_non_desc(self):
 +        """Test the operator "<"."""
 +        assert ev("<", 1, 2, 3)
 +        assert ev("<", 1, 1, 3)
 +        assert not ev("<", 3, 2, 1)
++
+     def test_non_incr(self):
+         """Test the operator ">"."""
+         assert ev(">", 3, 2, 1)
+         assert ev(">", 3, 2, 2)
+         assert not ev(">", 1, 2, 3)
$ python3 -m unittest discover tests
....
----------------------------------------------------------------------
Ran 4 tests in 0.000s

OK
$ git status
On branch master
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)
        both modified:   args/evaluator.py
        both modified:   tests/test_operators.py

no changes added to commit (use "git add" and/or "git commit -a")
$ git add args/evaluator.py tests/test_operators.py
$ git status
On branch master
All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)

Changes to be committed:
        modified:   args/evaluator.py
        modified:   tests/test_operators.py
$ git diff --cached
diff --git a/args/evaluator.py b/args/evaluator.py
index d964dca..b00bfab 100644
--- a/args/evaluator.py
+++ b/args/evaluator.py
@@ -9,3 +9,13 @@ def ev(op, *args):
         for a in args:
             p *= a
         return p
+    elif "<" == op:
+        for i in range(1, len(args)):
+            if args[i - 1] > args[i]:
+                return False
+        return True
+    elif ">" == op:
+        for i in range(1, len(args)):
+            if args[i - 1] < args[i]:
+                return False
+        return True
diff --git a/tests/test_operators.py b/tests/test_operators.py
index 5dfc209..114275b 100644
--- a/tests/test_operators.py
+++ b/tests/test_operators.py
@@ -12,3 +12,15 @@ class TestEvaluator(TestCase):
     def test_prod(self):
         """Test the operator "*"."""
         assert 6 == ev("*", 1, 2, 3)
+
+    def test_non_desc(self):
+        """Test the operator "<"."""
+        assert ev("<", 1, 2, 3)
+        assert ev("<", 1, 1, 3)
+        assert not ev("<", 3, 2, 1)
+
+    def test_non_incr(self):
+        """Test the operator ">"."""
+        assert ev(">", 3, 2, 1)
+        assert ev(">", 3, 2, 2)
+        assert not ev(">", 1, 2, 3)
$ git merge --continue
Merge branches 'add-non-desc-op' and 'add-non-incr-op'

# Conflicts:
#	args/evaluator.py
#	tests/test_operators.py
#
# It looks like you may be committing a merge.
# If this is not correct, please run
#	git update-ref -d MERGE_HEAD
# and try again.


# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# On branch master
# All conflicts fixed but you are still merging.
#
# Changes to be committed:
#	modified:   args/evaluator.py
#	modified:   tests/test_operators.py
#
$ git merge --continue
[master 3ef21b4] Merge branches 'add-non-desc-op' and 'add-non-incr-op'
$ git status
On branch master
nothing to commit, working tree clean
$ git logg
*-.   3ef21b4 (HEAD -> master) Merge branches 'add-non-desc-op' and 'add-non-incr-op'
|\ \
| | * 7d1e491 (add-non-incr-op) Implement operator ">"
| | * 676ab0f Add operator ">" unit test
| * | 715cfee (add-non-desc-op) Implement operator "<"
| * | 4d80713 Add operator "<" unit test
| |/
* / 250bc4e Update README with how to run tests
|/
*   8febb4c Merge branch 'add-sum-and-prod-operators'
|\
| * f8467dc Add operator "*"
| * 4e81de9 Add operator "*" unit test
| * 2eaeb68 Add evaluator module, operator "+"
| * 0715dc9 Add operator "+" unit test
|/
* 24784c8 Add gitignore
* fe22dec Add args Python3 package
* d0dbc16 Add license, readme
$ python3 -m unittest discover tests
....
----------------------------------------------------------------------
Ran 4 tests in 0.000s

OK

Vymazat dočasné vývojové větve.

$ git branch -d add-non-desc-op add-non-incr-op
Deleted branch add-non-desc-op (was 715cfee).
Deleted branch add-non-incr-op (was 7d1e491).
$ git logg
*-.   3ef21b4 (HEAD -> master) Merge branches 'add-non-desc-op' and 'add-non-incr-op'
|\ \
| | * 7d1e491 Implement operator ">"
| | * 676ab0f Add operator ">" unit test
| * | 715cfee Implement operator "<"
| * | 4d80713 Add operator "<" unit test
| |/
* / 250bc4e Update README with how to run tests
|/
*   8febb4c Merge branch 'add-sum-and-prod-operators'
|\
| * f8467dc Add operator "*"
| * 4e81de9 Add operator "*" unit test
| * 2eaeb68 Add evaluator module, operator "+"
| * 0715dc9 Add operator "+" unit test
|/
* 24784c8 Add gitignore
* fe22dec Add args Python3 package
* d0dbc16 Add license, readme
$ git show
commit 3ef21b4a5bb92bd014838709945c7fcf89341fd6 (HEAD -> master)
Merge: 250bc4e 715cfee 7d1e491
Author: Foo Bar <foo@bar.buzz>
Date:   Thu Jun 29 00:48:53 2023 +0200

    Merge branches 'add-non-desc-op' and 'add-non-incr-op'

diff --cc args/evaluator.py
index d964dca,1397bec,adfe8e2..b00bfab
--- a/args/evaluator.py
+++ b/args/evaluator.py
@@@@ -9,3 -9,8 -9,8 +9,13 @@@@ def ev(op, *args)
           for a in args:
               p *= a
           return p
+ +    elif "<" == op:
+ +        for i in range(1, len(args)):
+ +            if args[i - 1] > args[i]:
+ +                return False
+ +        return True
++     elif ">" == op:
++         for i in range(1, len(args)):
++             if args[i - 1] < args[i]:
++                 return False
++         return True
diff --cc tests/test_operators.py
index 5dfc209,0056ab1,4c75980..114275b
--- a/tests/test_operators.py
+++ b/tests/test_operators.py
@@@@ -12,3 -12,9 -12,9 +12,15 @@@@ class TestEvaluator(TestCase)
       def test_prod(self):
           """Test the operator "*"."""
           assert 6 == ev("*", 1, 2, 3)
+
+ +    def test_non_desc(self):
+ +        """Test the operator "<"."""
+ +        assert ev("<", 1, 2, 3)
+ +        assert ev("<", 1, 1, 3)
+ +        assert not ev("<", 3, 2, 1)
+++
++     def test_non_incr(self):
++         """Test the operator ">"."""
++         assert ev(">", 3, 2, 1)
++         assert ev(">", 3, 2, 2)
++         assert not ev(">", 1, 2, 3)
$ git status
On branch master
nothing to commit, working tree clean

Použité příkazy

editovat

Inicializace repozitáře:

$ git init
$ git config user.email 'foo@bar.buzz'
$ git config --global user.name 'Foo Bar'

Přidání souborů, prozkoumání repozitáře, nastavení editoru a aliasu:

$ git status
$ git add JMENO-SOUBORU
$ git diff --cached
$ git commit
$ git config --global core.editor 'vim'
$ git log
$ git show
$ git log --oneline --graph --decorate --all
$ git config --global --add alias.logg 'log --oneline --graph --decorate --all'
$ git logg
$ python3 -m unittest discover tests
$ git show HEAD^
$ git commit -m'52 znaků dokončujících větu'

Přeskupení a oprava historie:

$ git rebase -i IDENTIFIKATOR-ZMENY
$ git mv STARE-JMENO-SOUBORU NOVE-JMENO-SOUBORU
$ git commit --amend
$ git add -p JMENO-SOUBORU
$ git commit -m'F IDENTIFIKATOR-ZMENY'

Alternativní historie (branch):

$ git checkout IDENTIFIKATOR-ZMENY
$ git branch JMENO-NOVE-VETVE
$ git reset --hard IDENTIFIKATOR-ZMENY
$ git checkout JMENO-VETVE
$ git merge --no-ff JMENO-VETVE
$ git branch -d JMENO-VETVE

Konfliktní historie:

$ git branch JMENO-NOVE-VETVE IDENTIFIKATOR-ZMENY
$ git add -p
$ git merge --no-ff JMENO-PRVNI-VETVE JMENO-DRUHE-VETVE
$ git merge --continue
$ git branch -d JMENO-PRVNI-VETVE JMENO-DRUHE-VETVE