Reputation: 25661
I have two branches which have very little similar history, but are related to each other.
I want the changes between those two in one git commit.
files have been deleted and created between those patches and I want the patch to reflect that
i.e.: the following stuff will not work:
git diff branch_a branch_b -- > patchfile
git checkout branch_b
git apply patchfile # deletes and adds are ignored
git commit # we miss the deletes
Upvotes: 130
Views: 43853
Reputation: 21
If I understand correctly from your example, what you really want to achieve is to create a commit in branch_b
that makes the state of the repository match exactly that of branch_a
.
In that case, git commit-tree
will do the job:
new_commit=$(git commit-tree -p branch_b -m "my message" branch_a^{tree})
git branch --force branch_b $new_commit
In the commands above, we first create a new commit with branch_b
as the parent and with the same state of the repository as that of branch_a
. We then capture the object id of the new commit in the variable new_commit
to finally have branch_b
point to this new commit, effectively obtaining the same outcome as if we had committed the difference between branch_b
and branch_a
to branch_b
.
Note that git branch
will fail if we are already checked out at branch_b
. In that case, we can use git reset
instead:
git reset $new_commit # use --hard to also reset working directory
Another more traditional approach is to leverage git diff
in combination with git apply
:
git checkout branch_b
git diff --binary branch_b branch_a | git apply --index
git commit -m "my message"
This, however, might fail depending on the state of your working tree, as existing untracked or unstaged changes might cause conflicts when applying the patch.
Upvotes: 2
Reputation: 17243
A simple way to make "the diff from branch_b..branch_a" into a commit is:
git branch tmp branch_a && git checkout tmp
) (or git reset --hard branch_a
on an existing branch)git reset --soft branch_b
git commit
that commit will include all the diff between branch_b and branch_a.
This works because
1.
causes the files to reflect branch_a. This is the "end result" you want for the branch2.
“resets the head to branch_b” but “leaves all your changed files [i.e. branch_a head] as "Changes to be committed", as git status
would put it.” ←(git reset --soft
docs, with this example's branches added)Upvotes: 185
Reputation: 55900
If you have two branches:
has-changes
needs-changes
And you want to move the changes from has-changes
onto needs-changes
, then do the following:
git checkout -b deleteme has-changes # Create temporary branch to build commit on
git reset --soft needs-changes # Move diff into index
git commit # Create the diff patch commit
git checkout needs-changes # Switch to branch that needs changes
git cherry-pick deleteme # Apply the diff to the needs-changes
git branch -D deleteme # Delete the temporary branch
Upvotes: 59
Reputation: 161
It all comes down to a git reset --soft branch_b
on top of a temp branch based on branch_a, and the result committed back to branch_b.
This is a step-by-step walking through the process:
#Start out on the branch with the code we want
git checkout branch_a
#create tmp branch same as branch_a (so that we don't change our local branch_a state during the operation)
git branch tmp
#working directory has all the code that we want, on tmp branch
git checkout tmp
# Change the branch head to the branch we want to be on. All the delta
# between the current source code and branch_b is now staged for commit
git reset --soft branch_b
# Move away from tmp, so our commit will go directly to branch_b
git checkout branch_b
# Now you can examine the proposed commit
git status
# Add the delta we want to the branch
git commit
# Sanity check that the branches have the same content now (should return an empty line)
git diff branch_A..branch_b
# Remove tmp, we don't need it anymore
git branch -D tmp
Upvotes: 16