Skip to content

Commit

Permalink
Add support for --apply
Browse files Browse the repository at this point in the history
This option would be useful to apply pending branches to merge on top of
another (non-integration) branch. Mostly for comparison purposes.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
  • Loading branch information
felipec committed May 24, 2014
1 parent 4eecf1f commit 036395b
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 8 deletions.
7 changes: 6 additions & 1 deletion doc/git-reintegrate.txt
Expand Up @@ -11,7 +11,7 @@ SYNOPSIS
'git reintegrate' --create <name> [<base>]
'git-reintegrate' --generate <name> [<base>]
'git-reintegrate' --add=<name>
'git-reintegrate' (--edit | --rebuild | --cat | --status) [<name>]
'git-reintegrate' (--edit | --rebuild | --apply | --cat | --status) [<name>]
'git reintegrate' (--continue | --abort)
'git-reintegrate' --list

Expand Down Expand Up @@ -78,6 +78,11 @@ If no base is specified, 'master' is assumed.
Delete an integration branch. It doesn't delete the branch itself, only
the integration information.

--apply::
Applies the instruction sheet of the integration branch on top of the
current branch. If a branch to merge is already completely merged in
the current branch, it's skipped.

If `--continue` or `--abort` are specified then no other options may be given.

CONFIGURATION
Expand Down
55 changes: 48 additions & 7 deletions git-reintegrate
Expand Up @@ -126,11 +126,17 @@ end
class Branch

attr_reader :name, :ref, :int
attr_reader :into_name, :into_ref

def initialize(name)
@name = name
end

def into_name=(name)
@into_name = name
@into_ref = %x[git rev-parse --symbolic-full-name "refs/heads/#{name}"].chomp
end

def get
if @name
@ref = %x[git rev-parse --symbolic-full-name "refs/heads/#{@name}"].chomp
Expand Down Expand Up @@ -291,7 +297,7 @@ class Integration
self.new(obj).run
end

def self.start(branch, inst)
def self.start(branch, into_name, inst)
require_clean_work_tree('integrate', "Please commit or stash them.")

orig_head = %x[git rev-parse --quiet --verify "#{branch}^{commit}"].chomp
Expand All @@ -306,6 +312,9 @@ class Integration
commit = %x[git rev-parse --quiet --verify #{branch}].chomp
File.write($start_file, commit)

$branch.into_name = into_name
File.write($into_file, into_name)

File.write($insns, inst)
self.run(inst)
end
Expand Down Expand Up @@ -336,11 +345,15 @@ class Integration
end

def finish
system(*%w[git update-ref], $branch.ref, 'HEAD', File.read($start_file))
system(*%w[git symbolic-ref], 'HEAD', $branch.ref)
system(*%w[git update-ref], $branch.into_ref, 'HEAD', File.read($start_file))
system(*%w[git symbolic-ref], 'HEAD', $branch.into_ref)
FileUtils.rm_rf($state_dir)
system(*%w[git gc --auto])
puts "Successfully re-integrated #{$branch.name}."
if $branch.name == $branch.into_name
puts "Successfully re-integrated #{$branch.name}."
else
puts "Successfully applied #{$branch.name} into #{$branch.into_name}."
end
end

def stop(msg = nil)
Expand Down Expand Up @@ -416,7 +429,7 @@ def deindent(msg)
end

def cmd_merge(message, branch_to_merge, *args)
merge_msg = "Merge branch '#{branch_to_merge}' into #{$branch.name}\n"
merge_msg = "Merge branch '#{branch_to_merge}' into #{$branch.into_name}\n"
merge_msg += "\n#{deindent(message)}\n" unless message.empty?

merge_opts = args
Expand Down Expand Up @@ -497,6 +510,7 @@ def get_head_file
branch_name = File.read($head_file).gsub(%r{^refs/heads/}, '')
branch = Branch.new(branch_name)
branch.get
branch.into_name = File.read($into_file)
return branch
end

Expand Down Expand Up @@ -525,11 +539,29 @@ end
def do_abort
$branch = get_head_file

system(*%w[git symbolic-ref HEAD], $branch.ref) &&
system(*%w[git reset --hard], $branch.ref) &&
system(*%w[git symbolic-ref HEAD], $branch.into_ref) &&
system(*%w[git reset --hard], $branch.into_ref) &&
FileUtils.rm_rf($state_dir)
end

def do_apply
head = %x[git rev-parse --symbolic --abbrev-ref HEAD].chomp

inst = $branch.read_instructions
die "Failed to read instruction list for branch #{$branch.name}" unless $?.success?

inst = inst.lines.reject do |line|
next true if line =~ /^base /
if line =~ /^merge (.*)$/
system(*%W[git merge-base --is-ancestor #{$1} HEAD])
next true if $?.success?
end
false
end.join

Integration.start(head, head, inst)
end

def status_merge(branch_to_merge = nil)
if not branch_to_merge
$stderr.puts "no branch specified with 'merge' command"
Expand Down Expand Up @@ -646,6 +678,10 @@ opts.on('d', 'delete', 'delete an integration branch') do |v|
$delete = true
end

opts.on(nil, 'apply', 'apply an integration branch on the current branch') do |v|
$apply = true
end

%x[git config --bool --get integration.autocontinue].chomp == "true" &&
$autocontinue = true

Expand All @@ -658,6 +694,7 @@ $start_file = "#{$state_dir}/start-point"
$head_file = "#{$state_dir}/head-name"
$merged_file = "#{$state_dir}/merged"
$insns = "#{$state_dir}/instructions"
$into_file = "#{$state_dir}/into"

case $actions.first
when :continue
Expand Down Expand Up @@ -713,6 +750,10 @@ if $rebuild
do_rebuild
end

if $apply
do_apply
end

if $status
do_status
end
68 changes: 68 additions & 0 deletions test/apply.t
@@ -0,0 +1,68 @@
#!/bin/sh

#
# Copyright (C) 2014 Felipe Contreras
#
# This file may be used under the terms of the GNU GPL version 2.
#

test_description='Test git reintegrage apply option'

. ./test-lib.sh

commit_file() {
local filename="$1"
echo "$2" > $filename &&
git add -f $filename &&
git commit -q -m "commit $filename"
}

test_expect_success 'setup branches' '
git init -q &&
commit_file base base &&
git checkout -b feature-1 master &&
commit_file feature-1 feature-1 &&
git checkout -b feature-2 master &&
commit_file feature-2 feature-2 &&
git checkout -b next master &&
git merge --no-ff feature-1 &&
git merge --no-ff feature-2
'

test_expect_success 'generate integration' '
git reintegrate --create integration &&
git reintegrate --add=feature-1 --add=feature-2 &&
git reintegrate --rebuild &&
> expected &&
git diff next integration > actual &&
test_cmp expected actual
'

test_expect_success 'update integration' '
git checkout feature-1 &&
commit_file feature-1-fix feature-1-fix &&
git reintegrate --rebuild integration &&
git diff feature-1^..feature-1 > expected &&
git diff next integration > actual &&
test_cmp expected actual
'

cat > expected <<EOF
Merge branch 'feature-1' into next
commit feature-1-fix
EOF

test_expect_success 'apply pending' '
git checkout next &&
git branch old &&
git reintegrate --apply integration &&
git log --format=%s old..next > actual &&
test_cmp expected actual &&
> expected &&
git diff next integration > actual &&
test_cmp expected actual
'

test_done

0 comments on commit 036395b

Please sign in to comment.