Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
G
git-scripts
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Container registry
Model registry
Operate
Environments
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Hugo Hörnquist
git-scripts
Commits
79bc61d2
Commit
79bc61d2
authored
1 year ago
by
Hugo Hörnquist
Browse files
Options
Downloads
Patches
Plain Diff
Add git-children.
parent
aed4b93d
No related branches found
No related tags found
No related merge requests found
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
Makefile
+1
-0
1 addition, 0 deletions
Makefile
git-children.py
+137
-0
137 additions, 0 deletions
git-children.py
with
138 additions
and
0 deletions
Makefile
+
1
−
0
View file @
79bc61d2
...
@@ -4,5 +4,6 @@ PREFIX := /usr
...
@@ -4,5 +4,6 @@ PREFIX := /usr
DESTDIR
=
DESTDIR
=
install
:
install
:
install
git-children.py
$(
DESTDIR
)$(
PREFIX
)
/bin/git-children
install
git-ls.scm
$(
DESTDIR
)$(
PREFIX
)
/bin/git-ls
install
git-ls.scm
$(
DESTDIR
)$(
PREFIX
)
/bin/git-ls
install
git-open.py
$(
DESTDIR
)$(
PREFIX
)
/bin/git-open
install
git-open.py
$(
DESTDIR
)$(
PREFIX
)
/bin/git-open
This diff is collapsed.
Click to expand it.
git-children.py
0 → 100755
+
137
−
0
View file @
79bc61d2
#!/usr/bin/env python3
"""
Script for easily referencing children of a specific git commit.
Many of these procedures refer to the
"
current repo
"
. This is simply
the closest containing repo from the current working directory (per
the git command lines rules).
The two types of move currently supported are:
- ``^[<n>]`` Move to the *nth* (default first) child of the node.
- ``~[<n>]`` Move *n* commits backwards, always chocing the first
child.
"""
import
subprocess
import
re
from
typing
import
Literal
,
cast
,
Iterator
,
TypeAlias
import
argparse
ChangeType
:
TypeAlias
=
Literal
[
'
^
'
,
'
~
'
]
Change
:
TypeAlias
=
tuple
[
ChangeType
,
int
]
def
children
()
->
dict
[
bytes
,
list
[
bytes
]]:
"""
Load list of all relations in the current git repo.
"""
cmd
=
subprocess
.
Popen
(
"
git rev-list --children --all
"
.
split
(
'
'
),
stdout
=
subprocess
.
PIPE
)
tree
:
dict
[
bytes
,
list
[
bytes
]]
=
{}
for
line
in
cast
(
Iterator
[
bytes
],
cmd
.
stdout
):
commit
,
*
children
=
line
.
rstrip
().
split
(
b
'
'
)
tree
[
commit
]
=
children
return
tree
def
revparse
(
name
:
str
)
->
bytes
:
"""
Return the revparse of the name, in the current repo.
"""
return
subprocess
.
run
([
"
git
"
,
"
rev-parse
"
,
name
],
capture_output
=
True
).
stdout
.
rstrip
()
def
parse_refspec
(
spec
:
str
)
->
tuple
[
str
,
list
[
Change
]]:
"""
Parse a git refspec.
Currently only basic syntax is supported, and is on the form
BASE^^
Where BASE is dircet reference to a commit (through a tag, branch,
or direct id), and `^^` is how we should move from that commit.
The exact same rules as for git-rev-parse(1) applies. (We just
interpret them in reverse).
https://git-scm.com/docs/revisions/
:return:
A tuple containing the base name, and a list containing each
change. For changes where no value was given, 1 is used.
"""
ms
=
list
(
re
.
finditer
(
r
'
([0-9]*)([~^])
'
,
''
.
join
(
reversed
(
spec
))))
changes
:
list
[
Change
]
=
[]
for
m
in
ms
:
changes
.
append
((
cast
(
ChangeType
,
m
.
group
(
2
)),
int
(
m
.
group
(
1
))
if
m
.
group
(
1
)
else
1
))
base
:
str
if
ms
:
base
=
''
.
join
(
reversed
(
''
.
join
(
reversed
(
spec
))[
ms
[
-
1
].
end
():]))
else
:
base
=
spec
return
base
,
changes
def
resolve_change_mods
(
tree
:
dict
[
bytes
,
list
[
bytes
]],
base
:
str
,
changes
:
list
[
Change
])
->
bytes
:
"""
Resolve a refspec finding children.
This takes the output of ``parse_refspec``, and locates the wanted
commit.
:param tree:
Tree where the keys are commit ids, and the children that
commits childrens id.
:param base:
The commit to start the search from. Can be either a branch,
tag, id, or anything else git-rev-parse(1) handles.
:param change:
How we should move from that commit.
:returns:
The found commits id.
"""
node
:
bytes
=
revparse
(
base
)
for
(
opt
,
count
)
in
changes
:
match
opt
:
case
'
^
'
:
node
=
tree
[
node
][
count
-
1
]
case
'
~
'
:
for
_
in
range
(
count
):
node
=
tree
[
node
][
0
]
return
node
def
build_parser
():
"""
Construct the command line argument parser.
"""
parser
=
argparse
.
ArgumentParser
(
prog
=
"
git children
"
,
description
=
"
Easily locale decendants of a git commit.
"
)
parser
.
add_argument
(
'
revision
'
,
action
=
'
store
'
,
help
=
"
Target revision. Example:
'
HEAD^^
'
.
"
)
return
parser
def
main
():
"""
Entry point of program.
"""
args
=
build_parser
().
parse_args
()
base
,
mods
=
parse_refspec
(
args
.
revision
)
ref
=
resolve_change_mods
(
children
(),
base
,
mods
)
print
(
ref
.
decode
(
'
ASCII
'
))
if
__name__
==
'
__main__
'
:
main
()
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment