Home > Enterprise >  Is there any difference between git fixup and drop reword while interactive rebasing?
Is there any difference between git fixup and drop reword while interactive rebasing?

Time:01-11

I've started looking into interactive rebasing a little more and I've come across some issues. They are about the "fixup" option. I am interested in what is the difference between fixup and drop reword option. For example, let's say we have:

pick 577dab2 add navbar
pick 432fda1 fix navbar bug

What is the difference between these two:

pick 577dab2 add navbar
fixup 432fda1 fix navbar bug

and

drop 577dab2 add navbar
reword 432fda1 fix navbar bug -> reword it to 'add navbar'

It would make a difference if the fixup option provided resolution of conflicts if there were any when "merging" (I know it's not real merging, but let's call it that) with the previous commit (in my example, if there is any conflicts between 577dab2 and 432fda1 commit). However, as far as I have noticed, the implementation is only "meld into", that is, everything that is within the fixup commit (432fda1) will only be "transferred" to the previous commit (577dab2) and the name of that previous commit (577dab2) will be taken. In other words, even if there is conflicts, they won't be resolved because everything was just "transferred" from one commit to another.

So from what I understand so far, fixup just allows the same thing to be done faster... Can anyone tell me what the real difference (if any)?

Someone asked this question over 8 years ago, but no one answered, at least not completely. Here's link.

CodePudding user response:

What is the difference between these two

All the difference in the world. drop is very powerful option that propagates to all later commits a major alteration such that the "changes" represented by the dropped commit in relation to its parent will never have happened.

pick is just the opposite. It keeps those "changes" in the history.

Indeed, the two choices you compare have nothing substantial in common. I don't see why you ask for the difference between them; what they lack is any similarity.

CodePudding user response:

Yes, a huge difference. If you drop the first commit, it... drops the first commit. Whatever changes were in that commit will be gone, the thing that you were fixing won't be there to fix, the second commit probably won't apply, and if it does apply it probably won't be valid.

CodePudding user response:

They are not equivalent.

I think the confusion is that when working with an interactive rebase you're working with individual sets of changes, not the complete content up to that commit. Think of it like rearranging a series of patches.

When you say drop 577dab2 add navbar it is as if that commit never happened. There is no navbar for 432fda1 to fix.


pick 577dab2 add navbar
fixup 432fda1 fix navbar bug

You're saying "pretend I never made that mistake and did it right the first time".

This turns the changes in both commits into a single commit, and uses the log message for the picked commit. You wind up with the changes in both 577dab2 and 432fda1 in a single new commit with only the "add navbar" log message.

drop 577dab2 add navbar
reword 432fda1 fix navbar bug -> reword it to 'add navbar'

You're saying "pretend 577dab2 never happened, I never added a navbar" (I'm ignoring the reword, its not relevant).

This throws out the changes made in 577dab2 (adding a navbar) and you're left with just the changes in 432fda1. Since 432fda1 is trying to fix a navbar that was never added, you'll probably get a conflict.


the implementation is only "meld into", that is, everything that is within the fixup commit (432fda1) will only be "transferred" to the previous commit (577dab2) and the name of that previous commit (577dab2) will be taken.

Side note: Git never changes a commit. It only creates new commits.

Let's say your repo looks like this.

A - B - C - D - E [main]

Let's say you fixup C. Git creates a new commit with the changes in both B and C and rewrites the changes of D and E on top of the new commit.

A - B - C - D - E
 \
  BC - D1 - E1 [main]

The old B, C, D, and E commits will be garbage collected.

For more on why it works this way, see What is a Git commit ID?.

But if you say drop B Git will now try to rewrite C on top of A. It's as if B never happened.

A - B - C - D - E
 \
  C1 - D1 - E1 [main]

The changes in C are now applied to A. If C's changes depend on B (as in fixing the navbar introduced by B) then you will get a conflict.


Let's look at it another way. Let's say 577dab2 is this.

--- a/dir1/file
    b/dir1/file
@@ -11,3  11,7 @@ and some more
 and here is more
 
 and then this
 
 
 Back Home Escape Next
 

And 432fda1 is this.

--- a/dir1/file
    b/dir1/file
@@ -13,5  13,5 @@ and here is more
 and then this
 
 
-Back Home Escape Next
 Back Home Leave Next
 

And you do a fixup...

pick dedbeef something else
pick 577dab2 add navbar
fixup 432fda1 fix navbar bug

The result is a new commit containing both 577dab2 and 432fda1's changes with 577dab2's commit message.

pick dedbeef something else
pick abc1234 add navbar
--- a/dir1/file
    b/dir1/file
@@ -11,3  11,7 @@ and some more
 and here is more
 
 and then this
 
 
 Back Home Leave Next
 

But if you drop 577dab2 and reword 432fda1...

pick dedbeef something else
drop 577dab2 add navbar
reword 432fda1 fix navbar bug

This is the same as deleting 577dab2 and trying to apply the changes in 432fda1 on top of dedbeef.

pick dedbeef something else
reword 432fda1 fix navbar bug

dedbeef doesn't have a "Back Home Escape Next" line to alter, so this will result in a conflict.

CodePudding user response:

Your misunderstanding is conceptual about how rebase works. Rebasing is basically just cherry-picking each of the changes contained in a range of commits (thus the word "pick" in an interactive rebase). Note your thought about reaching the original state of a commit isn't relevant when cherry-picking or rebasing.

Given that, consider the differences:

pick aaaaaaa Add file A
pick bbbbbbb Add file B
# RESULTING COMMITS: 2 commits with those titles
# RESULTING STATE:   File A and File B both exist.

pick aaaaaaa Add file A
fixup bbbbbbb Add file B
# RESULTING COMMITS: 1 commit with title "Add file A"
# RESULTING STATE:   File A and File B both exist.

drop aaaaaaa Add file A
reword bbbbbbb Add file B
# RESULTING COMMITS: 1 commit with default title "Add file B", but pops up editor
#                      and allows you to change it
# RESULTING STATE:   Only File B exists.
  • Related