# HG changeset patch # User Mads Kiilerich # Date 2015-01-09 17:38:02 # Node ID 9d25bb84cf6ce4f09519c805454df54c8064c244 # Parent ddc17eaf0f1b8eef38e14d5f5f7431ad8a28497d largefiles: make linear update set unsure largefiles normal if unchanged 'hg update' would hash all 'unsure' largefiles before performing the merge. It would update the standins but not detect the very common case where the largefile never had been changed by the user but just had been marked with an invalid dirstate mtime to make sure any changes done by the user in the same second would be detected. The largefile would remain in that state and would have to be hashed again next time even though it still not had been changed. Sad trombone. Instead, for largefiles listed as 'unsure' or 'modified', after updating the standin with the actual hash, mark the largefile as normal if it turns out to not be modified relative to the revision in the parent revision. That will prevent it from being hashed again next time. diff --git a/hgext/largefiles/overrides.py b/hgext/largefiles/overrides.py --- a/hgext/largefiles/overrides.py +++ b/hgext/largefiles/overrides.py @@ -1295,8 +1295,21 @@ def mergeupdate(orig, repo, node, branch unsure, s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [], False, False, False) - for lfile in unsure + s.modified + s.added: + pctx = repo['.'] + for lfile in unsure + s.modified: + lfileabs = repo.wvfs.join(lfile) + if not os.path.exists(lfileabs): + continue + lfhash = lfutil.hashrepofile(repo, lfile) + standin = lfutil.standin(lfile) + lfutil.writestandin(repo, standin, lfhash, + lfutil.getexecutable(lfileabs)) + if (standin in pctx and + lfhash == lfutil.readstandin(repo, lfile, '.')): + lfdirstate.normal(lfile) + for lfile in s.added: lfutil.updatestandin(repo, lfutil.standin(lfile)) + lfdirstate.write() if linearmerge: # Only call updatelfiles on the standins that have changed diff --git a/tests/test-largefiles-update.t b/tests/test-largefiles-update.t --- a/tests/test-largefiles-update.t +++ b/tests/test-largefiles-update.t @@ -25,6 +25,39 @@ directory (and ".hg/largefiles/dirstate" $ hg commit -m '#2' created new head +Test that update also updates the lfdirstate of 'unsure' largefiles after +hashing them: + +The previous operations will usually have left us with largefiles with a mtime +within the same second as the dirstate was written. +The lfdirstate entries will thus have been written with an invalidated/unset +mtime to make sure further changes within the same second is detected. +We will however occasionally be "lucky" and get a tick between writing +largefiles and writing dirstate so we get valid lfdirstate timestamps. The +following verification is thus disabled but can be verified manually. + +#if false + $ hg debugdirstate --large --nodate + n 644 7 unset large1 + n 644 13 unset large2 +#endif + +Wait to make sure we get a tick so the mtime of the largefiles become valid. + + $ sleep 1 + +A linear merge will update standins before performing the actual merge. It will +do a lfdirstate status walk and find 'unset'/'unsure' files, hash them, and +update the corresponding standins. +Verify that it actually marks the clean files as clean in lfdirstate so +we don't have to hash them again next time we update. + + $ hg up + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ hg debugdirstate --large --nodate + n 644 7 set large1 + n 644 13 set large2 + Test that lfdirstate keeps track of last modification of largefiles and prevents unnecessary hashing of content - also after linear/noop update