59
51
If null (default), a time/random revision id is generated.
64
from bzrlib.osutils import local_time_offset, username
65
from bzrlib.branch import gen_file_id
66
from bzrlib.errors import BzrError, PointlessCommit
67
from bzrlib.revision import Revision, RevisionReference
68
from bzrlib.trace import mutter, note
69
from bzrlib.xml import pack_xml
74
# First walk over the working inventory; and both update that
75
# and also build a new revision inventory. The revision
76
# inventory needs to hold the text-id, sha1 and size of the
77
# actual file versions committed in the revision. (These are
78
# not present in the working inventory.) We also need to
79
# detect missing/deleted files, and remove them from the
82
work_tree = branch.working_tree()
83
work_inv = work_tree.inventory
84
basis = branch.basis_tree()
85
basis_inv = basis.inventory
88
# note('looking for changes...')
89
# print 'looking for changes...'
90
# disabled; should be done at a higher level
93
pending_merges = branch.pending_merges()
95
missing_ids, new_inv, any_changes = \
96
_gather_commit(branch,
103
if not (any_changes or allow_pointless or pending_merges):
104
raise PointlessCommit()
106
for file_id in missing_ids:
107
# Any files that have been deleted are now removed from the
108
# working inventory. Files that were not selected for commit
109
# are left as they were in the working inventory and ommitted
110
# from the revision inventory.
112
# have to do this later so we don't mess up the iterator.
113
# since parents may be removed before their children we
116
# FIXME: There's probably a better way to do this; perhaps
117
# the workingtree should know how to filter itbranch.
118
if work_inv.has_id(file_id):
119
del work_inv[file_id]
122
rev_id = _gen_revision_id(branch, time.time())
125
inv_tmp = tempfile.TemporaryFile()
126
pack_xml(new_inv, inv_tmp)
128
branch.inventory_store.add(inv_tmp, inv_id)
129
mutter('new inventory_id is {%s}' % inv_id)
131
# We could also just sha hash the inv_tmp file
132
# however, in the case that branch.inventory_store.add()
133
# ever actually does anything special
134
inv_sha1 = branch.get_inventory_sha1(inv_id)
136
branch._write_inventory(work_inv)
138
if timestamp == None:
139
timestamp = time.time()
141
if committer == None:
142
committer = username(branch)
145
timezone = local_time_offset()
147
mutter("building commit log message")
148
rev = Revision(timestamp=timestamp,
153
inventory_sha1=inv_sha1,
157
precursor_id = branch.last_patch()
159
precursor_sha1 = branch.get_revision_sha1(precursor_id)
160
rev.parents.append(RevisionReference(precursor_id, precursor_sha1))
161
for merge_rev in pending_merges:
162
rev.parents.append(RevisionReference(merge_rev))
164
rev_tmp = tempfile.TemporaryFile()
165
pack_xml(rev, rev_tmp)
167
branch.revision_store.add(rev_tmp, rev_id)
168
mutter("new revision_id is {%s}" % rev_id)
170
## XXX: Everything up to here can simply be orphaned if we abort
171
## the commit; it will leave junk files behind but that doesn't
174
## TODO: Read back the just-generated changeset, and make sure it
175
## applies and recreates the right state.
177
## TODO: Also calculate and store the inventory SHA1
178
mutter("committing patch r%d" % (branch.revno() + 1))
180
branch.append_revision(rev_id)
182
branch.set_pending_merges([])
185
# disabled; should go through logging
186
# note("commited r%d" % branch.revno())
187
# print ("commited r%d" % branch.revno())
194
def _gen_revision_id(branch, when):
195
"""Return new revision-id."""
196
from binascii import hexlify
197
from bzrlib.osutils import rand_bytes, compact_date, user_email
199
s = '%s-%s-' % (user_email(branch), compact_date(when))
200
s += hexlify(rand_bytes(8))
204
def _gather_commit(branch, work_tree, work_inv, basis_inv, specific_files,
206
"""Build inventory preparatory to commit.
208
Returns missing_ids, new_inv, any_changes.
210
This adds any changed files into the text store, and sets their
211
test-id, sha and size in the returned inventory appropriately.
214
Modified to hold a list of files that have been deleted from
215
the working directory; these should be removed from the
218
from bzrlib.inventory import Inventory
219
from bzrlib.osutils import isdir, isfile, sha_string, quotefn, \
54
import os, time, tempfile
56
from inventory import Inventory
57
from osutils import isdir, isfile, sha_string, quotefn, \
220
58
local_time_offset, username, kind_marker, is_inside_any
222
from bzrlib.branch import gen_file_id
223
from bzrlib.errors import BzrError
224
from bzrlib.revision import Revision
225
from bzrlib.trace import mutter, note
228
inv = Inventory(work_inv.root.file_id)
60
from branch import gen_file_id
61
from errors import BzrError
62
from revision import Revision
63
from trace import mutter, note
65
branch._need_writelock()
67
# First walk over the working inventory; and both update that
68
# and also build a new revision inventory. The revision
69
# inventory needs to hold the text-id, sha1 and size of the
70
# actual file versions committed in the revision. (These are
71
# not present in the working inventory.) We also need to
72
# detect missing/deleted files, and remove them from the
75
work_tree = branch.working_tree()
76
work_inv = work_tree.inventory
78
basis = branch.basis_tree()
79
basis_inv = basis.inventory
83
note('looking for changes...')
231
85
for path, entry in work_inv.iter_entries():
232
86
## TODO: Check that the file kind has not changed from the previous
233
87
## revision of this file (if any).
235
91
p = branch.abspath(path)
236
92
file_id = entry.file_id
237
93
mutter('commit prep file %s, id %r ' % (p, file_id))
239
95
if specific_files and not is_inside_any(specific_files, path):
240
mutter(' skipping file excluded from commit')
241
96
if basis_inv.has_id(file_id):
242
97
# carry over with previous state
243
98
inv.add(basis_inv[file_id].copy())
289
139
content = file(p, 'rb').read()
291
# calculate the sha again, just in case the file contents
292
# changed since we updated the cache
293
141
entry.text_sha1 = sha_string(content)
294
142
entry.text_size = len(content)
296
144
entry.text_id = gen_file_id(entry.name)
297
145
branch.text_store.add(content, entry.text_id)
298
146
mutter(' stored with text_id {%s}' % entry.text_id)
301
marked = path + kind_marker(entry.kind)
303
print 'added', marked
305
elif old_ie == entry:
307
elif (old_ie.name == entry.name
308
and old_ie.parent_id == entry.parent_id):
309
print 'modified', marked
312
print 'renamed', marked
315
return missing_ids, inv, any_changes
149
print('added %s' % path)
150
elif (old_ie.name == entry.name
151
and old_ie.parent_id == entry.parent_id):
152
print('modified %s' % path)
154
print('renamed %s' % path)
157
for file_id in missing_ids:
158
# Any files that have been deleted are now removed from the
159
# working inventory. Files that were not selected for commit
160
# are left as they were in the working inventory and ommitted
161
# from the revision inventory.
163
# have to do this later so we don't mess up the iterator.
164
# since parents may be removed before their children we
167
# FIXME: There's probably a better way to do this; perhaps
168
# the workingtree should know how to filter itbranch.
169
if work_inv.has_id(file_id):
170
del work_inv[file_id]
174
rev_id = _gen_revision_id(time.time())
177
inv_tmp = tempfile.TemporaryFile()
178
inv.write_xml(inv_tmp)
180
branch.inventory_store.add(inv_tmp, inv_id)
181
mutter('new inventory_id is {%s}' % inv_id)
183
branch._write_inventory(work_inv)
185
if timestamp == None:
186
timestamp = time.time()
188
if committer == None:
189
committer = username()
192
timezone = local_time_offset()
194
mutter("building commit log message")
195
rev = Revision(timestamp=timestamp,
198
precursor = branch.last_patch(),
203
rev_tmp = tempfile.TemporaryFile()
204
rev.write_xml(rev_tmp)
206
branch.revision_store.add(rev_tmp, rev_id)
207
mutter("new revision_id is {%s}" % rev_id)
209
## XXX: Everything up to here can simply be orphaned if we abort
210
## the commit; it will leave junk files behind but that doesn't
213
## TODO: Read back the just-generated changeset, and make sure it
214
## applies and recreates the right state.
216
## TODO: Also calculate and store the inventory SHA1
217
mutter("committing patch r%d" % (branch.revno() + 1))
219
branch.append_revision(rev_id)
222
note("commited r%d" % branch.revno())
226
def _gen_revision_id(when):
227
"""Return new revision-id."""
228
from binascii import hexlify
229
from osutils import rand_bytes, compact_date, user_email
231
s = '%s-%s-' % (user_email(), compact_date(when))
232
s += hexlify(rand_bytes(8))