Announcing git graph and advanced filters to visualize commit history

Did you ever want a quick way to understand change history in a branch? VSTS now shows git graph in commit history for files in repositories. Now you can easily create a mental model of all your branches and commits for your git repositories using git graph.

VSTS commit history also supports advanced filters that allow you to view various history of the repository, branches, or files with various levels of granularity to support complex scenarios.

How can git graph help?

Commits with graph

commits-with-graph

 

In the figure above, just a cursory glance at the graph, tells that the author branch and then proceeded to update the readme, fix some bugs, work on a feature on the dev branch that was later merged to the master branch using PR 45. Since we show the topological order in the graph view, it clearly groups all changes descendant commits before their parents.

Graph is particularly helpful in busy repositories where changes are made by multiple authors for multiple files across branches at the same time. It makes it easier to identify rogue commits and their associated information therefore allowing to

Git graph experience

  • The blue dots represent any commit in the repo or a file
  • The grey dots represent a merge commit.
  • A line connects a commit to its ancestor commit. In case a commit does not show its parent within the next 50 commits, you will see an arrow that once clicked will connect the commit to its parent commit.

parent-commit-for-7c24c9a1

Parent commit for 7c24c9a1 is not within the next 50 commits or in the view port.

 

connect-to-parent

Clicking on the graph node for 7c24c9a1 connects the commit to its parent commit.

Advanced filters

Now, VSTS supports advanced commit filters such as :

  • Simple history
  • First parent
  • Full history
  • Full History with simplified merges

filters

 

By default the commit history view in VSTS is filtered to show Simple history. In simple history git simplifies the history e.g. In a case where a merge commit (commit M) rolls back a change of a previous commit (commit P), simple history won’t show commit P since the changes associated with it has no impact on the final state of the file. These are cases where one can find it very difficult to find where and how the changes introduced to a file went missing.

This is where with simplified merges” can help. Git keeps all the changes associated with the file and when you filter your results by  “full history”, the hidden commits such as “commit P” would start showing up.

In order to explain this a little better I will use the same example as mentioned in Ross Brodbeck’s blog.

examples

In this case, the user followed the following steps:

 

# Task performed Associated commit message
1 Created a file test.txt and added some content to it in the master branch. Initial commit.
2 Created a new branch animals from master and updated the content of test.txt.
3 Next, created another branch fruit from master and updated the content of test.txt
4 Merge the animals branch to master We have added an animal
5 Merge fruit branch to master.

 

At this stage the user gets a conflict error and she chose to simply create a new file called test.txt in the fruit branch and merge it to master.

We have added a fruit

 

As a result, since the changes associated with the commit “We have added an animal” are already overwritten by the commit “We have added a fruit”, simplified git history does not show the commit “We have added an animal”.

added-a-fruit

 

 

Once you change the filter to “Full history” you can see all the changes that impacted the file test.txt including our missing commit “We have added an animal” as shown in the image below.

added-an-animal

 

You can see all read changes that impacted the file test.txt including our missing commit.

all-changes

 

Similarly, other options such as can be very useful to see commits that occurred directly on the branch itself and not to another branch that got merged into the current branch.

2