Modify git map-branches to show the number of commits on a branch

Currently, for a given branch, map-branches displays the number of
commits ahead and behind it is. This change replaces ahead with
commits, representing the number of commits a branch has, starting from
its base commit, and more accurately reflects the state of a repo.

Bug:1128716
Change-Id: I7c070b4efd452d82d878e1cfb7c20d1c80f38ec7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/2412991
Commit-Queue: Gavin Mak <gavinmak@google.com>
Reviewed-by: Josip Sokcevic <sokcevic@google.com>
diff --git a/git_common.py b/git_common.py
index 9550085..8df16a8 100644
--- a/git_common.py
+++ b/git_common.py
@@ -1036,18 +1036,21 @@
   info_map = {}
   data = run('for-each-ref', format_string, 'refs/heads')
   BranchesInfo = collections.namedtuple(
-      'BranchesInfo', 'hash upstream ahead behind')
+      'BranchesInfo', 'hash upstream commits behind')
   for line in data.splitlines():
     (branch, branch_hash, upstream_branch, tracking_status) = line.split(':')
 
-    ahead_match = re.search(r'ahead (\d+)', tracking_status)
-    ahead = int(ahead_match.group(1)) if ahead_match else None
+    commits = None
+    base = get_or_create_merge_base(branch)
+    if base:
+      commits = int(run('rev-list', '--count', branch, '^%s' % base)) or None
 
     behind_match = re.search(r'behind (\d+)', tracking_status)
     behind = int(behind_match.group(1)) if behind_match else None
 
     info_map[branch] = BranchesInfo(
-        hash=branch_hash, upstream=upstream_branch, ahead=ahead, behind=behind)
+        hash=branch_hash, upstream=upstream_branch, commits=commits, 
+        behind=behind)
 
   # Set None for upstreams which are not branches (e.g empty upstream, remotes
   # and deleted upstream branches).
diff --git a/git_map_branches.py b/git_map_branches.py
index eac29fb..c35368f 100755
--- a/git_map_branches.py
+++ b/git_map_branches.py
@@ -248,29 +248,30 @@
 
     # The branch tracking status.
     if self.verbosity >= 1:
-      ahead_string = ''
+      commits_string = ''
       behind_string = ''
       front_separator = ''
       center_separator = ''
       back_separator = ''
       if branch_info and not self.__is_invalid_parent(branch_info.upstream):
-        ahead = branch_info.ahead
         behind = branch_info.behind
+        commits = branch_info.commits
 
-        if ahead:
-          ahead_string = 'ahead %d' % ahead
+        if commits:
+          commits_string = '%d commit' % commits
+          commits_string += 's' if commits > 1 else ' '
         if behind:
           behind_string = 'behind %d' % behind
 
-        if ahead or behind:
+        if commits or behind:
           front_separator = '['
           back_separator = ']'
 
-        if ahead and behind:
+        if commits and behind:
           center_separator = '|'
 
       line.append(front_separator, separator=' ')
-      line.append(ahead_string, separator=' ', color=Fore.MAGENTA)
+      line.append(commits_string, separator=' ', color=Fore.MAGENTA)
       line.append(center_separator, separator=' ')
       line.append(behind_string, separator=' ', color=Fore.MAGENTA)
       line.append(back_separator)
diff --git a/man/html/git-map-branches.html b/man/html/git-map-branches.html
index eb4a3f2..f014161 100644
--- a/man/html/git-map-branches.html
+++ b/man/html/git-map-branches.html
@@ -860,10 +860,10 @@
 <span style="color: #d338d3"></span><span style="color: #d338d3">{NO_UPSTREAM}          </span><span style="color: #ffffff">  </span><span style="color: #d338d3">        </span><span style="color: #ffffff">  </span><span style="color: #d338d3">         </span><span style="color: #ffffff">
 </span><span style="color: #19c518"></span><span style="color: #19c518">  no_upstream          </span><span style="color: #ffffff">  </span><span style="color: #d338d3">        </span><span style="color: #ffffff">  </span><span style="color: #d338d3">         </span><span style="color: #ffffff">
 </span><span style="color: #e42e16"></span><span style="color: #e42e16">origin/master          </span><span style="color: #ffffff">  </span><span style="color: #d338d3">        </span><span style="color: #ffffff">  </span><span style="color: #d338d3">         </span><span style="color: #ffffff">
-</span><span style="color: #19c518"></span><span style="color: #19c518">  cool_feature         </span><span style="color: #ffffff">[ </span><span style="color: #d338d3">ahead 4 </span><span style="color: #ffffff">  </span><span style="color: #d338d3">         </span><span style="color: #ffffff">]
-</span><span style="color: #19c518"></span><span style="color: #19c518">    subfeature         </span><span style="color: #ffffff">[ </span><span style="color: #d338d3">ahead 2 </span><span style="color: #ffffff">| </span><span style="color: #d338d3">behind 1 </span><span style="color: #ffffff">]
-</span><span style="color: #19c518"></span><span style="color: #19c518">  fixit                </span><span style="color: #ffffff">[ </span><span style="color: #d338d3">ahead 2 </span><span style="color: #ffffff">  </span><span style="color: #d338d3">         </span><span style="color: #ffffff">]
-</span><span style="color: #33d6e5"></span><span style="font-weight: bold; color: #33d6e5">    frozen_branch *    </span><span style="font-weight: bold; color: #ffffff">[ </span><span style="font-weight: bold; color: #d338d3">ahead 3 </span><span style="font-weight: bold; color: #ffffff">  </span><span style="font-weight: bold; color: #d338d3">         </span><span style="font-weight: bold; color: #ffffff">]</span>
+</span><span style="color: #19c518"></span><span style="color: #19c518">  cool_feature         </span><span style="color: #ffffff">[ </span><span style="color: #d338d3">4 commits </span><span style="color: #ffffff">  </span><span style="color: #d338d3">         </span><span style="color: #ffffff">]
+</span><span style="color: #19c518"></span><span style="color: #19c518">    subfeature         </span><span style="color: #ffffff">[ </span><span style="color: #d338d3">2 commits </span><span style="color: #ffffff">| </span><span style="color: #d338d3">behind 1 </span><span style="color: #ffffff">]
+</span><span style="color: #19c518"></span><span style="color: #19c518">  fixit                </span><span style="color: #ffffff">[ </span><span style="color: #d338d3">2 commits </span><span style="color: #ffffff">  </span><span style="color: #d338d3">         </span><span style="color: #ffffff">]
+</span><span style="color: #33d6e5"></span><span style="font-weight: bold; color: #33d6e5">    frozen_branch *    </span><span style="font-weight: bold; color: #ffffff">[ </span><span style="font-weight: bold; color: #d338d3">3 commits </span><span style="font-weight: bold; color: #ffffff">  </span><span style="font-weight: bold; color: #d338d3">         </span><span style="font-weight: bold; color: #ffffff">]</span>
 </code></pre></div></div><p><div class="paragraph"></p></div>
 </div>
 </div>
diff --git a/man/man1/git-map-branches.1 b/man/man1/git-map-branches.1
index 23c0d03..88de449 100644
--- a/man/man1/git-map-branches.1
+++ b/man/man1/git-map-branches.1
@@ -172,10 +172,10 @@
 {NO_UPSTREAM}
   no_upstream
 origin/master
-  cool_feature         [ ahead 4            ]
-    subfeature         [ ahead 2 | behind 1 ]
-  fixit                [ ahead 2            ]
-\fB    frozen_branch *    [ ahead 3            ]\fR
+  cool_feature         [ 4 commits            ]
+    subfeature         [ 2 commits | behind 1 ]
+  fixit                [ 2 commits            ]
+\fB    frozen_branch *    [ 3 commits            ]\fR
 .fi
 .if n \{\
 .RE
diff --git a/tests/git_common_test.py b/tests/git_common_test.py
index a0ac1ee..c382cdb 100755
--- a/tests/git_common_test.py
+++ b/tests/git_common_test.py
@@ -524,6 +524,59 @@
     }
     self.assertEqual(expected, actual)
 
+  def testGetBranchesInfoWithReset(self):
+    self.repo.git('commit', '--allow-empty', '-am', 'foooooo')
+    self.repo.git('checkout','-tb', 'foobarA', 'master')
+    self.repo.git('config', 'branch.foobarA.base',
+      self.repo.run(self.gc.hash_one, 'master'))
+    self.repo.git('config', 'branch.foobarA.base-upstream', 'master')
+
+    with self.repo.open('foobar1', 'w') as f:
+      f.write('hello')
+    self.repo.git('add', 'foobar1')
+    self.repo.git_commit('commit1')
+
+    with self.repo.open('foobar2', 'w') as f:
+      f.write('goodbye')
+    self.repo.git('add', 'foobar2')
+    self.repo.git_commit('commit2')
+
+    self.repo.git('checkout','-tb', 'foobarB', 'foobarA')
+    self.repo.git('config', 'branch.foobarB.base',
+      self.repo.run(self.gc.hash_one, 'foobarA'))
+    self.repo.git('config', 'branch.foobarB.base-upstream', 'foobarA')
+    self.repo.git('checkout', 'foobarA')
+    self.repo.git('reset', '--hard', 'HEAD~')
+
+    with self.repo.open('foobar', 'w') as f:
+      f.write('world')
+    self.repo.git('add', 'foobar')
+    self.repo.git_commit('commit1.2')
+
+    actual = self.repo.run(self.gc.get_branches_info, True)
+    expected = {
+        'foobarA': (
+            self.repo.run(self.gc.hash_one, 'foobarA', short=True),
+            'master',
+            2,
+            None
+        ),
+        'foobarB': (
+            self.repo.run(self.gc.hash_one, 'foobarB', short=True),
+            'foobarA',
+            None,
+            1
+        ),
+        'master': (
+            self.repo.run(self.gc.hash_one, 'master', short=True),
+            '',
+            None,
+            None
+        ),
+        '': None
+    }
+    self.assertEqual(expected, actual)
+
 
 class GitMutableStructuredTest(git_test_utils.GitRepoReadWriteTestBase,
                                GitCommonTestBase):