Skip to content

Commit

Permalink
[CodeExtractor] Support merge commits
Browse files Browse the repository at this point in the history
When using cherry-pick, it wouldn't handle merges properly, since it
requires a `-m 1` argument for it to work properly.

By switching to using `git rebase --root --onto`, we can take the branch
that now is a "orphan" branch, and apply the commits onto the target
remote's target branch.

Left extra code in there to show other possibilities (since this isn't
getting merged in away)
  • Loading branch information
NickLaMuro committed Nov 20, 2019
1 parent 52d2a40 commit 8e0fc61
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 3 deletions.
40 changes: 37 additions & 3 deletions lib/code_extractor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,16 @@ def extract_commits extractions, upstream_name
end
end

# Three step process to filter out the commits we want in three passes:
#
# - Move code we want to keep into a separate tmp dir (using @prune_script)
# - Prune anything that isn't in that subdirectory
# - Move the tmp directory back into the root of the directory
#
#
# Note: We don't use `--subdirectory-filter` here as it will remove merge
# commits, which we don't want.
#
def prune_commits extractions
puts "Pruning commits…"

Expand All @@ -102,7 +112,11 @@ def prune_commits extractions
Dir.chdir git_dir do
`git checkout -b #{prune_branch} #{@source_branch}`
`git filter-branch -f --prune-empty --tree-filter #{@prune_script} HEAD`
`git filter-branch -f --prune-empty --subdirectory-filter #{@keep_directory}`
`git filter-branch -f --prune-empty --index-filter '
git read-tree --empty
git reset $GIT_COMMIT -- #{@keep_directory}
'HEAD`
`git filter-branch -f --prune-empty --tree-filter 'mv #{@keep_directory}/* .' HEAD`
end
end

Expand Down Expand Up @@ -188,8 +202,28 @@ def inject_commits target_base_branch, upstream_name
echo "(transferred from #{upstream_name}@$GIT_COMMIT)"
' -- #{prune_branch}`

`git checkout --no-track -b #{inject_branch} #{@reference_target_branch}`
`git cherry-pick ..#{prune_branch}`
# Old (bad: doesn't handle merges)
#
# `git checkout --no-track -b #{inject_branch} #{@reference_target_branch}`
# `git cherry-pick ..#{prune_branch}`
#
#
# Attempted #1 (not working, but uses older `git` methods)
#
# `git checkout --orphan #{inject_branch}`
# `git commit -m "Dummy Init commit"`
# orphan_commit = `git log --pretty="%H" -n1`.chomp
# prune_first = `git log --pretty="%H" --reverse -n1 #{prune_branch}`.chomp
# `git rebase --onto #{orphan_commit} #{prune_first} #{inject_branch}`
# `git replace #{orphan_commit} #{@reference_target_branch}`
#
#
# Better
#
# Ref: git rebase --onto code_extractor_inject_the_extracted --root
#
`git checkout --no-track -b #{inject_branch} #{prune_branch}`
`git rebase --preserve-merges --root --onto #{@reference_target_branch} #{inject_branch}`
end
end

Expand Down
67 changes: 67 additions & 0 deletions test/code_extractor_reinsert_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ def test_unextract_an_extraction
]

refute Dir.exist? "foo"
refute File.exist? "README.md"

assert File.exist? "qux"
assert File.exist? "lib/foo/bar"
assert File.exist? "lib/foo/baz"
Expand Down Expand Up @@ -129,6 +131,68 @@ def test_reinsert_when_code_extractor_was_not_used
]

refute Dir.exist? "foo"
refute File.exist? "README.md"

assert File.exist? "qux"
assert File.exist? "lib/foo/bar"
assert File.exist? "lib/foo/baz"
end
end

# Basically, a test to ensure we are using a rebase and not a cherry-pick
# method, since `git cherry-pick` doesn't handle merge commits well.
def test_reinsert_when_there_is_a_merge_commit
# original extraction to work off of, in which we "un-extract" this later
create_base_repo
set_extractions ["foo"]
run_extraction

# Perform updates to extracted repo to simulate changes since extraction
perform_merges_of_extracted_code
apply_new_commits_on_extracted_repo do
checkout_b 'master', 'origin/master'

update_file "foo/bar", "Updated Bar Content"
commit "update bar content"

checkout_b 'add_baz', 'master'

update_file "foo/baz", "Baz Content"
commit "add new baz"

checkout 'master'
merge 'add_baz'

add_file "README.md", "READ ME!"
commit "add README"
end
update_extraction_hash

# Run new extraction, with some extra commits added to the new repo that
# has been extracted previously
#
# This next line will run the actual extraction we are testing
#
# aka: updated commits and puts 'lib/foo' back into the original repo
run_extraction

in_git_dir do
assert_commits [
"Move foo/ into lib/",
"Merged branch 'add_baz' into master",
"add new baz",
"update bar content",
"Re-insert extractions from MyOrg/extracted_repo",
"Merged branch 'extract_my_extractions' into master",
"Extract my_extractions",
"Commit #3",
"add Bar content",
"Initial Commit"
]

refute Dir.exist? "foo"
refute File.exist? "README.md"

assert File.exist? "qux"
assert File.exist? "lib/foo/bar"
assert File.exist? "lib/foo/baz"
Expand Down Expand Up @@ -170,6 +234,9 @@ def apply_new_commits_on_extracted_repo &block

update_file "foo/baz", "Baz Content"
commit "add new baz"

add_file "README.md", "READ ME!"
commit "add README"
end
end

Expand Down

0 comments on commit 8e0fc61

Please sign in to comment.