File: splice_repos.py

package info (click to toggle)
git-filter-repo 2.47.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,280 kB
  • sloc: sh: 4,887; python: 4,856; makefile: 114
file content (87 lines) | stat: -rwxr-xr-x 2,754 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#!/usr/bin/env python3

"""
Please see the
  ***** API BACKWARD COMPATIBILITY CAVEAT *****
near the top of git-filter-repo.

Also, note that splicing repos may need some special care as fast-export
only shows the files that changed relative to the first parent, so there
may be gotchas if you are to splice near merge commits; this example does
not try to handle any such special cases.
"""

import re
import sys
import git_filter_repo as fr

class InterleaveRepositories:
  def __init__(self, repo1, repo2, output_dir):
    self.repo1 = repo1
    self.repo2 = repo2
    self.output_dir = output_dir

    self.commit_map = {}
    self.last_commit = None

  def skip_reset(self, reset, metadata):
    reset.skip()

  def hold_commit(self, commit, metadata):
    commit.skip(new_id = commit.id)
    letter = re.match(b'Commit (.)', commit.message).group(1)
    self.commit_map[letter] = commit

  def weave_commit(self, commit, metadata):
    letter = re.match(b'Commit (.)', commit.message).group(1)
    prev_letter = bytes([ord(letter)-1])

    # Splice in any extra commits needed
    if prev_letter in self.commit_map:
      new_commit = self.commit_map[prev_letter]
      new_commit.dumped = 0
      new_commit.parents = [self.last_commit] if self.last_commit else []
      # direct_insertion=True to avoid weave_commit being called recursively
      # on the same commit
      self.out.insert(new_commit, direct_insertion = True)
      commit.parents = [new_commit.id]

    # Dump our commit now
    self.out.insert(commit, direct_insertion = True)

    # Make sure that commits that depended on new_commit.id will now depend
    # on commit.id
    if prev_letter in self.commit_map:
      self.last_commit = commit.id
      fr.record_id_rename(new_commit.id, commit.id)

  def run(self):
    blob = fr.Blob(b'public gpg key contents')
    tag = fr.Tag(b'gpg-pubkey', blob.id,
                 b'Ima Tagger', b'ima@tagg.er', b'1136199845 +0300',
                 b'Very important explanation and stuff')

    args = fr.FilteringOptions.parse_args(['--target', self.output_dir])
    out = fr.RepoFilter(args)
    out.importer_only()
    self.out = out

    i1args = fr.FilteringOptions.parse_args(['--source', self.repo1])
    i1 = fr.RepoFilter(i1args,
                       reset_callback  = self.skip_reset,
                       commit_callback = self.hold_commit)
    i1.set_output(out)
    i1.run()

    i2args = fr.FilteringOptions.parse_args(['--source', self.repo2])
    i2 = fr.RepoFilter(i2args,
                       commit_callback = self.weave_commit)
    i2.set_output(out)
    i2.run()

    out.insert(blob)
    out.insert(tag)
    out.finish()

splicer = InterleaveRepositories(sys.argv[1], sys.argv[2], sys.argv[3])
splicer.run()