I am using GNU Bash 4.3, and Git 2.1.4, to tag certain git commits based on their commit messages. Specifically, I want to tag:
- as
v0.0.1the commit with message "Commit 5", - as
v0.0.2the commit with message "Commit 10",
given the following commit log:
$ git log --format=oneline --decorate
924d9120dec9f61d0f99a5155c51bad63d24b37f (HEAD, master) Commit 10
c62b2f68ea6b8ff047dd5f1e99010ebf434709ef Commit 9
feec2d76977521018ff33fd6e109530fdb69291d Commit 8
9a25b2ea11d0aa19af33761c7c81bd10d0f17949 Commit 7
c7b02e556738e7cd2a2459e07af731e5677ab090 Commit 6
1bf5b98cf90340e714bd0bd13c7721f94749fa5f Commit 5
8a9c25eda46b3424a870584e4a8a4f90f6e5aa2c Commit 4
0ecf2464ec82a3aa74abb6f6c2127315ef4c2495 Commit 3
e18bdb2ae52f2149421965ff69d96dba46cd7c0a Commit 2
cf10d47067bef60ae787e5421e32b4541bdf52be Commit 1
Here is my initial solution:
$ v=(1 2); c=(5 10); for i in 0 1; do git tag -a v0.0.${v[$i]} -m "Tag v0.0.${v[$i]}" $(git rev-parse :/'Commit '${c[$i]}); done
This clearly works as desired:
$ git log --format=oneline --decorate
924d9120dec9f61d0f99a5155c51bad63d24b37f (HEAD, tag: v0.0.2, master) Commit 10
c62b2f68ea6b8ff047dd5f1e99010ebf434709ef Commit 9
feec2d76977521018ff33fd6e109530fdb69291d Commit 8
9a25b2ea11d0aa19af33761c7c81bd10d0f17949 Commit 7
c7b02e556738e7cd2a2459e07af731e5677ab090 Commit 6
1bf5b98cf90340e714bd0bd13c7721f94749fa5f (tag: v0.0.1) Commit 5
8a9c25eda46b3424a870584e4a8a4f90f6e5aa2c Commit 4
0ecf2464ec82a3aa74abb6f6c2127315ef4c2495 Commit 3
e18bdb2ae52f2149421965ff69d96dba46cd7c0a Commit 2
cf10d47067bef60ae787e5421e32b4541bdf52be Commit 1
But it seems excessively verbose and fragile.
Questions:
Instead of separately defining three arrays (
v=(1 2); c=(5 10); for i in 0 1), can I create a single array for the two independent variables (e.g. in pseudocode:vc=((1 5) (2 10))) and then determine the incrementor's value automatically upon each iteration?Instead of using a
forloop, can I use brace expansion or some other more concise and elegant approach?
I would prefer a one-liner, but I do not require a one-liner.
-
\$\begingroup\$ Does it need to be a one-liner? \$\endgroup\$chicks– chicks2017年06月18日 14:46:57 +00:00Commented Jun 18, 2017 at 14:46
-
\$\begingroup\$ @chicks, thanks for asking! Question updated accordingly :) \$\endgroup\$user51143– user511432017年06月18日 19:19:51 +00:00Commented Jun 18, 2017 at 19:19
2 Answers 2
You could extract the main operation to a function:
tag() { local v=1ドル c=2ドル; git tag -a v0.0.$v -m "Tag v0.0.$v" $(git rev-parse :/"Commit $c"); }
And then call this function with the desired values:
tag 1 5
tag 2 10
This is very easy to read and understand.
As per using nested arrays, you cannot do that in Bash, but you can always emulate a 2D-array with appropriate indexing, for example:
vc=(1 5 2 10); for ((i = 0; i < ${#vc[@]}; i+=2)); do v=${vc[i]}; c=${vc[i+1]}; git tag -a v0.0.$v -m "Tag v0.0.$v" $(git rev-parse :/"Commit $c"); done
If I had to write a "single-use" quickie command, I would write it like this:
while read version commit; do
git tag -a v0.0.$version -m "Tag v0.0.$version" $(git rev-parse :/'Commit '$commit)
done
Then, as the script awaits input, type:
1 5
2 10
^D
In contrast to your parallel arrays, the main advantage of this approach is that each line constitutes a commit-version pair.
-
\$\begingroup\$ Nifty! Not quite what I had in mind, but I like it :) Upvoted accordingly :) \$\endgroup\$user51143– user511432017年06月19日 13:21:20 +00:00Commented Jun 19, 2017 at 13:21