changeset 6602:2cf6d49b6073

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 historic 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.
author Andrew Shadura <andrew@shadura.me>
date Sat, 15 Apr 2017 14:10:39 +0200
parents 6f6ee1cfe2d6
children fd9b2d83d52b
files kallithea/model/pull_request.py
diffstat 1 files changed, 12 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/kallithea/model/pull_request.py	Wed May 03 03:41:11 2017 +0200
+++ b/kallithea/model/pull_request.py	Sat Apr 15 14:10:39 2017 +0200
@@ -39,7 +39,7 @@
 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 +139,12 @@
     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 +234,7 @@
         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 +259,10 @@
         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