Code Monkey home page Code Monkey logo

git2dot's Introduction

This is just me experimenting with an awesome project I just found: https://github.com/jlinoff/git2dot

Visualize a git repository using the graphviz dot tool.

Here is an example that shows the PNG file generated by test04 in the test directory.

https://cloud.githubusercontent.com/assets/2991242/22413672/a3357722-e66e-11e6-8cc8-332b5123a561.png

  • [ ] Remove summary?
  • [ ] Use pydot to create the dot source
  • [ ] Use bats for tests
  • [ ] Update –range to be –git-extra-opts or –git-log-extra-opts
  • [ ] GitHub Action that runs tests
  • [ ] Single squash node
  • [ ] Ability to create graphs with simple labels like A, B, C, D (instead of git commit SHAs)
    • Probably a --msg flag, which puts the commit message in the node instead of the git hash.

git log

Just have one option for modifying git log: --git-log-opts. There you can pass =”–branches”=, =”–tags”=, =”–since”=, … anything that filters the git log. You can do anything except for changing the log format.

Nodes

Kinds of nodes:

  • Commit Node - A commit.
    • Abbrev: cnode
    • Default color: bisque (tan)
  • Branch Node - A branch.
    • Abbrev: bnode
    • Default color: light blue
  • Merge Node - A Merge commit (a commit that has 2 or more parents).
    • Abbrev: mnode
    • Default color: light red
  • Squash Node - The end-points of a squashed commit chain. Squashed commit chains do not have any branches, tags, change-ids or merges.
    • Abrev: snode
    • Default color: dark red
  • Tag Node - A git tag.
    • Abbrev: tnode
    • Default color: light purple

Commit, merge, and squash nodes show the short id, commit date, the subject (truncated to 32 characters) and the change-id (if it exists).

Edges

Kinds of edges:

  • Parent Edge - From a node to its parent.
    • Abbrev: pedge
  • Squash Edge - Between squash nodes.
    • Abbrev: sedge
  • Branch Edge - From a branch node to a commit node.
    • Abbrev: bedge
  • Tag Edge - From a tag node.
    • Abbrev: tedge

Examples

Here is an example run:

git2dot --png git.dot

The output is pretty customizable. For example, to add the subject and commit date to the commit node names use -l '%s|%cr'=. The items come from the git format placeholders or variables that you define using =-D. The | separator is used to define the end of a line. The maximum width of each line can be specified by -w. Variables are defined by -D and come from text in the commit message. See -D for more details.

You can customize the attributes of the different types of nodes and edges in the graph using the -?node and -?edge attributes. The table below briefly describes the different node types:

Node TypeBrief Description
bedgeEdge connecting to a bnode.
bnodeBranch node associated with a commit.
cnodeCommit node (simple commit node).
mnodeMerge node. A commit node with multiple children.
snodeSquashed node. End point of a sequence of squashed nodes.
tedgeEdge connecting to a tnode.
tnodeTag node associated with a commit.

If you have long chains of single commits use the --squash option to squash out the middle ones. That is generally helpful for filtering out extraneous commit details for moderately sized repos.

If you find that dot is placing your bnode and tnode nodes in odd places, use the --crunch option to collapse the bnode nodes into a single node and the tnodes into a single node for each commit.

If you want to limit the analysis to commits between certain dates, use the --since and --until options.

If you want to limit the analysis to commits in a certain range use the --range option.

If you want to limit the analysis to a small set of branches or tags you can use the --choose-branch and --choose-tag options. These options prune the graph so that only parents of commits with the choose branch or tag ids are included in the graph. This gives you more detail controlled that the git options allowed in the –range command. It is very useful for determining where branches occurred.

You can choose to keep the git output to re-use multiple times with different display options or to share by specifying the -k (--keep) option.

Use the -h option to get detailed information about the available options.

Example

echo 'A' > README
git add README
git commit -m 'master - first'

echo 'B' >> README
git add README
git commit -m 'master - second' -m 'Change-Id: I001'

# tag the basis for all of the branches
git tag -a 'v1.0' -m 'Initial version.'
git tag -a 'v1.0a' -m 'Another version.'

git checkout -b branchX1
git checkout master
git checkout -b branchX2

git checkout master
git checkout -b branchA
echo 'C' >> README
git add README
git commit -m 'branchA - first'

echo 'B' >> README
git add README
git commit -m 'branchA - second' -m 'Change-Id: I001'

git checkout master
git checkout -b branchB
echo 'E' >> README
git add README
git commit -m 'branchB - first'

echo 'F' >> README
git add README
git commit -m 'branchB - second'

echo 'B' >> README
git add README
git commit -m 'branchB - third' -m 'Change-Id: I001'

echo 'H' >> README
git add README
git commit -m 'branchB - fourth' -m 'Change-Id: I002'

echo 'I' >> README
git add README
git commit -m 'branchB - fifth'

echo 'J' >> README
git add README
git commit -m 'branchB - sixth'

echo 'K' >> README
git add README
git commit -m 'branchB - seventh'

git checkout master
echo 'L' >> README
git add README
git commit -m 'master - third'

You can verify the repo structure using something like git log.

Now run the git2dot tool to generate PNG, HTML and SVG files.

git2dot.py --png --svg --html example.html example.dot
ls -1 example.*
example.dot
example.dot.png
example.dot.svg
example.html

To view the generated SVG file with pan and zoom you must download the svg-pan-zoom.min.js file from https://github.com/ariutta/svg-pan-zoom and copy into the current directory.

cp ~/work/svg-pan-zoom-3.4.1/dist/svg-pan-zoom.min.js .
ls -1 example* svg*
example.dot
example.dot.png
example.dot.svg
example.html
svg-pan-zoom.min.js

Now you need to start a server.

python -m SimpleHTTPServer 8090

After that you can browse to http://localhost:8090/example.html and you will see this.

<img src=”https://cloud.githubusercontent.com/assets/2991242/22431235/b585cf7e-e6c5-11e6-8f17-6b99847bfe51.png” width=”1100” alt=”example”>

As you can see, there is a long chain of commits, to run it again using the --squash option.

git2dot.py --squash --png --svg --html example1.html example1.dot

And browse to http://localhost:8090/example1.html and you will see this.

<img src=”https://cloud.githubusercontent.com/assets/2991242/22431252/c5077344-e6c5-11e6-95b0-54cd02d11aa2.png” width=”1100” alt=”example1”>

Which is a cleaner view of the overall structure.

You will also note that there are two branches and two tags on ecdc7dc. They can be collapsed using the --crunch option like this.

git2dot --crunch --squash --png --svg --html example1.html example1.dot

When you browse to http://localhost:8090/example2.html and you will see this.

<img src=”https://cloud.githubusercontent.com/assets/2991242/22431258/c89d7e7c-e6c5-11e6-826e-cf7450b9f125.png” width=”1100” alt=”example2”>

For such a small graph the crunch operation doesn’t really make things simpler but for larger graphs where dot may move the branch and tag information around, it can be a much cleaner view.

Example 2 - pruning the graph

There are two more options you will want to think about for making large graphs more readable: --choose-branch and --choose-tag. As described earlier, they prune the graph so that it only considers the parent chains of the specified branches or tags. This can be very useful to determining where branches occurred.

This example shows how it works.

First you create a repository like this.

git init

echo 'A' >example2.txt
git add example2.txt
git commit -m 'master - first'
sleep 1

echo 'B' >>example2.txt
git add example2.txt
git commit -m 'master - second'
sleep 1

# tag the basis for all of the branches
git tag -a 'v1.0' -m 'Initial version.'
git tag -a 'v1.0a' -m 'Another version.'

git checkout -b branchX1
git checkout master
git checkout -b branchX2

git checkout master
git checkout -b branchA
echo 'C' >> example2.txt
git add example2.txt
git commit -m 'branchA - first'
sleep 1

echo 'D' >> example2.txt
git add example2.txt
git commit -m 'branchA - second'
sleep 1

echo 'E' >> example2.txt
git add example2.txt
git commit -m 'branchA - third'
sleep 1

echo 'F' >> example2.txt
git add example2.txt
git commit -m 'branchA - fourth'
sleep 1

git checkout master
git checkout -b branchB
echo 'G' >> example2.txt
git add example2.txt
git commit -m 'branchB - first'
sleep 1

echo 'H' >> example2.txt
git add example2.txt
git commit -m 'branchB - second'
sleep 1

echo 'I' >> example2.txt
git add example2.txt
git commit -m 'branchB - third'
sleep 1

echo 'J' >> example2.txt
git add example2.txt
git commit -m 'branchB - fourth'
sleep 1
git tag -a 'v2.0a' -m 'Initial version.'

echo 'K' >> example2.txt
git add example2.txt
git commit -m 'branchB - fifth'
sleep 1

echo 'L' >> example2.txt
git add example2.txt
git commit -m 'branchB - sixth'
sleep 1

echo 'M' >> example2.txt
git add example2.txt
git commit -m 'branchB - seventh'
sleep 1

git checkout master
echo 'N' >> example2.txt
git add example2.txt
git commit -m 'master - third'
sleep 1

echo 'O' >> example2.txt
git add example2.txt
git commit -m 'master - fourth'

You can confirm its layout like this.

git log --graph --oneline --decorate --all --topo-order

Create the graph without pruning.

git2dot \
    --graph-label 'graph[label="example2 - compressed initial state"]' \
    --crunch --squash --png --svg \
    --html example2-2.html \
    example2-2.dot

<img src=”https://cloud.githubusercontent.com/assets/2991242/22488086/0d34a592-e7c5-11e6-91d8-720f21e357f6.png” width=”1100” alt=”example2-2”>

Create the graph with pruning.

git2dot \
    --graph-label 'graph[label="example2 - compressed pruned state"]' \
    --choose-branch 'branchA' \
    --choose-tag 'tag: v2.0a' \
    --crunch --squash --png --svg --html example2-4.html \
    example2-4.dot

<img src=”https://cloud.githubusercontent.com/assets/2991242/22488091/11ae8912-e7c5-11e6-9818-1c8e9c607182.png” width=”1100” alt=”example2-4”>

As you can see, branchB has been completely removed in the second one.

Eat your own dog food

Here is the generated image of the git2dot development tree for v0.6.

<img src=”https://cloud.githubusercontent.com/assets/2991242/22603307/b1538d68-e9fb-11e6-859b-7c0387e9b972.png” width=”1100” alt=”dog food”>

It was generated with this command.

git2dot \
    -s -c --png \
    --graph-label 'graph[label="git2dot v0.6", fontsize="18"]' \
    git.dot

Here is how I created a pannable and zoomable version of the “eat your own dog food” graph.

First I created the HTML and SVG files in an example directory. I also created a PNG file for local testing. Note that I ran the git2dot.py command in the git2dot repo and directed the output to the example directory.

mkdir ~/work/git2dot-zoom-example
cd ~/work/git2dot  # the repo
git2dot -s -c \
        -L 'graph[label="\ngit2dot v0.6", fontsize="24"]' \
        --png --svg --html ~/work/git2dot-zoom-example/git.html \
        --choose-tag 'tag: v0.6' \
        ~/work/git2dot-zoom-example/git.dot
open -a Preview ~/work/git2dot-zoom-example/git.png

I then copied over the svg-pan-zoom.min.js file. Without it, panning and zooming cannot work.

cd ~/work/git2dot-zoom-example
cp ~/work/svg-pan-zoom/dist/svg-pan-zoom.min.js .

Once the files were in place, I started a simple HTTP server in the same directory that I created the HTML and SVG files.

cd ~/work/git2dot-zoom-example
python -m SimpleHTTPServer 8081

I then navigated to http://localhost:8081/git.html in a browser and saw this.

<img src=”https://cloud.githubusercontent.com/assets/2991242/22622763/0b8e6ea8-eaf9-11e6-98b0-94869f7b0f30.png” width=”1100” alt=”dog food 1”>

After that I panned to the left (left-mouse-button-down and drag) and zoomed in using the mousewheel to see the most recent tag.

<img src=”https://cloud.githubusercontent.com/assets/2991242/22622765/193a16b0-eaf9-11e6-81ba-950ff26fc13b.png” width=”1100” alt=”dog food zoom”>

Hints

  1. For large graphs consider using the --squash option.
  2. For large graphs consider using the svg-pan-zoom zoom() function when the data is loaded to make the nodes visible.
  3. For graphs that have multiple branches and tags on the same commits consider using the --crunch option.
  4. If you only want to see the combined history of a few branches or tags (like release branches) consider using the --choose-branch and --choose-tag options to prune the graph.
  5. Use the --since option if you don’t care about ancient history.
  6. The --graph-label option can be useful and can be very simple: --graph-label 'graph[label“MY LABEL”]’=.
  7. Read the program help: -h or --help, there is a lot of useful information there.

Summary data

The generated dot file has summary fields at the end that can be useful for post processing.

The fields are written as dot comments like this.

// summary:num_graph_commit_nodes 5
// summary:num_graph_merge_nodes 1
// summary:num_graph_squash_nodes 2
// summary:total_commits 12
// summary:total_graph_commit_nodes 8

They are described in the table below.

FieldDescription
// summary:num_graph_commit_nodes INTThe total number of simple commit nodes in the graph.
// summary:num_graph_merge_nodes INTThe total nummber of merge commit nodes in the graph.
// summary:num_graph_squash_nodes INTThe total number of squash commit nodes in the graph.
// summary:total_commits INTThe total number of commits (incuding merges) with no squashing.
// summary:total_graph_commit_nodes INTThe number of actual commit nodes in the graph.

Note that total_commits and total_graph_commit_nodes will be the same if squashing is not specified.

git2dot's People

Contributors

jlinoff avatar cfclrk avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.