Module: GitWrapper

Defined in:
lib/git_wrapper.rb

Defined Under Namespace

Classes: OutOfDateGitException, WorkingFolderDirtyException, WrongBranchException

Class Method Summary collapse

Class Method Details

.add(*args) ⇒ Object



173
174
175
# File 'lib/git_wrapper.rb', line 173

def add(*args)
  run_git "add #{args.join(" ")}"
end

.branches(remote_name = nil) ⇒ Object



38
39
40
41
42
43
44
# File 'lib/git_wrapper.rb', line 38

def branches(remote_name = nil)
  if remote_name
    git.remotes.select { |e| e.name =~ Regexp.new("^#{remote_name}") }
  else
    git.branches
  end
end

.checkout(branch_name, remote = 'origin') ⇒ Object

Modification commands: these just shell out to git (directly or indirectly) #####



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/git_wrapper.rb', line 60

def checkout(branch_name, remote='origin')
  fetch(remote)
  lb, rb = local_branch_exists?(branch_name), remote_branch_exists?(branch_name, remote)
  case
  when  lb &&  rb
    checkout_with_existing_local_and_existing_remote(branch_name, remote)
  when  lb && !rb
    checkout_with_existing_local_and_NON_existing_remote(branch_name, remote)
  when !lb &&  rb
    checkout_with_NON_existing_local_and_existing_remote(branch_name, remote)
  when !lb && !rb
    checkout_with_NON_existing_local_and_NON_existing_remote(branch_name, remote)
  end
  return "That was fun!"
end

.checkout_branch(branch_name, remote = nil) ⇒ Object



120
121
122
123
# File 'lib/git_wrapper.rb', line 120

def checkout_branch(branch_name, remote=nil)
  refspec = [remote, branch_name].reject(&:nil?) * '/'
  run_git "checkout #{refspec}"
end

.checkout_with_existing_local_and_existing_remote(branch_name, remote) ⇒ Object



76
77
78
79
80
# File 'lib/git_wrapper.rb', line 76

def checkout_with_existing_local_and_existing_remote(branch_name, remote)
  checkout_branch(branch_name)
  track_remote_branch(branch_name, remote)
  merge_without_remote_update(branch_name, remote)
end

.checkout_with_existing_local_and_NON_existing_remote(branch_name, remote) ⇒ Object



81
82
83
84
85
# File 'lib/git_wrapper.rb', line 81

def checkout_with_existing_local_and_NON_existing_remote(branch_name, remote)
  checkout_branch(branch_name)
  publish_remote_branch(branch_name, remote)
  track_remote_branch(branch_name, remote)
end

.checkout_with_NON_existing_local_and_existing_remote(branch_name, remote) ⇒ Object



86
87
88
89
90
91
# File 'lib/git_wrapper.rb', line 86

def checkout_with_NON_existing_local_and_existing_remote(branch_name, remote)
  checkout_branch(branch_name, remote)
  create_branch(branch_name)
  checkout_branch(branch_name)
  track_remote_branch(branch_name, remote)
end

.checkout_with_NON_existing_local_and_NON_existing_remote(branch_name, remote) ⇒ Object



92
93
94
95
96
97
98
# File 'lib/git_wrapper.rb', line 92

def checkout_with_NON_existing_local_and_NON_existing_remote(branch_name, remote)
  checkout_branch 'master'  # yes, really
  create_branch(branch_name)
  checkout_branch(branch_name)
  publish_remote_branch(branch_name, remote)
  track_remote_branch(branch_name, remote)
end

.commit(default_message = "") ⇒ Object



177
178
179
# File 'lib/git_wrapper.rb', line 177

def commit(default_message = "")
  run_git "commit -m \"#{default_message}\" -e", true
end

.create_branch(branch_name) ⇒ Object



104
105
106
# File 'lib/git_wrapper.rb', line 104

def create_branch(branch_name)
  run_git "branch #{branch_name}".strip
end

.current_branch_nameObject



26
27
28
# File 'lib/git_wrapper.rb', line 26

def current_branch_name
  git.head.name
end

.fetch(remote = 'origin') ⇒ Object



100
101
102
# File 'lib/git_wrapper.rb', line 100

def fetch(remote='origin')
  run_git "fetch #{remote}"
end

.gitObject



11
12
13
# File 'lib/git_wrapper.rb', line 11

def git
  @git ||= Grit::Repo.new(locate_git_repo_root)
end

.git_versionObject



34
35
36
# File 'lib/git_wrapper.rb', line 34

def git_version
  @git_version ||= run_git('--version').match(/^git version (.*)$/).captures.first.split('.').map(&:to_i)
end

.is_git_current_enough?Boolean

Returns:

  • (Boolean)


30
31
32
# File 'lib/git_wrapper.rb', line 30

def is_git_current_enough?
  (git_version <=> [1, 7]) != -1
end

.is_state_clean?Boolean

Returns:

  • (Boolean)


54
55
56
57
# File 'lib/git_wrapper.rb', line 54

def is_state_clean?
  current_status = run_git 'status'
  !!(current_status =~ /nothing to commit \(working directory clean\)/)
end

.local_branch_exists?(name) ⇒ Boolean

Returns:

  • (Boolean)


46
47
48
# File 'lib/git_wrapper.rb', line 46

def local_branch_exists?(name)
  git.branches.any? { |e| e.name == name }
end

.locate_git_repo_root(start_dir = nil) ⇒ Object



15
16
17
18
19
20
21
22
23
24
# File 'lib/git_wrapper.rb', line 15

def locate_git_repo_root(start_dir = nil)
  pwd = start_dir || ENV['PWD']
  if Dir.new(pwd).entries.include?('.git')
    pwd
  else
    parent = File.dirname(pwd)
    return nil if parent == pwd
    locate_git_repo_root(parent)
  end
end

.merge_branch_into_master(branch = nil) ⇒ Object



150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/git_wrapper.rb', line 150

def merge_branch_into_master(branch=nil)
  if branch
    require_clean_master_branch
    branch_to_be_squashed = branch
  else
    require_clean_story_branch
    branch_to_be_squashed = current_branch_name
    run_git 'checkout master'
  end
  run_git 'pull'
  run_git "merge #{branch_to_be_squashed}"
end

.merge_from_masterObject



129
130
131
132
133
134
135
136
# File 'lib/git_wrapper.rb', line 129

def merge_from_master
  require_clean_story_branch
  story_branch = current_branch_name
  run_git 'checkout master'
  run_git 'pull'
  run_git "checkout #{story_branch}"
  run_git 'merge master'
end

.merge_without_remote_update(branch, remote) ⇒ Object



125
126
127
# File 'lib/git_wrapper.rb', line 125

def merge_without_remote_update(branch, remote)
  run_git "merge #{remote}/#{branch}"
end

.publish_remote_branch(branch_name, remote = 'origin') ⇒ Object



108
109
110
# File 'lib/git_wrapper.rb', line 108

def publish_remote_branch(branch_name, remote='origin')
  run_git "push #{remote} #{branch_name}:refs/heads/#{branch_name}"
end

.push_branchObject



144
145
146
147
148
# File 'lib/git_wrapper.rb', line 144

def push_branch
  require_clean_story_branch
  run_git 'pull --rebase'
  run_git "push origin #{current_branch_name}"
end

.push_masterObject



138
139
140
141
142
# File 'lib/git_wrapper.rb', line 138

def push_master
  require_clean_master_branch
  run_git 'pull --rebase'
  run_git "push origin master"
end

.remote_branch_exists?(name, remote = 'origin') ⇒ Boolean

Returns:

  • (Boolean)


50
51
52
# File 'lib/git_wrapper.rb', line 50

def remote_branch_exists?(name, remote='origin')
  branches(remote).any? { |b| b.name == "#{remote}/#{name}" }
end

.require_clean_master_branchObject



168
169
170
171
# File 'lib/git_wrapper.rb', line 168

def require_clean_master_branch
  raise WorkingFolderDirtyException.new unless is_state_clean?
  raise WrongBranchException.new unless 'master' == current_branch_name
end

.require_clean_story_branchObject



163
164
165
166
# File 'lib/git_wrapper.rb', line 163

def require_clean_story_branch
  raise WorkingFolderDirtyException.new unless is_state_clean?
  raise WrongBranchException.new if 'master' == current_branch_name
end

.run_git(cmd, interactive = false) ⇒ Object



181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/git_wrapper.rb', line 181

def run_git(cmd, interactive=false)
  puts "*" * 80
  puts "* git #{cmd}"
  puts "*" * 80
  old_env = ENV['I_AM_A_GIT_GURU']
  ENV['I_AM_A_GIT_GURU'] = '1'
  if interactive
    ShellCmd.run "git #{cmd}"
  else
    out = `git #{cmd}`
    puts out
    return out
  end
ensure
  ENV['I_AM_A_GIT_GURU'] = old_env
end

.string_hyphenize(str) ⇒ Object



198
199
200
# File 'lib/git_wrapper.rb', line 198

def string_hyphenize(str)
  str.gsub(/[^A-Za-z ]/, '').gsub(/\s+/, '-').downcase
end

.track_remote_branch(branch_name, remote = 'origin') ⇒ Object



112
113
114
115
116
117
118
# File 'lib/git_wrapper.rb', line 112

def track_remote_branch(branch_name, remote='origin')
  # Note that this could also be written as:
  #   run_git "config branch.#{branch_name}.remote #{remote}"
  #   run_git "config branch.#{branch_name}.merge refs/heads/#{branch_name}"
  # ...but that doesn't read nearly as well.  Just upgrade your damn git install already.
  run_git "branch --set-upstream #{branch_name} #{remote}/#{branch_name}"
end