4827: git merge base calculated incorrectly starting in version 1.0.1

john

What version are you running?

$ rbt --version
RBTools 1.0.2

What steps will reproduce the problem?

  1. Create a git repository with the following structure
      / --> C  (myChange, HEAD)
     /
--> A --> B  (origin/master)

For example:

~$ git clone <...>/rbtools-test.git
...
~$ cd rbtools-test/
~/rbtools-test (master)$ git log -p
commit bd13f7e28a92f46d8405fb694435c41cb59fbd3d (HEAD -> master, origin/master, origin/HEAD)
Author: John Gallagher <john.gallagher@delphix.com>
Date:   Tue Jun 4 21:00:54 2019 -0700

    bar

diff --git a/bar b/bar
new file mode 100644
index 0000000..5716ca5
--- /dev/null
+++ b/bar
@@ -0,0 +1 @@
+bar

commit eef010a325c433d57ecb18e8d24debc0fdedc3c9
Author: John Gallagher <john.gallagher@delphix.com>
Date:   Tue Jun 4 20:58:24 2019 -0700

    foo

diff --git a/foo b/foo
new file mode 100644
index 0000000..257cc56
--- /dev/null
+++ b/foo
@@ -0,0 +1 @@
+foo
~/rbtools-test (master)$ git checkout -b myChange HEAD^
Switched to a new branch 'myChange'
~/rbtools-test {myChange}$ echo baz >baz
~/rbtools-test {myChange}$ git add baz
~/rbtools-test {myChange}$ git commit -m baz
[myChange e9e8928] baz
 1 file changed, 1 insertion(+)
 create mode 100644 baz
  1. From branch myChange, run rbt diff

What is the expected output? What do you see instead?

Expected output:

  • the changes made on the current branch since it diverged with origin/master, aka
  • git diff origin/master...HEAD, aka
  • the difference between A and C in the diagram above.
diff --git a/baz b/baz
new file mode 100644
index 0000000000000000000000000000000000000000..76018072e09c5d31c8c6e3113b8aa0fe625195ca
--- /dev/null
+++ b/baz
@@ -0,0 +1 @@
+baz

Actual output:

  • the changes made on the current branch since it diverged with origin/master plus the inverse of the changes made on origin/master since the branches diverged, aka
  • git diff origin/master..HEAD, aka
  • the difference between B and C in the diagram above.
diff --git a/bar b/bar
deleted file mode 100644
index 5716ca5987cbf97d6bb54920bea6adde242d87e6..0000000000000000000000000000000000000000
--- a/bar
+++ /dev/null
@@ -1 +0,0 @@
-bar
diff --git a/baz b/baz
new file mode 100644
index 0000000000000000000000000000000000000000..76018072e09c5d31c8c6e3113b8aa0fe625195ca
--- /dev/null
+++ b/baz
@@ -0,0 +1 @@
+baz

What operating system are you using?

macOS 10.14.5

Attach the debug out from the command.

~/rbtools-test (myChange)$ rbt diff --debug
>>> RBTools 1.0.2
>>> Python 3.7.3 (default, Mar 27 2019, 09:23:15)
[Clang 10.0.1 (clang-1001.0.46.3)]
>>> Running on Darwin-18.6.0-x86_64-i386-64bit
>>> Home = /Users/jgallagher
>>> Current directory = /Users/jgallagher/junk/rbtoolsTest/rbtools-test
>>> Command line: rbt diff --debug
>>> Running: tf vc help
>>> Checking for a Bazaar repository...
>>> Unable to execute "bzr help": skipping Bazaar
>>> Checking for a ClearCase repository...
>>> Unable to execute "cleartool help": skipping ClearCase
>>> Checking for a CVS repository...
>>> Unable to execute "cvs": skipping CVS
>>> Checking for a Git repository...
>>> Running: git rev-parse --git-dir
>>> Running: git config core.bare
>>> Running: git rev-parse --show-toplevel
>>> Running: git symbolic-ref -q HEAD
>>> Running: git config --get branch.myChange.merge
>>> Command exited with rc 1: ['git', 'config', '--get', 'branch.myChange.merge']
---
>>> Running: git config --get branch.myChange.remote
>>> Command exited with rc 1: ['git', 'config', '--get', 'branch.myChange.remote']
---
>>> Running: git config --get remote.origin.url
>>> Repository info: Path: git@gitlab.delphix.com:john.gallagher/rbtools-test.git, Base path: , Supports changesets: False
>>> Checking for a Mercurial repository...
>>> Unable to execute "hg --help": skipping Mercurial
>>> Checking for a Perforce repository...
>>> Unable to execute "p4 help": skipping Perforce
>>> Checking for a Plastic repository...
>>> Unable to execute "cm version": skipping Plastic
>>> Checking for a Subversion repository...
>>> Running: svn --non-interactive info
>>> Command exited with rc 1: ['svn', '--non-interactive', 'info']
>>> Checking for a Team Foundation Server repository...
>>> Unable to execute "tf help": skipping TFS
>>> Running: git config --get reviewboard.url
>>> Making HTTP GET request to http://reviews.delphix.com/api/
>>> Running: git rev-parse refs/heads/myChange
>>> Running: git config --get branch.myChange.merge
>>> Command exited with rc 1: ['git', 'config', '--get', 'branch.myChange.merge']
---
>>> Running: git config --get branch.myChange.remote
>>> Command exited with rc 1: ['git', 'config', '--get', 'branch.myChange.remote']
---
>>> Running: git branch --remotes
>>> Running: git rev-parse origin/master
>>> Running: git rev-list bd13f7e28a92f46d8405fb694435c41cb59fbd3d --not --remotes=origin
>>> Running: git status --porcelain --untracked-files=no --ignore-submodules=dirty
>>> Running: git version
>>> Running: git -c core.quotepath=false -c diff.noprefix=false diff --no-color --full-index --ignore-submodules -M --no-ext-diff bd13f7e28a92f46d8405fb694435c41cb59fbd3d..e9e892845ee4f7e531e9c386954b07ce46fc3cb8
diff --git a/bar b/bar
deleted file mode 100644
index 5716ca5987cbf97d6bb54920bea6adde242d87e6..0000000000000000000000000000000000000000
--- a/bar
+++ /dev/null
@@ -1 +0,0 @@
-bar
diff --git a/baz b/baz
new file mode 100644
index 0000000000000000000000000000000000000000..76018072e09c5d31c8c6e3113b8aa0fe625195ca
--- /dev/null
+++ b/baz
@@ -0,0 +1 @@
+baz

Please provide any additional information below.

Through version 1.0, the behavior of rbt diff was as I would exepect. It changed to the unexpected behavior starting in version 1.0.1.

The source of the unexpected behavior is parse_revision_spec() in rbtools/clients/git.py. The revision calculated for merge_base is not the merge base of current branch and the upstream branch, but the tip upstream branch. For the simple example I gave above, the following patch corrects the output of rbt diff

diff --git a/rbtools/clients/git.py b/rbtools/clients/git.py
index 24be522..c0a1f86 100644
--- a/rbtools/clients/git.py
+++ b/rbtools/clients/git.py
@@ -153,10 +153,10 @@ class GitClient(SCMClient):
             parent_ref = self._rev_parse(parent_branch)[0]

             merge_base = self._rev_list_youngest_remote_ancestor(
-                parent_ref, remote)
+                head_ref, remote)

             result = {
-                'base': parent_ref,
+                'base': merge_base,
                 'tip': head_ref,
                 'commit_id': head_ref,
             }

I doubt this is the correct fix, I just provide it to show where I believe the issue lies. parse_revision_spec() seems to handle a lot of cases more complicated than the example I gave, so this change is probably too simplistic to be correct.