681 return actions |
682 return actions |
682 |
683 |
683 def recordactions(self): |
684 def recordactions(self): |
684 """record remove/add/get actions in the dirstate""" |
685 """record remove/add/get actions in the dirstate""" |
685 branchmerge = self._repo.dirstate.p2() != nullid |
686 branchmerge = self._repo.dirstate.p2() != nullid |
686 recordupdates(self._repo, self.actions(), branchmerge) |
687 recordupdates(self._repo, self.actions(), branchmerge, None) |
687 |
688 |
688 def queueremove(self, f): |
689 def queueremove(self, f): |
689 """queues a file to be removed from the dirstate |
690 """queues a file to be removed from the dirstate |
690 |
691 |
691 Meant for use by custom merge drivers.""" |
692 Meant for use by custom merge drivers.""" |
1462 # cwd was removed in the course of removing files; print a helpful |
1463 # cwd was removed in the course of removing files; print a helpful |
1463 # warning. |
1464 # warning. |
1464 repo.ui.warn(_("current directory was removed\n" |
1465 repo.ui.warn(_("current directory was removed\n" |
1465 "(consider changing to repo root: %s)\n") % repo.root) |
1466 "(consider changing to repo root: %s)\n") % repo.root) |
1466 |
1467 |
1467 def batchget(repo, mctx, wctx, actions): |
1468 def batchget(repo, mctx, wctx, wantfiledata, actions): |
1468 """apply gets to the working directory |
1469 """apply gets to the working directory |
1469 |
1470 |
1470 mctx is the context to get from |
1471 mctx is the context to get from |
1471 |
1472 |
1472 yields tuples for progress updates |
1473 Yields arbitrarily many (False, tuple) for progress updates, followed by |
|
1474 exactly one (True, filedata). When wantfiledata is false, filedata is an |
|
1475 empty list. When wantfiledata is true, filedata[i] is a triple (mode, size, |
|
1476 mtime) of the file written for action[i]. |
1473 """ |
1477 """ |
|
1478 filedata = [] |
1474 verbose = repo.ui.verbose |
1479 verbose = repo.ui.verbose |
1475 fctx = mctx.filectx |
1480 fctx = mctx.filectx |
1476 ui = repo.ui |
1481 ui = repo.ui |
1477 i = 0 |
1482 i = 0 |
1478 with repo.wvfs.backgroundclosing(ui, expectedcount=len(actions)): |
1483 with repo.wvfs.backgroundclosing(ui, expectedcount=len(actions)): |
1492 conflicting = p |
1497 conflicting = p |
1493 break |
1498 break |
1494 if repo.wvfs.lexists(conflicting): |
1499 if repo.wvfs.lexists(conflicting): |
1495 orig = scmutil.backuppath(ui, repo, conflicting) |
1500 orig = scmutil.backuppath(ui, repo, conflicting) |
1496 util.rename(repo.wjoin(conflicting), orig) |
1501 util.rename(repo.wjoin(conflicting), orig) |
1497 wctx[f].clearunknown() |
1502 wfctx = wctx[f] |
|
1503 wfctx.clearunknown() |
1498 atomictemp = ui.configbool("experimental", "update.atomic-file") |
1504 atomictemp = ui.configbool("experimental", "update.atomic-file") |
1499 wctx[f].write(fctx(f).data(), flags, backgroundclose=True, |
1505 size = wfctx.write(fctx(f).data(), flags, |
1500 atomictemp=atomictemp) |
1506 backgroundclose=True, |
|
1507 atomictemp=atomictemp) |
|
1508 if wantfiledata: |
|
1509 s = wfctx.lstat() |
|
1510 mode = s.st_mode |
|
1511 mtime = s[stat.ST_MTIME] |
|
1512 filedata.append((mode, size, mtime)) # for dirstate.normal |
1501 if i == 100: |
1513 if i == 100: |
1502 yield i, f |
1514 yield False, (i, f) |
1503 i = 0 |
1515 i = 0 |
1504 i += 1 |
1516 i += 1 |
1505 if i > 0: |
1517 if i > 0: |
1506 yield i, f |
1518 yield False, (i, f) |
|
1519 yield True, filedata |
1507 |
1520 |
1508 def _prefetchfiles(repo, ctx, actions): |
1521 def _prefetchfiles(repo, ctx, actions): |
1509 """Invoke ``scmutil.prefetchfiles()`` for the files relevant to the dict |
1522 """Invoke ``scmutil.prefetchfiles()`` for the files relevant to the dict |
1510 of merge actions. ``ctx`` is the context being merged in.""" |
1523 of merge actions. ``ctx`` is the context being merged in.""" |
1511 |
1524 |
1548 ACTION_EXEC, |
1561 ACTION_EXEC, |
1549 ACTION_KEEP, |
1562 ACTION_KEEP, |
1550 ACTION_PATH_CONFLICT, |
1563 ACTION_PATH_CONFLICT, |
1551 ACTION_PATH_CONFLICT_RESOLVE)) |
1564 ACTION_PATH_CONFLICT_RESOLVE)) |
1552 |
1565 |
1553 def applyupdates(repo, actions, wctx, mctx, overwrite, labels=None): |
1566 def applyupdates(repo, actions, wctx, mctx, overwrite, wantfiledata, |
|
1567 labels=None): |
1554 """apply the merge action list to the working directory |
1568 """apply the merge action list to the working directory |
1555 |
1569 |
1556 wctx is the working copy context |
1570 wctx is the working copy context |
1557 mctx is the context to be merged into the working copy |
1571 mctx is the context to be merged into the working copy |
1558 |
1572 |
1559 Return a tuple of counts (updated, merged, removed, unresolved) that |
1573 Return a tuple of (counts, filedata), where counts is a tuple |
1560 describes how many files were affected by the update. |
1574 (updated, merged, removed, unresolved) that describes how many |
|
1575 files were affected by the update, and filedata is as described in |
|
1576 batchget. |
1561 """ |
1577 """ |
1562 |
1578 |
1563 _prefetchfiles(repo, mctx, actions) |
1579 _prefetchfiles(repo, mctx, actions) |
1564 |
1580 |
1565 updated, merged, removed = 0, 0, 0 |
1581 updated, merged, removed = 0, 0, 0 |
1647 progress.increment(item=f) |
1663 progress.increment(item=f) |
1648 |
1664 |
1649 # get in parallel. |
1665 # get in parallel. |
1650 threadsafe = repo.ui.configbool('experimental', |
1666 threadsafe = repo.ui.configbool('experimental', |
1651 'worker.wdir-get-thread-safe') |
1667 'worker.wdir-get-thread-safe') |
1652 prog = worker.worker(repo.ui, cost, batchget, (repo, mctx, wctx), |
1668 prog = worker.worker(repo.ui, cost, batchget, |
|
1669 (repo, mctx, wctx, wantfiledata), |
1653 actions[ACTION_GET], |
1670 actions[ACTION_GET], |
1654 threadsafe=threadsafe) |
1671 threadsafe=threadsafe, |
1655 for i, item in prog: |
1672 hasretval=True) |
1656 progress.increment(step=i, item=item) |
1673 getfiledata = [] |
|
1674 for final, res in prog: |
|
1675 if final: |
|
1676 getfiledata = res |
|
1677 else: |
|
1678 i, item = res |
|
1679 progress.increment(step=i, item=item) |
1657 updated = len(actions[ACTION_GET]) |
1680 updated = len(actions[ACTION_GET]) |
1658 |
1681 |
1659 if [a for a in actions[ACTION_GET] if a[0] == '.hgsubstate']: |
1682 if [a for a in actions[ACTION_GET] if a[0] == '.hgsubstate']: |
1660 subrepoutil.submerge(repo, wctx, mctx, wctx, overwrite, labels) |
1683 subrepoutil.submerge(repo, wctx, mctx, wctx, overwrite, labels) |
1661 |
1684 |
1776 extraactions = ms.actions() |
1799 extraactions = ms.actions() |
1777 if extraactions: |
1800 if extraactions: |
1778 mfiles = set(a[0] for a in actions[ACTION_MERGE]) |
1801 mfiles = set(a[0] for a in actions[ACTION_MERGE]) |
1779 for k, acts in extraactions.iteritems(): |
1802 for k, acts in extraactions.iteritems(): |
1780 actions[k].extend(acts) |
1803 actions[k].extend(acts) |
|
1804 if k == ACTION_GET and wantfiledata: |
|
1805 # no filedata until mergestate is updated to provide it |
|
1806 getfiledata.extend([None] * len(acts)) |
1781 # Remove these files from actions[ACTION_MERGE] as well. This is |
1807 # Remove these files from actions[ACTION_MERGE] as well. This is |
1782 # important because in recordupdates, files in actions[ACTION_MERGE] |
1808 # important because in recordupdates, files in actions[ACTION_MERGE] |
1783 # are processed after files in other actions, and the merge driver |
1809 # are processed after files in other actions, and the merge driver |
1784 # might add files to those actions via extraactions above. This can |
1810 # might add files to those actions via extraactions above. This can |
1785 # lead to a file being recorded twice, with poor results. This is |
1811 # lead to a file being recorded twice, with poor results. This is |
1798 |
1824 |
1799 actions[ACTION_MERGE] = [a for a in actions[ACTION_MERGE] |
1825 actions[ACTION_MERGE] = [a for a in actions[ACTION_MERGE] |
1800 if a[0] in mfiles] |
1826 if a[0] in mfiles] |
1801 |
1827 |
1802 progress.complete() |
1828 progress.complete() |
1803 return updateresult(updated, merged, removed, unresolved) |
1829 assert len(getfiledata) == (len(actions[ACTION_GET]) if wantfiledata else 0) |
1804 |
1830 return updateresult(updated, merged, removed, unresolved), getfiledata |
1805 def recordupdates(repo, actions, branchmerge): |
1831 |
|
1832 def recordupdates(repo, actions, branchmerge, getfiledata): |
1806 "record merge actions to the dirstate" |
1833 "record merge actions to the dirstate" |
1807 # remove (must come first) |
1834 # remove (must come first) |
1808 for f, args, msg in actions.get(ACTION_REMOVE, []): |
1835 for f, args, msg in actions.get(ACTION_REMOVE, []): |
1809 if branchmerge: |
1836 if branchmerge: |
1810 repo.dirstate.remove(f) |
1837 repo.dirstate.remove(f) |
1844 # keep |
1871 # keep |
1845 for f, args, msg in actions.get(ACTION_KEEP, []): |
1872 for f, args, msg in actions.get(ACTION_KEEP, []): |
1846 pass |
1873 pass |
1847 |
1874 |
1848 # get |
1875 # get |
1849 for f, args, msg in actions.get(ACTION_GET, []): |
1876 for i, (f, args, msg) in enumerate(actions.get(ACTION_GET, [])): |
1850 if branchmerge: |
1877 if branchmerge: |
1851 repo.dirstate.otherparent(f) |
1878 repo.dirstate.otherparent(f) |
1852 else: |
1879 else: |
1853 repo.dirstate.normal(f) |
1880 parentfiledata = getfiledata[i] if getfiledata else None |
|
1881 repo.dirstate.normal(f, parentfiledata=parentfiledata) |
1854 |
1882 |
1855 # merge |
1883 # merge |
1856 for f, args, msg in actions.get(ACTION_MERGE, []): |
1884 for f, args, msg in actions.get(ACTION_MERGE, []): |
1857 f1, f2, fa, move, anc = args |
1885 f1, f2, fa, move, anc = args |
1858 if branchmerge: |
1886 if branchmerge: |
2164 repo.ui.warn( |
2192 repo.ui.warn( |
2165 _('(warning: large working directory being used without ' |
2193 _('(warning: large working directory being used without ' |
2166 'fsmonitor enabled; enable fsmonitor to improve performance; ' |
2194 'fsmonitor enabled; enable fsmonitor to improve performance; ' |
2167 'see "hg help -e fsmonitor")\n')) |
2195 'see "hg help -e fsmonitor")\n')) |
2168 |
2196 |
2169 stats = applyupdates(repo, actions, wc, p2, overwrite, labels=labels) |
2197 updatedirstate = not partial and not wc.isinmemory() |
2170 |
2198 wantfiledata = updatedirstate and not branchmerge |
2171 if not partial and not wc.isinmemory(): |
2199 stats, getfiledata = applyupdates(repo, actions, wc, p2, overwrite, |
|
2200 wantfiledata, labels=labels) |
|
2201 |
|
2202 if updatedirstate: |
2172 with repo.dirstate.parentchange(): |
2203 with repo.dirstate.parentchange(): |
2173 repo.setparents(fp1, fp2) |
2204 repo.setparents(fp1, fp2) |
2174 recordupdates(repo, actions, branchmerge) |
2205 recordupdates(repo, actions, branchmerge, getfiledata) |
2175 # update completed, clear state |
2206 # update completed, clear state |
2176 util.unlink(repo.vfs.join('updatestate')) |
2207 util.unlink(repo.vfs.join('updatestate')) |
2177 |
2208 |
2178 if not branchmerge: |
2209 if not branchmerge: |
2179 repo.dirstate.setbranch(p2.branch()) |
2210 repo.dirstate.setbranch(p2.branch()) |