From 3dae3eaaacbb9259a6c7d9c5e32ce0cebf4d94b4 Mon Sep 17 00:00:00 2001 From: Jacob Stopak Date: Mon, 6 Mar 2023 23:05:38 -0800 Subject: [PATCH 1/2] Add --color-by=author option to color commits by author after drawing commit graph Signed-off-by: Jacob Stopak --- README.md | 2 + git_sim/__main__.py | 5 +++ git_sim/branch.py | 1 + git_sim/cherrypick.py | 1 + git_sim/git_sim_base_command.py | 66 ++++++++++++++++++++++++++++++--- git_sim/log.py | 1 + git_sim/merge.py | 5 +++ git_sim/rebase.py | 1 + git_sim/settings.py | 1 + git_sim/tag.py | 1 + 10 files changed, 79 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a4d71a0..133ee2f 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ Example: `$ git-sim merge ` - Run a one-liner git-sim command in the terminal to generate a custom Git command visualization (.jpg) from your repo - Supported commands: `log`, `status`, `add`, `restore`, `commit`, `stash`, `branch`, `tag`, `reset`, `revert`, `merge`, `rebase`, `cherry-pick` - Generate an animated video (.mp4) instead of a static image using the `--animate` flag (note: significant performance slowdown, it is recommended to use `--low-quality` to speed up testing and remove when ready to generate presentation-quality video) +- Color commits by parameter, such as author the `--color-by=author` option - Choose between dark mode (default) and light mode - Specify output formats of either jpg, png, mp4, or webm - Combine with bundled command [git-dummy](https://github.com/initialcommit-com/git-dummy) to generate a dummy Git repo and then simulate operations on it @@ -136,6 +137,7 @@ The `[global options]` apply to the overarching `git-sim` simulation itself, inc `-n `: Number of commits to display from each branch head. `--all`: Display all local branches in the log output. `--animate`: Instead of outputting a static image, animate the Git command behavior in a .mp4 video. +`--color-by author`: Color commits by parameter, such as author. `--invert-branches`: Invert positioning of branches by reversing order of multiple parents where applicable. `--hide-merged-branches`: Hide commits from merged branches, i.e. only display mainline commits. `--media-dir`: The path at which to store the simulated output media files. diff --git a/git_sim/__main__.py b/git_sim/__main__.py index 570d17a..8c029bf 100644 --- a/git_sim/__main__.py +++ b/git_sim/__main__.py @@ -134,6 +134,10 @@ def main( settings.all, help="Display all local branches in the log output", ), + color_by: str = typer.Option( + settings.color_by, + help="Color commits by parameter, such as author", + ), ): settings.animate = animate settings.n = n @@ -159,6 +163,7 @@ def main( settings.invert_branches = invert_branches settings.hide_merged_branches = hide_merged_branches settings.all = all + settings.color_by = color_by if sys.platform == "linux" or sys.platform == "darwin": repo_name = git.repo.Repo( diff --git a/git_sim/branch.py b/git_sim/branch.py index e75fae1..6c949a0 100644 --- a/git_sim/branch.py +++ b/git_sim/branch.py @@ -49,6 +49,7 @@ def construct(self): self.recenter_frame() self.scale_frame() + self.color_by() self.fadeout() self.show_outro() diff --git a/git_sim/cherrypick.py b/git_sim/cherrypick.py index 822f75f..8da873a 100644 --- a/git_sim/cherrypick.py +++ b/git_sim/cherrypick.py @@ -67,6 +67,7 @@ def construct(self): self.recenter_frame() self.scale_frame() self.reset_head_branch("abcdef") + self.color_by(offset=2) self.fadeout() self.show_outro() diff --git a/git_sim/git_sim_base_command.py b/git_sim/git_sim_base_command.py index 196ee82..7d4c6da 100644 --- a/git_sim/git_sim_base_command.py +++ b/git_sim/git_sim_base_command.py @@ -28,8 +28,19 @@ def __init__(self): self.selected_branches = [] self.zone_title_offset = 2.6 if platform.system() == "Windows" else 2.6 self.arrow_map = [] + self.arrows = [] self.all = settings.all self.first_parse = True + self.author_groups = {} + self.colors = [ + m.ORANGE, + m.YELLOW, + m.GREEN, + m.BLUE, + m.MAROON, + m.PURPLE, + m.GOLD, + ] self.logo = m.ImageMobject(settings.logo) self.logo.width = 3 @@ -276,6 +287,8 @@ def draw_commit(self, commit, i, prevCircle, shift=numpy.array([0.0, 0.0, 0.0])) if commit != "dark": self.drawnCommits[commit.hexsha] = circle + group = m.Group(circle, commitId, message) + self.add_group_to_author_groups(commit.author.name, group) self.toFadeOut.add(circle, commitId, message) self.prevRef = commitId @@ -374,7 +387,7 @@ def draw_branch(self, commit, i): else: self.add(fullbranch) - self.toFadeOut.add(branchRec, branchText) + self.toFadeOut.add(fullbranch) self.drawnRefs[branch] = fullbranch if i == 0 and self.first_parse: @@ -410,18 +423,20 @@ def draw_tag(self, commit, i): tagRec.next_to(self.prevRef, m.UP) tagText.move_to(tagRec.get_center()) + fulltag = m.VGroup(tagRec, tagText) + self.prevRef = tagRec if settings.animate: self.play( - m.Create(tagRec), - m.Create(tagText), + m.Create(fulltag), run_time=1 / settings.speed, ) else: - self.add(tagRec, tagText) + self.add(fulltag) - self.toFadeOut.add(tagRec, tagText) + self.toFadeOut.add(fulltag) + self.drawnRefs[tag] = fulltag if i == 0 and self.first_parse: self.topref = self.prevRef @@ -439,6 +454,7 @@ def draw_arrow(self, prevCircle, arrow): else: self.add(arrow) + self.arrows.append(arrow) self.toFadeOut.add(arrow) def recenter_frame(self): @@ -896,6 +912,7 @@ def setup_and_draw_parent( self.play(m.Create(arrow), run_time=1 / settings.speed) else: self.add(arrow) + self.arrows.append(arrow) self.toFadeOut.add(arrow) return commitId @@ -1042,6 +1059,45 @@ def create_zone_text( thirdColumnFiles.add(text) thirdColumnFilesDict[f] = text + def color_by(self, offset=0): + if settings.color_by == "author": + sorted_authors = sorted( + self.author_groups.keys(), + key=lambda k: len(self.author_groups[k]), + reverse=True, + ) + for i, author in enumerate(sorted_authors): + authorText = m.Text( + f"{author[:15]} ({str(len(self.author_groups[author]))})", + font="Monospace", + font_size=36, + color=self.colors[int(i % 7)], + ) + authorText.move_to( + [(-5 - offset) if settings.reverse else (5 + offset), -i, 0] + ) + self.toFadeOut.add(authorText) + if i == 0: + self.recenter_frame() + self.scale_frame() + if settings.animate: + self.play(m.AddTextLetterByLetter(authorText)) + else: + self.add(authorText) + for g in self.author_groups[author]: + g[0].set_color(self.colors[int(i % 7)]) + self.recenter_frame() + self.scale_frame() + + elif settings.color_by == "branch": + pass + + def add_group_to_author_groups(self, author, group): + if author not in self.author_groups: + self.author_groups[author] = [group] + else: + self.author_groups[author].append(group) + class DottedLine(m.Line): def __init__(self, *args, dot_spacing=0.4, dot_kwargs={}, **kwargs): diff --git a/git_sim/log.py b/git_sim/log.py index 93c7e4e..491d494 100644 --- a/git_sim/log.py +++ b/git_sim/log.py @@ -43,6 +43,7 @@ def construct(self): self.parse_all() self.recenter_frame() self.scale_frame() + self.color_by() self.fadeout() self.show_outro() diff --git a/git_sim/merge.py b/git_sim/merge.py index ae73f42..f83d59f 100644 --- a/git_sim/merge.py +++ b/git_sim/merge.py @@ -93,6 +93,10 @@ def construct(self): text=self.repo.active_branch.name, color=m.GREEN, ) + if self.no_ff: + self.color_by(offset=2) + else: + self.color_by() else: self.parse_commits(head_commit) @@ -111,6 +115,7 @@ def construct(self): self.recenter_frame() self.scale_frame() self.reset_head_branch("abcdef") + self.color_by(offset=2) self.fadeout() self.show_outro() diff --git a/git_sim/rebase.py b/git_sim/rebase.py index 91c7570..6effcd8 100644 --- a/git_sim/rebase.py +++ b/git_sim/rebase.py @@ -102,6 +102,7 @@ def construct(self): self.recenter_frame() self.scale_frame() self.reset_head_branch(parent) + self.color_by(offset=2 * len(to_rebase)) self.fadeout() self.show_outro() diff --git a/git_sim/settings.py b/git_sim/settings.py index 0b571ec..53c029a 100644 --- a/git_sim/settings.py +++ b/git_sim/settings.py @@ -45,6 +45,7 @@ class Settings(BaseSettings): invert_branches = False hide_merged_branches = False all = False + color_by: Union[str, None] = None class Config: env_prefix = "git_sim_" diff --git a/git_sim/tag.py b/git_sim/tag.py index 4eb1135..cbdd772 100644 --- a/git_sim/tag.py +++ b/git_sim/tag.py @@ -49,6 +49,7 @@ def construct(self): self.recenter_frame() self.scale_frame() + self.color_by() self.fadeout() self.show_outro() From 0f1e3537ffa30234f208a6e9a390bcb603e25b4f Mon Sep 17 00:00:00 2001 From: Jacob Stopak Date: Mon, 6 Mar 2023 23:05:57 -0800 Subject: [PATCH 2/2] Bump version to 0.2.7 Signed-off-by: Jacob Stopak --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index f9c5df1..a5b5db5 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setuptools.setup( name="git-sim", - version="0.2.6", + version="0.2.7", author="Jacob Stopak", author_email="jacob@initialcommit.io", description="Simulate Git commands on your own repos by generating an image (default) or video visualization depicting the command's behavior.",