Alexander Oh
Alexander Oh

Reputation: 25661

git create commit from diff between two branches

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

Answers (4)

Nicola De Angeli
Nicola De Angeli

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

Balog Pal
Balog Pal

Reputation: 17243

A simple way to make "the diff from branch_b..branch_a" into a commit is:

  1. create and checkout branch tmp at branch_a (git branch tmp branch_a && git checkout tmp) (or git reset --hard branch_a on an existing branch)
  2. git reset --soft branch_b
  3. 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 branch
  • 2. “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

Cory Klein
Cory Klein

Reputation: 55900

If you have two branches:

  1. has-changes
  2. 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

AndrewSk
AndrewSk

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

Related Questions