diff --git a/README.md b/README.md
index 1c9b321..f07dc6e 100644
--- a/README.md
+++ b/README.md
@@ -30,7 +30,7 @@ I also hate to change directories to execute git commands.
 ![gita screenshot](https://github.com/nosarthur/gita/raw/master/doc/screenshot.png)
 
 In the screenshot, the `gita remote nowhub` command translates to `git remote -v`
-for the `nowhub` repo, even though we are at the `blog` repo.
+for the `nowhub` repo, even though we are in the `blog` repo.
 To see the pre-defined sub-commands, run `gita -h` or take a look at
 [cmds.yml](https://github.com/nosarthur/gita/blob/master/gita/cmds.yml).
 To add your own sub-commands, see the [customization section](#custom).
@@ -70,7 +70,7 @@ The bookkeeping sub-commands are
     - `gita color set <situation> <color>`: Use the specified color for the local-remote situation
 - `gita freeze`: print information of all repos such as URL, name, and path.
 - `gita group`: group sub-command
-    - `gita group add <repo-name(s)> -n <group-name>`: add repo(s) to a new group or existing group
+    - `gita group add <repo-name(s)> -n <group-name>`: add repo(s) to a new or existing group
     - `gita group [ll]`: display existing groups with repos
     - `gita group ls`: display existing group names
     - `gita group rename <group-name> <new-name>`: change group name
@@ -171,11 +171,12 @@ Here `repo-name(s)` or `group-name(s)` are optional, and their absence means all
 For example,
 
 - `gita shell ll` lists contents for all repos
-- `gita shell repo1 mkdir docs` create a new directory `docs` in repo1
+- `gita shell repo1 repo2 mkdir docs` create a new directory `docs` in `repo1` and `repo2`
+- `gita shell "git describe --abbrev=0 --tags | xargs git checkout"`: check out the latest tag for all repos
 
 ## <a name='custom'></a> Customization
 
-### user-defined sub-command using yaml file
+### add user-defined sub-command using yaml file
 
 Custom delegating sub-commands can be defined in `$XDG_CONFIG_HOME/gita/cmds.yml`
 (most likely `~/.config/gita/cmds.yml`).
@@ -195,12 +196,11 @@ which executes `git diff --stat` for the specified repo(s).
 
 If the delegated `git` command is a single word, the `cmd` tag can be omitted.
 See `push` for an example.
-To disable asynchronous execution, set the `disable_async` tag to be `true`.
+To disable asynchronous execution, set `disable_async` to be `true`.
 See `difftool` for an example.
 
-If you want a custom command to behave like `gita fetch`, i.e., to apply the
-command to all repos when no repo is specified,
-set the `allow_all` option to be `true`.
+If you want a custom command to behave like `gita fetch`, i.e., to apply to all
+repos when no repo is specified, set `allow_all` to be `true`.
 For example, the following snippet creates a new command
 `gita comaster [repo-name(s)]` with optional repo name input.
 
@@ -223,7 +223,7 @@ You can customize the information displayed by `gita ll`.
 The used and unused information items are shown with `gita info`, and the
 configuration is saved in `$XDG_CONFIG_HOME/gita/info.yml`.
 
-For example, the default information items setting corresponds to
+For example, the default setting corresponds to
 
 ```yaml
 - branch
diff --git a/gita/__main__.py b/gita/__main__.py
index beecab2..a183c37 100644
--- a/gita/__main__.py
+++ b/gita/__main__.py
@@ -249,10 +249,10 @@ def f_shell(args):
                 for r in groups[k]:
                     chosen[r] = repos[r]
         repos = chosen
-    cmds = args.man[i:]
+    cmds = ' '.join(args.man[i:])  # join the shell command into a single string
     for name, path in repos.items():
         # TODO: pull this out as a function
-        got = subprocess.run(cmds, cwd=path, check=True,
+        got = subprocess.run(cmds, cwd=path, check=True, shell=True,
                 stdout=subprocess.PIPE,
                 stderr=subprocess.STDOUT)
         print(utils.format_output(got.stdout.decode(), name))
diff --git a/gita/info.py b/gita/info.py
index a8044e9..dc9d167 100644
--- a/gita/info.py
+++ b/gita/info.py
@@ -106,7 +106,8 @@ def get_path(path):
 
 
 def get_head(path: str) -> str:
-    result = subprocess.run('git rev-parse --abbrev-ref HEAD'.split(),
+    result = subprocess.run('git symbolic-ref -q --short HEAD || git describe --tags --exact-match',
+                            shell=True,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.DEVNULL,
                             universal_newlines=True,
diff --git a/setup.py b/setup.py
index c729963..9f25098 100644
--- a/setup.py
+++ b/setup.py
@@ -7,7 +7,7 @@ with open('README.md', encoding='utf-8') as f:
 setup(
     name='gita',
     packages=['gita'],
-    version='0.12.7',
+    version='0.12.8',
     license='MIT',
     description='Manage multiple git repos with sanity',
     long_description=long_description,

diff --git a/tests/test_main.py b/tests/test_main.py
index ad501f7..7e3feb9 100644
--- a/tests/test_main.py
+++ b/tests/test_main.py
@@ -167,10 +167,10 @@ def test_superman(mock_run, _, input):
 @patch('subprocess.run')
 def test_shell(mock_run, _, input):
     mock_run.reset_mock()
-    args = ['shell', 'repo7'] + shlex.split(input)
+    args = ['shell', 'repo7', input]
     __main__.main(args)
-    expected_cmds = shlex.split(input)
-    mock_run.assert_called_once_with(expected_cmds, cwd='path7', check=True, stderr=-2, stdout=-1)
+    expected_cmds = input
+    mock_run.assert_called_once_with(expected_cmds, cwd='path7', check=True, shell=True, stderr=-2, stdout=-1)
 
 
 class TestContext:

Optionally display tags
it could be one of the information items

spun from #114 
tests/test_main.py::test_shell[diff tests/test_main.py::test_shell[commit
tests/test_main.py::TestLsLl::testLs tests/test_main.py::TestLsLl::testWithPathFiles[/root/data/temp_dir/tmp6h_zl2xh/nosarthur__gita__0.0/tests/mock_path_file-repo1 tests/test_main.py::TestLsLl::testWithPathFiles[/root/data/temp_dir/tmp6h_zl2xh/nosarthur__gita__0.0/tests/empty_path_file-] tests/test_main.py::TestLsLl::testWithPathFiles[/root/data/temp_dir/tmp6h_zl2xh/nosarthur__gita__0.0/tests/clash_path_file-repo1 tests/test_main.py::test_freeze tests/test_main.py::test_rm tests/test_main.py::test_not_add tests/test_main.py::test_fetch tests/test_main.py::test_async_fetch tests/test_main.py::test_superman[diff tests/test_main.py::test_superman[commit tests/test_main.py::TestContext::testDisplayNoContext tests/test_main.py::TestContext::testDisplayContext tests/test_main.py::TestContext::testReset tests/test_main.py::TestContext::testSetFirstTime tests/test_main.py::TestContext::testSetSecondTime tests/test_main.py::TestGroupCmd::testLs tests/test_main.py::TestGroupCmd::testLl tests/test_main.py::TestGroupCmd::testRename tests/test_main.py::TestGroupCmd::testRenameError tests/test_main.py::TestGroupCmd::testRm[xx-expected0] tests/test_main.py::TestGroupCmd::testRm[xx tests/test_main.py::TestGroupCmd::testAdd tests/test_main.py::TestGroupCmd::testAddToExisting tests/test_main.py::TestGroupCmd::testRmRepo tests/test_main.py::test_rename tests/test_main.py::TestInfo::testLl tests/test_main.py::TestInfo::testAdd tests/test_main.py::TestInfo::testRm