Skip to content

Fix push after pull with full history rewrite #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion bin/git-subrepo
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,11 @@ require "subrepo/version"

app = Subrepo::CLI.new
app.setup
result = app.run(ARGV)
begin
result = app.run(ARGV)
rescue => e
require 'pry'
binding.pry
end

exit result
64 changes: 56 additions & 8 deletions lib/subrepo/commands.rb
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,19 @@ def command_pull(subdir, squash:, remote: nil)
end
end

# Push subrepo to the remote
#
# Steps in the process:
#
# * Fetch latest state from remote
# * Abort if any changes on the remote were not known: In this case, we
# need to pull first
# * Map the entire history of the repository, keeping only changes relevant
# to the subrepo
# * Rebase the mapped history onto the latest fetched commit
# * Push the result
# * Record the pushed commit and its local equivalent in the subrepo
# configuration
def command_push(subdir, remote: nil, branch: nil)
subdir or raise "No subdir provided"
fetched = command_fetch(subdir, remote: remote)
Expand All @@ -142,7 +155,7 @@ def command_push(subdir, remote: nil, branch: nil)
config = Config.new(subdir)

remote ||= config.remote
branch ||= config.branch
target_branch ||= config.branch
last_merged_commit = config.commit
last_pushed_commit = config.parent

Expand All @@ -158,9 +171,41 @@ def command_push(subdir, remote: nil, branch: nil)
raise "It seems #{split_branch_name} already exists. Remove it first"
end

last_commit = map_commits(repo, subdir, last_pushed_commit, last_merged_commit)
# TODO: If last_merged_commit maps to last_pushed_commit,
# use mapped_commits(repo, subdir, last_pushed_commit,
# last_merged_commit) directly to avoid history rewrite.

unless last_commit
mapped_commit_sha = map_commits(repo, subdir, nil, nil)
require 'pry'
binding.pry

if last_merged_commit.empty?
last_commit_sha = mapped_commit_sha
else
mapped_commit = repo.lookup mapped_commit_sha
upstream_commit = repo.lookup last_merged_commit
committer = {
name: repo.config["user.name"],
email: repo.config["user.email"]
}
rebase = Rugged::Rebase.new(repo, mapped_commit, upstream_commit)
while (result = rebase.next())
# NOTE: Expect result to contain the in-memory index
#index = rebase.inmemory_index
# NOTE: We would like to do some conflict resolution here, i.e.,
# start a merge editor, but the in-memory index has the wrong owner
# so can't find its repo.
#raise if index.conflicts?

# NOTE: Some conflicts are trivial!
require 'pry'
binding.pry
last_commit_sha = rebase.commit(committer: committer)
end
rebase.finish(committer)
end

unless last_commit_sha
if fetched
warn "No changes to push"
else
Expand All @@ -169,17 +214,20 @@ def command_push(subdir, remote: nil, branch: nil)
return
end

repo.branches.create split_branch_name, last_commit
system "git push \"#{remote}\" #{split_branch_name}:#{branch}"
pushed_commit = last_commit
require 'pry'
binding.pry
repo.branches.create split_branch_name, last_commit_sha
system "git push \"#{remote}\" #{split_branch_name}:#{target_branch}"

system "git branch -D #{split_branch_name}"
parent_commit = `git rev-parse HEAD`.chomp

config.commit = pushed_commit
config.commit = last_commit_sha
config.parent = parent_commit
system "git add -f -- #{config.file_name}"
system "git commit -m \"Push subrepo #{subdir}\""
require 'pry'
binding.pry
end

def command_init(subdir, remote: nil, branch: nil, method: nil)
Expand Down Expand Up @@ -280,7 +328,7 @@ def map_commits(repo, subdir, last_pushed_commit, last_merged_commit)
target_parents = target_parent_shas.map { |sha| repo.lookup sha }
rewritten_tree = calculate_subtree(repo, subdir, commit)

if parents.empty?
if target_parents.empty?
next if rewritten_tree.entries.empty?
else
# TODO: Compare tree oids directly instead of doing a full diff
Expand Down