Grupos/Organizações
ELT85B-N21-2026-2 Teams
for letter in A B C D E F G H I J K L M P; do
gh api --method POST --silent orgs/ELT85B-N21-2026-2/teams \
-f name="Grupo-$letter" \
-f privacy="closed"
done
Organization: ELT85B-N21-2026-2
│
├── Teams
│ ├── Grupo-A
│ ├── Grupo-B
│ ├── Grupo-C
│ └── ...
│
└── Repositories
├── lab00-template
├── lab00-grupo-a
├── lab00-grupo-b
├── ...
├── lab10-template
├── lab10-grupo-a
├── lab10-grupo-b
├── ...
├── projeto-template
├── projeto-grupo-a
├── projeto-grupo-b
└── ...
List your teams and their slugs:
gh api orgs/ELT85B-N21-2026-2/teams --jq '.[] | "\(.name) → \(.slug)"'
List members
gh api orgs/ELT85B-N21-2026-2/teams/grupo-a/members --jq '.[].login'
List repos for a team
gh api orgs/ELT85B-N21-2026-2/teams/grupo-a/repos --jq '.[].full_name'
Here’s a script that creates the lab templates (lab00-template, lab01-template, …):
#!/bin/bash
ORG="ELT85B-N21-2026-2"
NLABS=10 # Creates lab00-template → lab10-template
echo "Creating lab templates in organization: $ORG"
echo ""
for lab in $(seq -w 0 $NLABS); do
REPO="lab${lab}-template"
echo "Creating $REPO..."
# Create the repository
gh repo create "$ORG/$REPO" \
--private \
--description "Template for LAB$lab" \
--add-readme \
--silent
# Mark it as a template repository
gh api --method PATCH --silent \
"repos/$ORG/$REPO" \
-f is_template=true
echo " ✓ $REPO created and marked as template"
done
echo ""
echo "All lab templates created successfully!"
echo ""
echo "You can now use them like this:"
echo " TEMPLATE=\"$ORG/lab05-template\""
./scripts/create-labs-template.sh
Create only one specific template
ORG="ELT85B-N21-2026-2"
NLAB=0
LAB=$(printf "%02d" $NLAB)
REPO="lab${LAB}-template"
gh repo create "$ORG/$REPO" \
--private \
--description "Template for LAB$LAB" \
--add-readme
gh api --method PATCH \
"repos/$ORG/$REPO" \
-f is_template=true
./scripts/create-lab-template.sh
#!/bin/bash
set -e
ORG="ELT85B-N21-2026-2"
GROUP_LIST="A B C D E F G H I J K L M P" # ← not GROUPS
NLAB=0
LAB=$(printf "lab%02d" "$NLAB")
TEMPLATE="$ORG/${LAB}-template"
echo "GROUP_LIST=[$GROUP_LIST]"
echo "Creating ${LAB}-grupo-* from $TEMPLATE"
echo ""
for letter in $GROUP_LIST; do
GROUP_LOWER=$(echo "$letter" | tr '[:upper:]' '[:lower:]')
TEAM_SLUG="grupo-${GROUP_LOWER}"
REPO="${LAB}-grupo-${GROUP_LOWER}"
echo "→ $REPO (team: $TEAM_SLUG)"
if gh repo view "$ORG/$REPO" &>/dev/null; then
echo " ⚠ already exists, skipping create"
else
gh repo create "$ORG/$REPO" \
--private \
--template "$TEMPLATE" \
--description "LAB$(printf '%02d' "$NLAB") - Grupo $letter"
fi
if gh api --method PUT --silent \
"orgs/$ORG/teams/$TEAM_SLUG/repos/$ORG/$REPO" \
-f permission=push; then
echo " ✓ https://github.com/$ORG/$REPO"
else
echo " ✗ Failed to add team $TEAM_SLUG"
fi
done
echo ""
echo "Done."
./scripts/create-lab-from-template.sh
Cheatsheet for your org
ORG="ELT85B-N21-2026-2"
# List teams
gh api "orgs/$ORG/teams" --jq '.[] | "\(.name) → \(.slug)"'
# Create all groups
for L in A B C D E F G H I J K L M X; do
gh api --method POST "orgs/$ORG/teams" \
-f name="Grupo-$L" -f privacy="closed" --silent
done
# Give team write on a lab repo
gh api --method PUT \
"orgs/$ORG/teams/grupo-a/repos/$ORG/lab00-grupo-a" \
-f permission="push"
# Add a student to a team
gh api --method PUT \
"orgs/$ORG/teams/grupo-a/memberships/student-username" \
-f role="member"
ELT85B-N21-2026-2 Teams (TODO)
for letter in A B C D E F G H I J X; do
gh api --method POST orgs/ELT85B-N21-2026-2/teams \
-f name="Grupo-$letter" \
-f privacy="closed"
done
for letter in A B C D E F G H I J K L M X; do
gh api --method POST orgs/ELT85B-N21-2026-2/teams \
-f name="Grupo-$letter" \
-f privacy="closed"
done
for letter in A B C D E F G H I J K L M X; do
gh api --method POST --silent orgs/ELT85B-N21-2026-2/teams \
-f name="Grupo-$letter" \
-f privacy="closed"
done
Organization: ELT85B-N21-2026-2
│
├── Teams
│ ├── Grupo-A
│ ├── Grupo-B
│ ├── Grupo-C
│ └── ...
│
└── Repositories
├── grupo-a-lab00
├── grupo-a-lab01
├── ...
├── grupo-a-lab10
├── grupo-b-lab00
├── grupo-b-lab01
└── ...
Bulk Creation Script (Git Bash)
Here’s a ready-to-use script that creates LAB00 to LAB10 for every group:
ORG="ELT85B-N21-2026-2"
GROUPS="A B C D E F G H I J K L M X"
for letter in $GROUPS; do
TEAM="Grupo-$letter"
for lab in $(seq -w 0 10); do # 00, 01, 02 ... 10
REPO="grupo-${letter,,}-lab$lab" # grupo-a-lab00, grupo-b-lab01...
echo "Creating $REPO for $TEAM..."
gh repo create "$ORG/$REPO" \
--private \
--team "$TEAM" \
--description "LAB$lab - Grupo $letter" \
--add-readme \
--silent
# Give the team write access (instead of just read)
gh api --method PUT --silent \
"orgs/$ORG/teams/$TEAM/repos/$ORG/$REPO" \
-f permission=push
done
done
Projeto
ORG="ELT85B-N21-2026-2"
GROUPS="A B C D E F G H I J K L M X"
for letter in $GROUPS; do
TEAM="Grupo-$letter"
REPO="grupo-${letter,,}-projeto" # grupo-a-projeto, grupo-b-projeto...
echo "Creating $REPO for $TEAM..."
gh repo create "$ORG/$REPO" \
--private \
--team "$TEAM" \
--description "Projeto Final - Grupo $letter" \
--add-readme \
--silent
# Give the team write access
gh api --method PUT --silent \
"orgs/$ORG/teams/$TEAM/repos/$ORG/$REPO" \
-f permission=push
done
Here’s the merged complete script with a NLABS variable:
#!/bin/bash
ORG="ELT85B-N21-2026-2"
GROUPS="A B C D E F G H I J K L M P"
NLABS=10 # Creates LAB00 to LAB10
for letter in $GROUPS; do
TEAM="Grupo-$letter"
GROUP_LOWER="${letter,,}" # a, b, c...
echo "=== Processing Grupo-$letter ==="
# ---------- Create LAB repositories ----------
for lab in $(seq -w 0 $NLABS); do
REPO="grupo-${GROUP_LOWER}-lab$lab"
echo " Creating $REPO..."
gh repo create "$ORG/$REPO" \
--private \
--team "$TEAM" \
--description "LAB$lab - Grupo $letter" \
--add-readme \
--silent
# Give write access to the team
gh api --method PUT --silent \
"orgs/$ORG/teams/$TEAM/repos/$ORG/$REPO" \
-f permission=push
done
# ---------- Create Projeto repository ----------
REPO="grupo-${GROUP_LOWER}-projeto"
echo " Creating $REPO..."
gh repo create "$ORG/$REPO" \
--private \
--team "$TEAM" \
--description "Projeto Final - Grupo $letter" \
--add-readme \
--silent
gh api --method PUT --silent \
"orgs/$ORG/teams/$TEAM/repos/$ORG/$REPO" \
-f permission=push
echo ""
done
echo "All repositories created successfully!"
bash create-repos.sh
What it creates (example for Grupo-A)
grupo-a-lab00
grupo-a-lab01
grupo-a-lab02
...
grupo-a-lab10
grupo-a-projeto
Here’s a focused script that creates repositories for one specific lab using a template:
#!/bin/bash
ORG="ELT85B-N21-2026-2"
TEMPLATE="ELT85B-N21-2026-2/lab-template" # ← change to your template repo
GROUPS="A B C D E F G H I J K L M X"
NLAB=5 # ← creates lab05
LAB=$(printf "%02d" $NLAB) # turns 5 into "05"
echo "Creating repositories for LAB$LAB using template: $TEMPLATE"
echo ""
for letter in $GROUPS; do
TEAM="Grupo-$letter"
GROUP_LOWER="${letter,,}"
REPO="grupo-${GROUP_LOWER}-lab$LAB"
echo "Creating $REPO for $TEAM..."
gh repo create "$ORG/$REPO" \
--template "$TEMPLATE" \
--private \
--team "$TEAM" \
--description "LAB$LAB - Grupo $letter" \
--silent
# Give the team write access
gh api --method PUT --silent \
"orgs/$ORG/teams/$TEAM/repos/$ORG/$REPO" \
-f permission=push
echo " ✓ $REPO created"
done
echo ""
echo "All LAB$LAB repositories created successfully!"
Here’s a script that creates the lab templates (lab00-template, lab01-template, …):
#!/bin/bash
ORG="ELT85B-N21-2026-2"
NLABS=10 # Creates lab00-template → lab10-template
echo "Creating lab templates in organization: $ORG"
echo ""
for lab in $(seq -w 0 $NLABS); do
REPO="lab${lab}-template"
echo "Creating $REPO..."
# Create the repository
gh repo create "$ORG/$REPO" \
--private \
--description "Template for LAB$lab" \
--add-readme \
--silent
# Mark it as a template repository
gh api --method PATCH --silent \
"repos/$ORG/$REPO" \
-f is_template=true
echo " ✓ $REPO created and marked as template"
done
echo ""
echo "All lab templates created successfully!"
echo ""
echo "You can now use them like this:"
echo " TEMPLATE=\"$ORG/lab05-template\""
Optional: Create only one specific template
ORG="ELT85B-N21-2026-2"
NLAB=5
LAB=$(printf "%02d" $NLAB)
REPO="lab${LAB}-template"
gh repo create "$ORG/$REPO" \
--private \
--description "Template for LAB$LAB" \
--add-readme
gh api --method PATCH \
"repos/$ORG/$REPO" \
-f is_template=true
GitHub CLI team management
GitHub CLI team management
The official gh CLI does not have a dedicated gh team command. Team operations are done with gh api (REST API) or with community extensions.
1. Prerequisites
# Auth with org permissions
gh auth login
gh auth refresh -h github.com -s admin:org,read:org,repo
| Scope | Purpose |
|---|---|
read:org | List teams / members |
admin:org | Create / update / delete teams |
repo | Grant teams access to repos |
Git Bash tip: omit the leading / in API paths (orgs/... not /orgs/...).
Bash tip: do not name a variable GROUPS — it is a special Bash array (that caused your 197121 issue).
2. Core concepts
| Concept | Meaning | Example |
|---|---|---|
| Name | Display name | Grupo-A |
| Slug | URL/API id (lowercase) | grupo-a |
| Privacy | closed or secret | closed |
| Permission on repo | pull, push, maintain, admin | push = write |
Always use the slug in API paths.
gh api orgs/ELT73A-S22-2026-2/teams --jq '.[] | "\(.name) → \(.slug)"'
3. Common operations with gh api
List teams
gh api orgs/ELT73A-S22-2026-2/teams --jq '.[] | {name, slug, privacy}'
Get one team
gh api orgs/ELT73A-S22-2026-2/teams/grupo-a
Create a team
gh api --method POST orgs/ELT73A-S22-2026-2/teams \
-f name="Grupo-A" \
-f description="Students group A" \
-f privacy="closed"
Update a team
gh api --method PATCH orgs/ELT73A-S22-2026-2/teams/grupo-a \
-f description="Updated description" \
-f privacy="closed"
Delete a team
gh api --method DELETE orgs/ELT73A-S22-2026-2/teams/grupo-a
Nested (parent) team
PARENT_ID=$(gh api orgs/ELT73A-S22-2026-2/teams/grupo-a --jq '.id')
gh api --method POST orgs/ELT73A-S22-2026-2/teams \
-f name="Grupo-A-Frontend" \
-f privacy="closed" \
-F parent_team_id="$PARENT_ID"
4. Members
List members
gh api orgs/ELT73A-S22-2026-2/teams/grupo-a/members --jq '.[].login'
Add member
# role: member | maintainer
gh api --method PUT \
orgs/ELT73A-S22-2026-2/teams/grupo-a/memberships/USERNAME \
-f role="member"
Remove member
gh api --method DELETE \
orgs/ELT73A-S22-2026-2/teams/grupo-a/memberships/USERNAME
Bulk add members
for user in alice bob carol; do
gh api --method PUT --silent \
orgs/ELT73A-S22-2026-2/teams/grupo-a/memberships/$user \
-f role="member"
echo "Added $user"
done
5. Team ↔ repository access
Grant access
gh api --method PUT \
orgs/ELT73A-S22-2026-2/teams/grupo-a/repos/ELT73A-S22-2026-2/lab00-grupo-a \
-f permission="push"
permission | Meaning |
|---|---|
pull | Read |
triage | Triage |
push | Write |
maintain | Maintain |
admin | Admin |
List repos for a team
gh api orgs/ELT73A-S22-2026-2/teams/grupo-a/repos --jq '.[].full_name'
Remove team from a repo
gh api --method DELETE \
orgs/ELT73A-S22-2026-2/teams/grupo-a/repos/ELT73A-S22-2026-2/lab00-grupo-a
Note on gh repo create
--teamgrants access at create time, but onlypull(read) and cannot be combined with--template.- Pattern you already use: create from template → then
PUTteam withpush.
6. Where teams appear in native gh
| Command | Team-related behavior |
|---|---|
gh repo create --team NAME | Add team with read (no --template) |
gh pr create --reviewer org/team-slug | Request team review |
gh project link --team ... | Link project to a team |
gh org list | List orgs only (not teams) |
Everything else → gh api.
7. Optional extensions
Higher-level team commands:
# Team CRUD, members, repos
gh extension install srz-zumix/gh-team-kit
# Examples
gh team-kit list
gh team-kit create "Grupo-A" --description "..."
gh team-kit tree
# Repo collaborators + teams
gh extension install mislav/gh-repo-collab
gh repo-collab add ORG/REPO org/team-slug --permission push
# Org extras (members/teams)
gh extension install Kyuubang/gh-org-extras
Core gh api is enough for your lab setup and avoids extra dependencies.
8. Cheatsheet for your org
ORG="ELT73A-S22-2026-2"
# List teams
gh api "orgs/$ORG/teams" --jq '.[] | "\(.name) → \(.slug)"'
# Create all groups
for L in A B C D E F G H I J K L M X; do
gh api --method POST "orgs/$ORG/teams" \
-f name="Grupo-$L" -f privacy="closed" --silent
done
# Give team write on a lab repo
gh api --method PUT \
"orgs/$ORG/teams/grupo-a/repos/$ORG/lab00-grupo-a" \
-f permission="push"
# Add a student to a team
gh api --method PUT \
"orgs/$ORG/teams/grupo-a/memberships/student-username" \
-f role="member"
9. Official docs
- Teams REST API: https://docs.github.com/en/rest/teams/teams
- Team members: https://docs.github.com/en/rest/teams/members
- Team repo permissions: https://docs.github.com/en/rest/teams/teams#add-or-update-team-repository-permissions
gh api: https://cli.github.com/manual/gh_api
If you want, next we can add a small scripts/teams.sh helper (create teams, add members from a CSV, sync repo access) tailored to ELT73A-S22-2026-2.
Restrict repository visibility to specific teams in a GitHub organization
1. Set the organization base permission to No permission (critical)
This prevents every organization member from automatically seeing or accessing private repositories.
- Go to the organization → Settings.
- In the left sidebar, under Access, click Member privileges.
- Under Base permissions, select No permission.
- Save the changes.
With this setting, members only see repositories to which they (or their teams) have been explicitly granted access.
2. Make every group repository Private
- Public or Internal repositories are visible more widely.
- For each
labXX-grupo-Yandproyecto-grupo-Yrepository:- Go to the repository → Settings → General → Danger Zone.
- Click Change visibility → Make private.
(Organization owners can also restrict who is allowed to change visibility under Member privileges → Repository visibility change.)
3. Grant access only to the matching team
For each group repository:
- Go to the repository → Settings → Collaborators and teams (or Access → Collaborators & teams).
- Click Add teams.
- Search for and select the matching team (e.g.
Grupo-Aforlab00-grupo-a). - Choose the appropriate role:
- Write — typical for students who need to push code.
- Maintain or Admin — only if the group needs higher privileges.
- Confirm.
Do not add other groups or a broad “all students” team to that repository.
You can also manage this from the team side:
- Organization → Teams → select the team → Repositories tab → add the matching repositories with the desired permission.
4. Handle templates separately
labXX-templateandproyecto-templateare usually kept private and given Read (or Write) access to an instructors/staff team, or to all groups if students need to see the starter code.- Alternatively, leave templates accessible only to instructors and have students create their group repos from the template (or use GitHub Classroom / scripts).
5. Optional but recommended hardening
- Secret teams: Make the student groups Secret teams (Teams → select team → Change visibility → Secret). Secret teams are only visible to their members and organization owners.
- Avoid nested teams unless you intentionally want inheritance.
- Prefer granting access via teams rather than individual users.
- Organization owners always retain full access (this is by design).
- Regularly audit access: Repository → Settings → Collaborators and teams.
Summary of the effective model
| Setting | Recommended value | Effect |
|---|---|---|
| Base permissions | No permission | Members see nothing by default |
| Group repos visibility | Private | Not publicly visible |
| Access grants | Only the matching team | lab00-grupo-a → only Grupo-A |
| Templates | Private + controlled access | Separate policy |
After these steps, a member of Grupo-A will only see (and be able to access) the repositories explicitly shared with Grupo-A. Members of other groups will not see those repositories at all.
If you need to do this at scale (many labs × many groups), the same rules can be applied via the GitHub CLI (gh), the REST/GraphQL API, or automation scripts. Let me know if you want example commands or a script for that.