or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cli.mdclients.mdconfiguration.mddiff-merge.mdindex-management.mdindex.mdobject-storage.mdobjects.mdpack-files.mdporcelain.mdreferences.mdrepository.md

diff-merge.mddocs/

0

# Diff and Merge

1

2

Comprehensive diff generation and merge algorithms for comparing trees, detecting changes, and resolving conflicts with rename detection.

3

4

## Capabilities

5

6

### Tree Comparison Functions

7

8

Functions for comparing Git trees and detecting changes between different states.

9

10

```python { .api }

11

def tree_changes(object_store, old_tree: bytes, new_tree: bytes,

12

want_unchanged: bool = False, rename_detector=None,

13

change_type_same: bool = False) -> Iterator[TreeChange]:

14

"""

15

Find changes between two trees.

16

17

Args:

18

object_store: Object store for loading trees

19

old_tree: SHA of old tree (None for empty)

20

new_tree: SHA of new tree (None for empty)

21

want_unchanged: Include unchanged files

22

rename_detector: RenameDetector instance

23

change_type_same: Include type changes as same

24

25

Yields:

26

TreeChange objects describing changes

27

"""

28

29

def tree_changes_for_merge(object_store, tree1: bytes, tree2: bytes,

30

base_tree: bytes) -> Iterator[TreeChange]:

31

"""

32

Find changes for three-way merge.

33

34

Args:

35

object_store: Object store for loading trees

36

tree1: SHA of first tree

37

tree2: SHA of second tree

38

base_tree: SHA of common base tree

39

40

Yields:

41

TreeChange objects for merge conflicts

42

"""

43

44

def walk_trees(object_store, tree1_id: bytes, tree2_id: bytes,

45

prune_identical: bool = True) -> Iterator[Tuple]:

46

"""

47

Walk two trees simultaneously.

48

49

Args:

50

object_store: Object store for loading trees

51

tree1_id: SHA of first tree

52

tree2_id: SHA of second tree

53

prune_identical: Skip identical subtrees

54

55

Yields:

56

Tuples of (path, mode1, sha1, mode2, sha2)

57

"""

58

```

59

60

### Diff Generation Functions

61

62

Functions for generating unified diff output from tree and working directory changes.

63

64

```python { .api }

65

def diff_tree_to_tree(object_store, old_tree: bytes, new_tree: bytes,

66

outf=None) -> bytes:

67

"""

68

Generate unified diff between two trees.

69

70

Args:

71

object_store: Object store for loading objects

72

old_tree: SHA of old tree

73

new_tree: SHA of new tree

74

outf: Optional output file

75

76

Returns:

77

Diff as bytes if outf is None

78

"""

79

80

def diff_index_to_tree(object_store, index_path: str, tree: bytes,

81

outf=None) -> bytes:

82

"""

83

Generate diff between index and tree.

84

85

Args:

86

object_store: Object store for loading objects

87

index_path: Path to index file

88

tree: SHA of tree to compare against

89

outf: Optional output file

90

91

Returns:

92

Diff as bytes if outf is None

93

"""

94

95

def diff_working_tree_to_tree(object_store, tree: bytes, root_path: str = ".",

96

outf=None) -> bytes:

97

"""

98

Generate diff between working tree and Git tree.

99

100

Args:

101

object_store: Object store for loading objects

102

tree: SHA of tree to compare against

103

root_path: Root path of working tree

104

outf: Optional output file

105

106

Returns:

107

Diff as bytes if outf is None

108

"""

109

110

def diff_working_tree_to_index(object_store, index_path: str,

111

root_path: str = ".", outf=None) -> bytes:

112

"""

113

Generate diff between working tree and index.

114

115

Args:

116

object_store: Object store for loading objects

117

index_path: Path to index file

118

root_path: Root path of working tree

119

outf: Optional output file

120

121

Returns:

122

Diff as bytes if outf is None

123

"""

124

```

125

126

### Rename Detection

127

128

Classes and functions for detecting file renames and copies in diffs.

129

130

```python { .api }

131

class RenameDetector:

132

"""Detect renames and copies in tree changes."""

133

134

def __init__(self, object_store, rename_threshold: int = 60,

135

copy_threshold: int = 60, max_files: int = None,

136

big_file_threshold: int = None): ...

137

138

def changes_with_renames(self, changes: List[TreeChange]) -> List[TreeChange]:

139

"""

140

Process changes to detect renames and copies.

141

142

Args:

143

changes: List of TreeChange objects

144

145

Returns:

146

List of TreeChange objects with renames detected

147

"""

148

149

def find_renames(self, added_files: List[TreeChange],

150

deleted_files: List[TreeChange]) -> List[Tuple[TreeChange, TreeChange]]:

151

"""

152

Find renames between added and deleted files.

153

154

Args:

155

added_files: List of added files

156

deleted_files: List of deleted files

157

158

Returns:

159

List of (deleted, added) pairs that are renames

160

"""

161

```

162

163

### Change Representation

164

165

Classes representing different types of changes between trees.

166

167

```python { .api }

168

class TreeChange:

169

"""Represents a change between two trees."""

170

171

type: str # 'add', 'delete', 'modify', 'rename', 'copy', 'unchanged'

172

old: TreeEntry # (name, mode, sha) or None

173

new: TreeEntry # (name, mode, sha) or None

174

175

def __init__(self, type: str, old: TreeEntry = None, new: TreeEntry = None): ...

176

177

@property

178

def is_rename(self) -> bool:

179

"""True if this change represents a rename."""

180

181

@property

182

def is_copy(self) -> bool:

183

"""True if this change represents a copy."""

184

185

@property

186

def is_modify(self) -> bool:

187

"""True if this change represents a modification."""

188

```

189

190

### Colorized Output

191

192

Classes for generating colorized diff output.

193

194

```python { .api }

195

class ColorizedDiffStream:

196

"""Stream wrapper that adds ANSI color codes to diff output."""

197

198

def __init__(self, f, color_config=None): ...

199

200

def write(self, data: bytes) -> None:

201

"""Write colorized diff data to underlying stream."""

202

```

203

204

## Usage Examples

205

206

### Basic Tree Comparison

207

208

```python

209

from dulwich.repo import Repo

210

from dulwich.diff_tree import tree_changes

211

212

# Open repository

213

repo = Repo('.')

214

215

# Get two commits to compare

216

commit1 = repo[b'HEAD~1']

217

commit2 = repo[b'HEAD']

218

219

# Find changes between the commits

220

changes = tree_changes(repo.object_store, commit1.tree, commit2.tree)

221

222

for change in changes:

223

if change.type == 'add':

224

print(f"Added: {change.new.path}")

225

elif change.type == 'delete':

226

print(f"Deleted: {change.old.path}")

227

elif change.type == 'modify':

228

print(f"Modified: {change.new.path}")

229

```

230

231

### Generating Unified Diffs

232

233

```python

234

from dulwich.repo import Repo

235

from dulwich.diff import diff_tree_to_tree

236

import sys

237

238

repo = Repo('.')

239

240

# Compare two commits

241

commit1 = repo[b'HEAD~1']

242

commit2 = repo[b'HEAD']

243

244

# Generate unified diff

245

diff_output = diff_tree_to_tree(repo.object_store, commit1.tree, commit2.tree)

246

247

# Write to stdout

248

sys.stdout.buffer.write(diff_output)

249

```

250

251

### Rename Detection

252

253

```python

254

from dulwich.repo import Repo

255

from dulwich.diff_tree import tree_changes, RenameDetector

256

257

repo = Repo('.')

258

259

# Create rename detector

260

rename_detector = RenameDetector(repo.object_store, rename_threshold=50)

261

262

# Get changes between commits

263

commit1 = repo[b'HEAD~1']

264

commit2 = repo[b'HEAD']

265

266

changes = list(tree_changes(repo.object_store, commit1.tree, commit2.tree))

267

268

# Detect renames

269

changes_with_renames = rename_detector.changes_with_renames(changes)

270

271

for change in changes_with_renames:

272

if change.is_rename:

273

print(f"Renamed: {change.old.path} -> {change.new.path}")

274

elif change.is_copy:

275

print(f"Copied: {change.old.path} -> {change.new.path}")

276

```

277

278

### Working Tree Diffs

279

280

```python

281

from dulwich.repo import Repo

282

from dulwich.diff import diff_working_tree_to_tree

283

284

repo = Repo('.')

285

286

# Compare working tree to HEAD

287

head_tree = repo[repo.head()].tree

288

diff_output = diff_working_tree_to_tree(repo.object_store, head_tree)

289

290

print(diff_output.decode('utf-8'))

291

```

292

293

### Colorized Diff Output

294

295

```python

296

from dulwich.repo import Repo

297

from dulwich.diff import diff_tree_to_tree, ColorizedDiffStream

298

import sys

299

300

repo = Repo('.')

301

302

# Create colorized output stream

303

colorized_stream = ColorizedDiffStream(sys.stdout.buffer)

304

305

# Generate colorized diff

306

commit1 = repo[b'HEAD~1']

307

commit2 = repo[b'HEAD']

308

309

diff_tree_to_tree(repo.object_store, commit1.tree, commit2.tree,

310

outf=colorized_stream)

311

```