diff --git a/zuul/merger.py b/zuul/merger.py index 2627b942fa..218f7f22f5 100644 --- a/zuul/merger.py +++ b/zuul/merger.py @@ -34,8 +34,6 @@ class Repo(object): self._initialized = False try: self._ensure_cloned() - # Pick up any tags or branch updates since we last ran: - self.update() except: self.log.exception("Unable to initialize repo for %s" % remote) @@ -60,16 +58,29 @@ class Repo(object): self._ensure_cloned() self.repo = git.Repo(self.local_path) + def reset(self): + self._ensure_cloned() + self.log.debug("Resetting repository %s" % self.local_path) + self.update() + origin = self.repo.remotes.origin + for ref in origin.refs: + if ref.remote_head == 'HEAD': + continue + self.repo.create_head(ref.remote_head, ref, force=True) + + # Reset to remote HEAD (usually origin/master) + self.repo.head.reference = origin.refs['HEAD'] + self.repo.head.reset(index=True, working_tree=True) + self.repo.git.clean('-x', '-f', '-d') + + def getBranchHead(self, branch): + return self.repo.heads[branch] + def checkout(self, ref): self._ensure_cloned() self.log.debug("Checking out %s" % ref) + self.repo.head.reference = ref self.repo.head.reset(index=True, working_tree=True) - self.repo.git.clean('-x', '-f', '-d') - if self.repo.re_hexsha_only.match(ref): - self.repo.git.checkout(ref) - else: - self.fetch(ref) - self.repo.git.checkout("FETCH_HEAD") def cherryPick(self, ref): self._ensure_cloned() @@ -94,15 +105,15 @@ class Repo(object): # data was fetched properly subsequent fetches don't seem to fail. # So try again if an AssertionError is caught. origin = self.repo.remotes.origin - self.log.debug("Fetching %s" % ref) try: origin.fetch(ref) except AssertionError: origin.fetch(ref) # If the repository is packed, and we fetch a change that is - # also entirely packed, the cache may be out of date. - # See the comment in update() and + # also entirely packed, the cache may be out of date for the + # same reason as reset() above. Avoid these problems by + # recreating the repo object. # https://bugs.launchpad.net/zuul/+bug/1078946 self.repo = git.Repo(self.local_path) @@ -171,18 +182,13 @@ class Merger(object): r.recreateRepoObject() return r - def updateRepo(self, project, ref=None): + def updateRepo(self, project): repo = self.getRepo(project) try: - if ref: - self.log.debug("Fetching ref %s for local repository %s" % - (ref, project)) - repo.fetch(ref) - else: - self.log.info("Updating local repository %s" % project) - repo.update() + self.log.info("Updating local repository %s", project) + repo.update() except: - self.log.exception("Unable to update %s" % project) + self.log.exception("Unable to update %s", project) def _mergeChange(self, change, ref, target_ref): repo = self.getRepo(change.project) @@ -237,8 +243,14 @@ class Merger(object): # Only current change to merge against tip of change.branch if len(sibling_items) == 1: repo = self.getRepo(item.change.project) + # we need to reset here in order to call getBranchHead + try: + repo.reset() + except: + self.log.exception("Unable to reset repo %s" % repo) + return False commit = self._mergeChange(item.change, - item.change.branch, + repo.getBranchHead(item.change.branch), target_ref=target_ref) # Sibling changes exist. Merge current change against newest sibling. elif (len(sibling_items) >= 2 and diff --git a/zuul/scheduler.py b/zuul/scheduler.py index 29c856e961..6a6c5d1ce1 100644 --- a/zuul/scheduler.py +++ b/zuul/scheduler.py @@ -563,14 +563,13 @@ class Scheduler(threading.Thread): return # Preprocessing for ref-update events - if event.ref: + if hasattr(event, 'refspec'): # Make sure the local git repo is up-to-date with the remote one. # We better have the new ref before enqueuing the changes. # This is done before enqueuing the changes to avoid calling an # update per pipeline accepting the change. - self.log.info("Fetching updated ref %s for %s" % - (event.ref, project)) - self.merger.updateRepo(project, event.ref) + self.log.info("Fetching references for %s" % project) + self.merger.updateRepo(project) for pipeline in self.layout.pipelines.values(): change = event.getChange(project,