2
\$\begingroup\$

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.1 the commit with message "Commit 5",
  • as v0.0.2 the 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 for loop, 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.

\$\endgroup\$
  • \$\begingroup\$ Does it need to be a one-liner? \$\endgroup\$ – chicks Jun 18 '17 at 14:46
  • \$\begingroup\$ @chicks, thanks for asking! Question updated accordingly :) \$\endgroup\$ – sampablokuper Jun 18 '17 at 19:19
1
\$\begingroup\$

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
\$\endgroup\$
1
\$\begingroup\$

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.

\$\endgroup\$
  • \$\begingroup\$ Nifty! Not quite what I had in mind, but I like it :) Upvoted accordingly :) \$\endgroup\$ – sampablokuper Jun 19 '17 at 13:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.