public
Description: A set of Sake tasks to make developing with Git easier.
Clone URL: git://github.com/eventualbuddha/sake-git.git
Search Repo:
sake-git / git.rake
100644 249 lines (231 sloc) 6.17 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
task 'git:helpers' do
  class GitError < RuntimeError; end
  class GitRebaseError < GitError; end
  
  def git_branch
    `git-branch`.grep(/^\*/).first.strip[(2..-1)]
  end
  def git_branches
    `git-branch`.to_a.map { |b| b[(2..-1)].chomp }
  end
  def git?
    `git-status`
    (not ($?.exitstatus == 128))
  end
  def git_stash
    `git-diff-files --quiet`
    if ($?.exitstatus == 1) then
      stash = true
      clear = (`git-stash list`.scan("\n").size == 0)
      puts("* Saving changes...")
      `git-stash save`
    else
      stash = false
    end
    begin
      yield rescue puts("* Encountered an error, backing out...")
      ensure
        if stash then
          puts("* Applying changes...")
          sh("git-stash apply")
          `git-stash clear` if clear
        end
    end
  end
  
  def git_checkout(what = nil)
    branch = git_branch
    sh("git-checkout #{what}") if branch != what
    if block_given?
      yield
      sh("git-checkout #{branch}") if branch != what
    end
  end
  
  def git_fetch
    sh("git#{"-svn" if git_svn?} fetch")
  end
  
  def assert_command_succeeded(*args)
    raise *args if $?.exitstatus != 0
  end
  
  def assert_rebase_succeeded(what = nil)
    assert_command_succeeded GitRebaseError, "conflict while rebasing branch #{what}"
  end
  
  def git_rebase(what = nil)
    if git_svn? then
      git_checkout what do
        sh("git-svn rebase --local")
        assert_rebase_succeeded what
      end
    else
      sh("git-rebase origin/master #{what}")
      assert_rebase_succeeded what
    end
  end
  def git_push
    git_svn? ? (sh("git-svn dcommit")) : (sh("git-push"))
  end
  def git_svn?
    not File.readlines(".git/config").grep(/^\[svn-remote "svn"\]\s*$/).empty?
  end
  def argv
    ARGV.inject([]) do |argv, arg|
      if (argv.last and argv.last =~ /=$/) then
        (argv.last << arg)
      else
        (argv << arg.dup)
      end
      argv
    end
  end
  def correct_env_from_argv
    argv.grep(/^[A-Z]+=/).each { |kv| ENV.send(:[]=, *kv.split("=", 2)) }
  end
  def env(name)
    case val = ENV[name]
    when "", nil then
      nil
    else
      val
    end
  end
  correct_env_from_argv
end
 
desc 'Pull new commits from the repository'
task 'git:update' => [ 'git:helpers' ] do
  git_stash do
    branch = git_branch
    if (branch == "master") then
      switch = false
    else
      switch = true
      `git-checkout master`
      puts("* Switching back to master...")
    end
    puts("* Pulling in new commits...")
    git_fetch
    git_rebase
    if switch then
      puts("* Porting changes into #{branch}...")
      `git-checkout #{branch}`
      sh("git-rebase master")
    end
  end
end
 
desc 'Push local commits into the remote repository'
task 'git:push' => [ 'git:update' ] do
  git_stash do
    puts("* Pushing changes...")
    git_push
    branch = git_branch
    unless (branch == "master") then
      `git-checkout master`
      puts("* Porting changes into master")
      git_rebase
      `git-checkout #{branch}`
    end
  end
end
 
desc 'Delete the current branch and switch back to master'
task 'git:close' => [ 'git:helpers' ] do
  branch = (env("NAME") or git_branch)
  current = git_branch
  if (branch == "master") then
    $stderr.puts("* Cannot delete master branch")
    exit(1)
  end
  if (current == branch) then
    puts("* Switching to master")
    `git-checkout master 2>/dev/null`
  end
  puts("* Deleting branch #{branch}")
  `git-branch -d #{branch} 2>/dev/null`
  if ($?.exitstatus == 1) then
    $stderr.puts("* Branch #{branch} isn't a strict subset of master, quitting")
    `git-checkout #{current} 2>/dev/null`
    exit(1)
  end
  `git-checkout #{current} 2>/dev/null` unless (current == branch)
  exit(0)
end
 
desc 'Create a new branch off master'
task 'git:open' => [ 'git:helpers' ] do
  newbranch = (env("NAME") or begin
    (require("readline")
    print("* Name your branch: ")
    Readline.readline.chomp)
  end)
  branch = git_branch
  if git_branches.include?(newbranch)
    if newbranch == branch
      puts(%{* Already on branch "#{newbranch}"})
    else
      puts(%{* Switching to existing branch "#{newbranch}"})
      git_checkout newbranch
    end
    exit(0)
  end
  unless (branch == "master") then
    puts("* Switching to master")
    git_checkout 'master'
  end
  `git-checkout -b #{newbranch}`
  unless $?.exitstatus.zero? then
    puts("* Couldn't create branch #{newbranch}, switching back to #{branch}")
    git_checkout branch
    exit(1)
  end
  exit(0)
end
 
desc 'Merge the current branch into the master branch.'
task 'git:fold' => [ 'git:helpers' ] do
  branch = git_branch
  if (branch == "master") then
    $stderr.puts("* Cannot fold master branch")
    exit(1)
  end
  puts("* Switching to master")
  `git-checkout master 2>/dev/null`
  puts("* Merging #{branch}")
  system("git-merge #{@merge_flags} #{branch}")
  if ($?.exitstatus == 1) then
    $stderr.puts("* Merge had errors -- see to your friend")
    exit(1)
  end
  puts("* Switching to #{branch}")
  `git-checkout #{branch} 2>/dev/null`
end
 
desc 'Squash the current branch into the master branch.'
task 'git:squash' do
  @merge_flags = "--squash"
  Rake::Task["git:fold"].invoke
end
 
desc 'Update all branches'
task 'git:update:all' => [ 'git:helpers' ] do
  git_stash do
    branch = git_branch
    switch = true
    git_branches.each do |b|
      puts("* Updating branch #{b}")
      begin
        git_rebase(b)
      rescue GitRebaseError => e
        puts("* Couldn't rebase #{b}, aborting so you can clean it up")
        switch = false
        break
      end
    end
    `git-checkout #{branch} 2>/dev/null` if switch
  end
end
 
desc 'Converts an existing Subversion Repo into a Git Repository'
task 'git:ify' do
  # Make sure we're in an svn repo
  unless File.directory?("./.svn")
    $stderr.puts "This task can only be executed in an existing working copy! (No .svn-Folder found)"
    exit(1)
  end
 
  # get svn info location
  svnurl = %x(svn info).grep(/^URL:/).first.gsub('URL: ','').chomp
 
  # project = basename
  project = "../#{File.basename(Dir.pwd)}.git"
 
  puts cmd = "git svn clone #{svnurl} #{project}"
 
  `#{cmd}`
end