Differences of bundled Git/Mercurial to original ones

What are the exact details of the differences between the bundled Git/Mercurial versions compared to the original ones where they derived from?

1 answer

1 accepted

0 votes
Answer accepted

Git is unchanged, it's just the binary version you can download from their site at the version number listed in the Preferences > Git page.

Mercurial has had some minor patches applied to make sure things like password prompts are fully flushed even when called by something that's not a real terminal, so SourceTree can see them and respond. The full source code is included inside SourceTree (we tell you where in the About box, but for info it's SourceTree.app/Contents/Resources/mercurial_local) to comply with the GPL, and you can diff that against the source version of Mercurial to see the changes. Obviously if you diff it against the upstream source version at the version displayed in Preferences > Mercurial you'll get just the changes we made.

That's what we do to comply with the GPL, but to make it even easier, here's the 2 patch files we apply to the embedded version. The first one isolates temporary files associated with checks to a location we can identify, so they don't make ST think that files have changed and cause an unnecessary refresh to occur

diff --git a/mercurial/dirstate.py b/mercurial_local/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -113,11 +113,25 @@
     def _checklink(self):
-        return util.checklink(self._root)
+		 # Force checks to happen in '.hgcheck' folder so we can identify them
+         d = os.path.join(self._root, '.hgcheck')
+         try:
+             if not os.path.isdir(d):
+                 os.mkdir(d)
+             return util.checklink(d)
+         except (IOError, OSError):
+             return False
     def _checkexec(self):
-        return util.checkexec(self._root)
+		 # Force checks to happen in '.hgcheck' folder so we can identify them
+         d = os.path.join(self._root, '.hgcheck')
+         try:
+             if not os.path.isdir(d):
+                 os.mkdir(d)
+             return util.checkexec(d)
+         except (IOError, OSError):
+             return False
     def _checkcase(self):

The second deals with flushing user/password prompts:

--- a/mercurial-2.0/mercurial/ui.py	2011-11-01 20:36:00.000000000 +0000
+++ b/mercurial/ui.py	2011-11-11 12:18:19.000000000 +0000
@@ -551,19 +551,13 @@
             except Exception:
-        # call write() so output goes through subclassed implementation
-        # e.g. color extension on Windows
-        self.write(prompt)
-        # instead of trying to emulate raw_input, swap (self.fin,
-        # self.fout) with (sys.stdin, sys.stdout)
-        oldin = sys.stdin
-        oldout = sys.stdout
-        sys.stdin = self.fin
-        sys.stdout = self.fout
-        line = raw_input(' ')
-        sys.stdin = oldin
-        sys.stdout = oldout
+        # SourceTree mod: prompt using read_line instead which ensures prompt is flushed
+        self.write_err(prompt)
+        line = sys.stdin.readline()
+        # get rid of \r
+        line = line[:-1]
+        #line = raw_input(prompt)
+        # End SourceTree mod
         # When stdin is in binary mode on Windows, it can cause
         # raw_input() to emit an extra trailing carriage return
@@ -604,7 +598,16 @@
         if not self.interactive():
             return default
-            return getpass.getpass(prompt or _('password: '))
+            # Ensure we flush so that we can read prompt in non-terminal
+            self.write_err('password:')
+            pwd = sys.stdin.readline() 
+            # get rid of \r \n
+            if pwd and pwd[-1] == '\n':
+                pwd = pwd[:-1]
+            if pwd and pwd[-1] == '\r':
+                pwd = pwd[:-1]
+            return pwd
         except EOFError:
             raise util.Abort(_('response expected'))
     def status(self, *msg, **opts):

FWIW, I've tried to submit these patches to Mercurial upstream a few times but never managed to get them in, that's why we continue to patch Mercurial for our use.

Thanks Steve. When I download Git from http://git-scm.com/downloads, I only get a installer bundle. After install, /usr/local/git differs significantly from the bundled Git in Sourcetree (SourceTree.app/Contents/Resources/git_local). Do you have a different source of downloading Git?

Steve, where do you get the original Git from?

Steve, any update on this topic?

Sorry for the late reply, I've been on vacation for a couple of weeks. My process for embedding git is literally this (from my own notes to remind me how to do it in fact :)

  1. Download the official binary distribution and install
  2. Copy the contents of the installed /usr/local/git folder into git_local
  3. For size reasons, remove share/git-gui, share/gitk and share/gitweb, these are not needed

Therefore I can't understand how you'd conclude the binary download is different, except maybe for the things I trimmed out to make the embedded version a little smaller. I used to have a step which stripped the 'ppc' or 'ppc7400' elements from the fat binaries, because the git binary distro used to include PowerPC support as well as i386 and Apple don't let you distribute that any more, but I haven't had to do that for a while because Git stopped packaging ppc support a year or so ago.

Thanks for the update. From where do you download the official Git binaries?

Always from git-scm.com, which is why I'm confused. I don't even dig any further than the front page, just grab the latest binary from the front page link when periodically updating the embedded version.

Could the differences be caused by the digital signature of SourceTree? If so, how to remove this signature for testing purposes?

Ah, that's very likely - we were required to sign every binary inside the .app to comply with both the App Store and the GateKeeper requirements on 10.7+ otherwise OS X wouldn't consider them valid. I'm not sure how you remove a code signature - we used the usual 'codesign' tool but I can't see an option to strip the signature back off again. It must be possible though, since nothing is recompiled when you sign the code, it just tacks on a signature that OS X can check.

Suggest an answer

Log in or Sign up to answer
Community showcase
Published Oct 23, 2018 in Sourcetree

Tip from the team: configure your repos for hosting goodness!

Supported Platforms macOS Windows We recently introduced support for additional hosting services such as GitHub Enterprise, GitLab (Cloud, Community Edition, Enterprise Edition), and...

1,237 views 4 2
Read article

Atlassian User Groups

Connect with like-minded Atlassian users at free events near you!

Find a group

Connect with like-minded Atlassian users at free events near you!

Find my local user group

Unfortunately there are no AUG chapters near you at the moment.

Start an AUG

You're one step closer to meeting fellow Atlassian users at your local meet up. Learn more about AUGs

Groups near you