Skip to content

Commit df30fef

Browse files
committed
feat: add git_set_identity script
Signed-off-by: Sebastian Davids <[email protected]>
1 parent 1b251d0 commit df30fef

File tree

3 files changed

+305
-0
lines changed

3 files changed

+305
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
// SPDX-FileCopyrightText: © 2025 Sebastian Davids <[email protected]>
2+
// SPDX-License-Identifier: Apache-2.0
3+
= git_set_identity
4+
:script_url: https://github.com/sdavids/sdavids-shell-misc/blob/main/scripts/git/git_set_identity.sh.sh
5+
6+
{script_url}[This script^] will set the identity (`user.name`, `user.email`, and `user.signingKey`) in the Git repositories of the given directory.
7+
8+
The following parameters are required:
9+
10+
`e` :: the email to be used for the identity and GPG secret key retrieval; can be omitted if `git config get user.email` is set, and you want to use its value
11+
`n` :: the name to be used for the identity; can be omitted if `git config get user.name` is set, and you want to use its value
12+
13+
The following parameter is optional:
14+
15+
`d` :: the directory (`$PWD` if not given) containing the Git repositories
16+
17+
[NOTE]
18+
====
19+
This script will not recursively search the given directory for Git repositories--only direct child directories are considered.
20+
====
21+
22+
[NOTE]
23+
====
24+
This script will set up https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work[GPG signing] under the following conditions:
25+
26+
. `git config get gpg.program` or `gpg`/`gpg2` is installed
27+
. a GPG secret key for the given email exists
28+
29+
In that case, the following Git configuration will be applied in addition to `user.email` and `user.name`:
30+
31+
commit.gpgSign :: set to `true`
32+
tag.forceSignAnnotated :: set to `true`
33+
tag.gpgSign :: set to `true`
34+
user.signingKey :: set to the first secret key returned by `--list-secret-keys` for the given email
35+
====
36+
37+
[TIP]
38+
====
39+
This script is useful if you do not use the same identity in all the projects you work on.
40+
41+
See: <<example>>
42+
====
43+
44+
== Usage
45+
46+
[,shell]
47+
----
48+
$ scripts/git/git_set_identity.sh -e [email protected]
49+
$ scripts/git/git_set_identity.sh \
50+
-d ~/workspaces/mutiny \
51+
52+
$ scripts/git/git_set_identity.sh \
53+
-d ~/workspaces/cardiff-electric \
54+
55+
-n 'Catherine Howe'
56+
----
57+
58+
== Example
59+
60+
Cameron works for two companies and also has personal projects:
61+
62+
[,shell]
63+
----
64+
$ tree --noreport ~/workspaces
65+
/Users/example/workspaces
66+
├── cardiff-electric
67+
│ ├── backend
68+
│ └── frontend
69+
├── mutiny
70+
│ └── giant
71+
└── personal
72+
├── sandbox
73+
└── secret-project
74+
----
75+
76+
She has three GPG secret keys--one for each company and one personal:
77+
78+
[,shell]
79+
----
80+
$ gpg --list-secret-keys
81+
/Users/example/.gnupg/pubring.kbx
82+
-----------------------------------------
83+
84+
sec rsa4096/49F1A380A5660737 2025-02-02 [SC] [expires: 2029-02-02]
85+
Key fingerprint = 3956 4B7A A0B5 1F88 A8F8 BCBC 49F1 A380 A566 0737
86+
uid [ultimate] Cameron Howe <[email protected]>
87+
ssb rsa4096/8B68480DE279CA88 2025-02-02 [E] [expires: 2029-02-02]
88+
89+
sec rsa4096/EC073F7EFD23C1FA 2025-02-02 [SC] [expires: 2029-02-02]
90+
Key fingerprint = 2DAF 54C7 67F3 FD24 EACF A1B5 EC07 3F7E FD23 C1FA
91+
uid [ultimate] Cameron Howe <[email protected]>
92+
ssb rsa4096/6363EEBF938865CF 2025-02-02 [E] [expires: 2029-02-02]
93+
94+
sec rsa4096/77254FBC1027F48D 2025-02-02 [SC] [expires: 2029-02-02]
95+
Key fingerprint = C09B 7924 274A 9865 545C 6512 7725 4FBC 1027 F48D
96+
uid [ultimate] Catherine Howe <[email protected]>
97+
ssb rsa4096/6C2E4F6CB45DD27E 2025-02-02 [E] [expires: 2029-02-02]
98+
----
99+
100+
She has configured her personal GPG key in her global Git configuration and signs commits and tags by default:
101+
102+
[,shell]
103+
----
104+
$ cat ~/.gitconfig
105+
[user]
106+
name = Cameron Howe
107+
108+
signingkey = 2DAF54C767F3FD24EACFA1B5EC073F7EFD23C1FA
109+
[commit]
110+
gpgsign = true
111+
[tag]
112+
forceSignAnnotated = true
113+
gpgsign = true
114+
----
115+
116+
With this configuration the following identities will be used for commits and tags:
117+
118+
[,shell]
119+
----
120+
$ find ~/workspaces/cardiff-electric -mindepth 1 -maxdepth 1 -type d -exec sh -c '(cd {} && echo "$PWD" && echo " $(git config get user.name) <$(git config get user.email)> $(git config get user.signingkey)")' \;
121+
/Users/example/workspaces/cardiff-electric/frontend
122+
Cameron Howe <[email protected]> 2DAF54C767F3FD24EACFA1B5EC073F7EFD23C1FA
123+
/Users/example/workspaces/cardiff-electric/backend
124+
Cameron Howe <[email protected]> 2DAF54C767F3FD24EACFA1B5EC073F7EFD23C1FA
125+
126+
$ find ~/workspaces/mutiny -mindepth 1 -maxdepth 1 -type d -exec sh -c '(cd {} && echo "$PWD" && echo " $(git config get user.name) <$(git config get user.email)> $(git config get user.signingkey)")' \;
127+
/Users/example/workspaces/mutiny/giant
128+
Cameron Howe <[email protected]> 2DAF54C767F3FD24EACFA1B5EC073F7EFD23C1FA
129+
130+
$ find ~/workspaces/personal -mindepth 1 -maxdepth 1 -type d -exec sh -c '(cd {} && echo "$PWD" && echo " $(git config get user.name) <$(git config get user.email)> $(git config get user.signingkey)")' \;
131+
/Users/example/workspaces/personal/secret-project
132+
Cameron Howe <[email protected]> 2DAF54C767F3FD24EACFA1B5EC073F7EFD23C1FA
133+
/Users/example/workspaces/personal/sandbox
134+
Cameron Howe <[email protected]> 2DAF54C767F3FD24EACFA1B5EC073F7EFD23C1FA
135+
----
136+
137+
She now uses this script to configure the identities for the companies' projects:
138+
139+
[,shell]
140+
----
141+
$ scripts/git/git_set_identity.sh \
142+
-d ~/workspaces/cardiff-electric \
143+
144+
-n 'Catherine Howe'
145+
Catherine Howe <[email protected]> C09B7924274A9865545C651277254FBC1027F48D - /Users/example/workspaces/cardiff-electric/backend
146+
Catherine Howe <[email protected]> C09B7924274A9865545C651277254FBC1027F48D - /Users/example/workspaces/cardiff-electric/frontend
147+
148+
$ scripts/git/git_set_identity.sh \
149+
-d ~/workspaces/mutiny \
150+
151+
Cameron Howe <[email protected]> 39564B7AA0B51F88A8F8BCBC49F1A380A5660737 - /Users/example/workspaces/mutiny/giant
152+
----
153+
154+
The following identities will be used for commits and tags now:
155+
156+
[,shell]
157+
----
158+
$ find ~/workspaces/cardiff-electric -mindepth 1 -maxdepth 1 -type d -exec sh -c '(cd {} && echo "$PWD" && echo " $(git config get user.name) <$(git config get user.email)> $(git config get user.signingkey)")' \;
159+
/Users/example/workspaces/cardiff-electric/frontend
160+
Catherine Howe <[email protected]> C09B7924274A9865545C651277254FBC1027F48D
161+
/Users/example/workspaces/cardiff-electric/backend
162+
Catherine Howe <[email protected]> C09B7924274A9865545C651277254FBC1027F48D
163+
164+
$ find ~/workspaces/mutiny -mindepth 1 -maxdepth 1 -type d -exec sh -c '(cd {} && echo "$PWD" && echo " $(git config get user.name) <$(git config get user.email)> $(git config get user.signingkey)")' \;
165+
/Users/example/workspaces/mutiny/giant
166+
Cameron Howe <[email protected]> 39564B7AA0B51F88A8F8BCBC49F1A380A5660737
167+
168+
$ find ~/workspaces/personal -mindepth 1 -maxdepth 1 -type d -exec sh -c '(cd {} && echo "$PWD" && echo " $(git config get user.name) <$(git config get user.email)> $(git config get user.signingkey)")' \;
169+
/Users/example/workspaces/personal/secret-project
170+
Cameron Howe <[email protected]> 2DAF54C767F3FD24EACFA1B5EC073F7EFD23C1FA
171+
/Users/example/workspaces/personal/sandbox
172+
Cameron Howe <[email protected]> 2DAF54C767F3FD24EACFA1B5EC073F7EFD23C1FA
173+
----
174+
175+
== More Information
176+
177+
* https://git-scm.com/docs/git-config#Documentation/git-config.txt-authorname[Git user.name & user.email]
178+
* https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work[GPG signing]
179+
* https://git-scm.com/docs/git-config#Documentation/git-config.txt-usersigningKey[user.signingKey]
180+
* https://git-scm.com/docs/git-config#Documentation/git-config.txt-commitgpgSign[commit.gpgSign]
181+
* https://git-scm.com/docs/git-config#Documentation/git-config.txt-taggpgSign[tag.gpgSign]
182+
* https://git-scm.com/docs/git-config#Documentation/git-config.txt-tagforceSignAnnotated[tag.forceSignAnnotated]
183+
* https://man.archlinux.org/man/core/gnupg/gpg.1.en[gpg]

docs/user-guide/modules/ROOT/pages/scripts/git/git.adoc

+1
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,6 @@ xref:scripts/git/git-get-hash.adoc[]:: return the hash of the HEAD commit
1313
xref:scripts/git/git-get-short-hash.adoc[]:: return the short hash of the HEAD commit
1414
xref:scripts/git/git-ignore-all.adoc[]:: create a `.gitignore` file ignoring everything for a given repository
1515
xref:scripts/git/git-is-working-tree-clean.adoc[]:: check whether the Git working tree is clean
16+
xref:scripts/git/git-set-identity.adoc[]:: set the identity (`user.name`, `user.email`, and `user.signingKey`) in the Git repositories of the given directory
1617

1718
Related: xref:functions/git/git.adoc[Git Functions]

scripts/git/git_set_identity.sh

+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
#!/usr/bin/env sh
2+
3+
# SPDX-FileCopyrightText: © 2025 Sebastian Davids <[email protected]>
4+
# SPDX-License-Identifier: Apache-2.0
5+
6+
set -u
7+
8+
name="$(git config get user.name)"
9+
# shellcheck disable=SC2181
10+
if [ $? -ne 0 ]; then
11+
name=''
12+
fi
13+
email="$(git config get user.email)"
14+
# shellcheck disable=SC2181
15+
if [ $? -ne 0 ]; then
16+
email=''
17+
fi
18+
gpg_program="$(git config get gpg.program)"
19+
# shellcheck disable=SC2181
20+
if [ $? -ne 0 ]; then
21+
gpg_program='gpg'
22+
fi
23+
24+
set -e
25+
26+
while getopts ':d:e:n:' opt; do
27+
case "${opt}" in
28+
d)
29+
base_dir="${OPTARG}"
30+
;;
31+
e)
32+
email="${OPTARG}"
33+
;;
34+
n)
35+
name="${OPTARG}"
36+
;;
37+
?)
38+
echo "Usage: $0 [-d <base_dir>] [-e <email>] [-n <name>]" >&2
39+
exit 1
40+
;;
41+
esac
42+
done
43+
44+
readonly base_dir="${base_dir:-$PWD}"
45+
readonly email
46+
readonly name
47+
48+
if [ ! -d "${base_dir}" ]; then
49+
printf "The directory '%s' does not exist.\n" "${base_dir}" >&2
50+
exit 2
51+
fi
52+
53+
if [ -z "${email}" ]; then
54+
echo '-e <email> is required because user.email is not set in your global Git configuration' >&2
55+
exit 3
56+
fi
57+
58+
if [ -z "${name}" ]; then
59+
echo '-n <name> is required because user.name is not set in your global Git configuration' >&2
60+
exit 4
61+
fi
62+
63+
if [ -z "$(ls -A "${base_dir}")" ]; then
64+
# base_dir empty nothing to do
65+
exit 0
66+
fi
67+
68+
if command -v "${gpg_program}" >/dev/null 2>&1; then
69+
cmd="${gpg_program} --list-secret-keys --with-colons \"${email}\" 2>&1 | sed -E -n -e 's/^fpr:::::::::([0-9A-F]+):$/\1/p' | head -n 1"
70+
key="$(eval "${cmd}")"
71+
if [ -z "${key}" ]; then
72+
printf "GPG key for '%s' does not exists--disabling GPG signing.\n\n" "${email}" >&2
73+
fi
74+
else
75+
if [ "${gpg_program}" = 'gpg' ] && command -v gpg2 >/dev/null 2>&1; then
76+
key="$(gpg2 --list-secret-keys --with-colons "${email}" 2>&1 | sed -E -n -e 's/^fpr:::::::::([0-9A-F]+):$/\1/p' | head -n 1)"
77+
if [ -z "${key}" ]; then
78+
printf "GPG key for '%s' does not exists--disabling GPG signing.\n\n" "${email}" >&2
79+
fi
80+
else
81+
key=''
82+
printf "gpg.program '%s' does not exists--disabling GPG signing.\n\n" "${gpg_program}" >&2
83+
fi
84+
fi
85+
86+
unset gpg_program
87+
readonly key
88+
89+
cd "${base_dir}"
90+
91+
if [ -n "${key}" ]; then
92+
for dir in ./*/; do
93+
cd "${dir}"
94+
if [ "$(git rev-parse --is-inside-work-tree 2>/dev/null)" = 'true' ]; then
95+
# https://git-scm.com/docs/git-config#_variables
96+
git config set user.name "${name}"
97+
git config set user.email "${email}"
98+
git config set user.signingkey "${key}"
99+
git config set --bool commit.gpgsign true
100+
git config set --bool tag.gpgsign true
101+
git config set --bool tag.forcesignannotated true
102+
echo "$(git config get user.name) <$(git config get user.email)> $(git config get user.signingkey) - $PWD"
103+
fi
104+
cd ..
105+
done
106+
else
107+
for dir in ./*/; do
108+
cd "${dir}"
109+
if [ "$(git rev-parse --is-inside-work-tree 2>/dev/null)" = 'true' ]; then
110+
# https://git-scm.com/docs/git-config#_variables
111+
git config set user.name "${name}"
112+
git config set user.email "${email}"
113+
git config set user.signingkey ''
114+
git config set --bool commit.gpgsign false
115+
git config set --bool tag.gpgsign false
116+
git config set --bool tag.forcesignannotated false
117+
echo "$(git config get user.name) <$(git config get user.email)> - $PWD"
118+
fi
119+
cd ..
120+
done
121+
fi

0 commit comments

Comments
 (0)