Module: Amp::Repositories::Updatable

Includes:
Amp::RevlogSupport::Node
Included in:
LocalRepository
Defined in:
lib/amp/repository/updatable.rb

Overview

This module contains all the code that makes a repository able to update its working directory.

Constant Summary

Constants included from Amp::RevlogSupport::Node

Amp::RevlogSupport::Node::NULL_ID, Amp::RevlogSupport::Node::NULL_REV

Instance Method Summary collapse

Methods included from Amp::RevlogSupport::Node

#short

Instance Method Details

#clean(node) ⇒ Object

Updates the repository to the given node, clobbering (removing) changes along the way. This has the effect of turning the working directory into a pristine copy of the requested changeset. Really just a nice way of skipping some arguments for the caller.

Parameters:

  • node (String)

    the requested node



129
130
131
# File 'lib/amp/repository/updatable.rb', line 129

def clean(node)
  update node, false, true, nil
end

#merge(node, force = false) ⇒ Object

Merge two heads



118
119
120
# File 'lib/amp/repository/updatable.rb', line 118

def merge(node, force=false)
  update node, true, force, false
end

#update(node = nil, branch_merge = false, force = false, partial = nil) ⇒ Array<Integer>

TODO:

add lock

Updates the repository to the given node. One of the major operations on a repository. This will update the working directory to the given node.

Parameters:

  • node (String, Integer) (defaults to: nil)

    the revision to which we are updating the repository. Can be either nil, a node ID, or an integer. If it is nil, it will update to the latest revision.

  • branch_merge (Boolean) (defaults to: false)

    whether to merge between branches

  • force (Boolean) (defaults to: false)

    whether to force branch merging or file overwriting

  • partial (Proc, #call) (defaults to: nil)

    a function to filter file lists (dirstate not updated if this is passed)

Returns:

  • (Array<Integer>)

    a set of statistics about the update. In the form:

    updated, merged, removed, unresolved

    where each entry is the # of files in that category.



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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/amp/repository/updatable.rb', line 24

def update(node=nil, branch_merge=false, force=false, partial=nil)
  # debugger
  self.status(:node_1 => self.dirstate.parents.first, :node_2 => nil)
  working_changeset = self[nil]
  # tip of current branch
  node ||= branch_tags[working_changeset.branch]
  node = self.lookup("tip") if node.nil? && working_changeset.branch == "default"
  if node.nil?
    raise abort("branch #{working_changeset.branch} not found")
  end
  
  overwrite = force && !branch_merge
  parent_list = working_changeset.parents
  parent1, parent2 = parent_list.first, self[node]
  parent_ancestor = parent1.ancestor(parent2)
  
  fp1, fp2, xp1, xp2 = parent1.node, parent2.node, parent1.to_s, parent2.to_s
  fast_forward = false
  
  ## In this section, we make sure that we can actually do an update.
  ## No use starting an udpate if we can't finish!
  
  if !overwrite && parent_list.size > 1
    raise abort("outstanding uncommitted merges")
  end
  
  if branch_merge
    if parent_ancestor == parent2
      raise abort("can't merge with ancestor")
    elsif parent_ancestor == parent1
      if parent1.branch != parent2.branch
        fast_forward = true
      else
        raise abort("nothing to merge (use 'hg update' or check"+
                             " 'hg heads')")
      end
    end
    if !force && (working_changeset.files.any? || working_changeset.deleted.any?)
      raise abort("oustanding uncommitted changes")
    end
  elsif !overwrite
    if parent_ancestor == parent1 || parent_ancestor == parent2
      # do nothing
    elsif parent1.branch == parent2.branch
      if working_changeset.files.any? || working_changeset.deleted.any?
        raise abort("crosses branches (use 'hg merge' or "+
                             "'hg update -C' to discard changes)")
      end
      raise abort("crosses branches (use 'hg merge' or 'hg update -C')")
    elsif working_changeset.files.any? || working_changeset.deleted.any?
      raise abort("crosses named branches (use 'hg update -C'"+
                           " to discard changes)")
    else
      overwrite = true
    end
  end
  
  ## Alright, now let's figure out exactly what we have to do to make this update.
  ## Shall we?
  
  actions = []
  check_unknown(working_changeset, parent2) if force
  check_collision(parent2) if false # case-sensitive file-system? seriously?
  
  actions += forget_removed(working_changeset, parent2, branch_merge)
  actions += manifest_merge(working_changeset, parent2, parent_ancestor, 
                            overwrite, partial)
                            
  ## Apply phase - apply the changes we just generated.
  unless branch_merge # just jump to the new revision
    fp1, fp2, xp1, xp2 = fp2, NULL_ID, xp2, ''
  end
  unless partial
    run_hook :preupdate, :throw => true, :parent1 => xp1, :parent2 => xp2
  end

  stats = apply_updates(actions, working_changeset, parent2)
  
  unless partial
    record_updates(actions, branch_merge)
    dirstate.parents = [fp1, fp2]
    if !branch_merge && !fast_forward
      dirstate.branch = parent2.branch
    end
    run_hook :update, :parent1 => xp1, :parent2 => xp2, :error => stats[3]
    dirstate.write
  end
  
  return stats
    
end