[PATCH v2] git: add references for Git pull request heads

Andrew Shadura andrew at shadura.me
Sat Apr 15 12:11:52 UTC 2017


# HG changeset patch
# User Andrew Shadura <andrew at shadura.me>
# Date 1492258239 -7200
#      Sat Apr 15 14:10:39 2017 +0200
# Node ID 977c0cfec8c00806d4331ebf402ce492657cf34a
# Parent  a1f8bf0428c5a3123da9c3ba2dbd8ada50be0b0e
git: add references for Git pull request heads

When a pull request is created, stick a reference to it in the refs/pull
namespace, similarly to what GitHub does, and remove it when the pull
request is deleted. That reference guarantees the commits stay around
and don't get garbage-collected when a PR is rebased or revised.
Also, that makes it possible to access head of the historis pull
requests using Git by fetching a ref from the source repository.

Unlike GitHub though, we don't put the ref into the destination repository
and don't copy commits there to prevent undesired repository growth.
Kallithea uses global pull request identifiers, so there should not be
any confusion as to what pull request the ref corresponds to.
We may later provide a shim to redirect users to the source repository
if that deems needed.

diff --git a/kallithea/model/pull_request.py b/kallithea/model/pull_request.py
--- a/kallithea/model/pull_request.py
+++ b/kallithea/model/pull_request.py
@@ -39,8 +39,7 @@ from kallithea.lib import helpers as h
 from kallithea.model.db import PullRequest, PullRequestReviewer, Notification, \
     ChangesetStatus, User
 from kallithea.model.notification import NotificationModel
-from kallithea.lib.utils2 import extract_mentioned_users, safe_unicode
-
+from kallithea.lib.utils2 import extract_mentioned_users, safe_str, safe_unicode
 
 log = logging.getLogger(__name__)
 
@@ -139,6 +138,12 @@ class PullRequestModel(object):
     def delete(self, pull_request):
         pull_request = PullRequest.guess_instance(pull_request)
         Session().delete(pull_request)
+	if pull_request.org_repo.scm_instance.alias == 'git':
+	    # remove a ref under refs/pull/ so that commits can be garbage-collected
+	    try:
+		del pull_request.org_repo.scm_instance._repo["refs/pull/%d/head" % pull_request.pull_request_id]
+	    except KeyError:
+		pass
 
     def close_pull_request(self, pull_request):
         pull_request = PullRequest.guess_instance(pull_request)
@@ -228,6 +233,7 @@ class CreatePullRequestAction(object):
         self.org_repo = org_repo
         self.other_repo = other_repo
         self.org_ref = org_ref
+        self.org_rev = org_rev
         self.other_ref = other_ref
         self.title = title
         self.description = description
@@ -252,6 +258,10 @@ class CreatePullRequestAction(object):
         Session().add(pr)
         Session().flush() # make database assign pull_request_id
 
+        if self.org_repo.scm_instance.alias == 'git':
+            # create a ref under refs/pull/ so that commits don't get garbage-collected
+            self.org_repo.scm_instance._repo["refs/pull/%d/head" % pr.pull_request_id] = safe_str(self.org_rev)
+
         #reset state to under-review
         from kallithea.model.changeset_status import ChangesetStatusModel
         from kallithea.model.comment import ChangesetCommentsModel


More information about the kallithea-general mailing list