Number945
Number945

Reputation: 4940

Git rebase skipping identical commits

According to git rebase doc

If the upstream branch already contains a change you have made (e.g., because you mailed a patch which was applied upstream), then that commit will be skipped. For example, running git rebase master on the following history (in which A' and A introduce the same set of changes, but have different committer information):

      A---B---C topic
     /
D---E---A'---F master 

will result in:

               B'---C' topic
              /
D---E---A'---F master

What I am not able to understand is what is the need of this optimisation ? If git would have rebased like :

               A''---- B'---C' topic
              /
D---E---A'---F master

what could have gone wrong ? (A = A' = A'')

EDIT : To make myself more clear, Let us say F reverts changes of A'. Now rebase will not apply A patch on F and just B' and C'. In such a case, git rebase behaviour might be unexpected and to me it does not make sense.

Upvotes: 3

Views: 3791

Answers (3)

torek
torek

Reputation: 487725

It is possible to have successive commits that store the same source tree. That's what you would get here, because A'' would introduce no changes to F—those changes are already in F; the diff from E to F includes the same changes due to the diff from E to A'.

In other words, the snapshot in A'' would be the same as the snapshot in F. Git calls this kind of commit pair an empty commit: that is, if the parent matches the child, and the child is not a merge commit, Git says that the child commit is "empty" (even though it still has a full snapshot). The git commit command requires the flag --allow-empty to make such a commit.

Moreover, the commit message in A'' would likely be the same as the commit message in A'. If so, A'' is in all useful ways redundant. Eliminating it is probably the best course of action.

Note that git rebase was originally implemented using git format-patch, which turns each commit into a diff against its parent,1 with additional text to make the patch email-send-able. A separate program, git am, reads "mailbox format" files (sequences of emailed messages) and applies the patch, using the additional text to reproduce the commit author, author-date, and log message. However, format-patch and git am refuse to work with an empty patch. So the initial version of rebase, which used these two programs to achieve the commit copying, had to drop these "empty" commits.

Modern git rebase has multiple back-ends, not just git am. These can create or copy empty commits. Depending on your particular Git version, you may need to supply the -k flag to git rebase to get rebase to deliberately create such commits. If your version of Git uses git am as a default back-end, git rebase -k forces rebase to use the interactive or merge back-end, rather than the git am back end (and of course also modifies its initial setup to tell it not to drop "empty" commits automatically).

Git version 2.26 and later use a merge-based back end by default, and do not require the -k flag to keep empty commits. Using -k now means keep commits that become empty rather than keep commits that are initially empty.

You can also do your rebase manually, using individual git cherry-pick commands or en-masse cherry-picking using the sequencer. Like rebase, cherry-pick refuses to copy "empty" commits by default, requiring the --allow-empty and/or --keep-redundant-commits flags to keep such commits.


1git format-patch cannot format merge commits at all, as they have more than one parent.

Upvotes: 7

Romain Valeri
Romain Valeri

Reputation: 21908

Your last schema is an impossible state. (Or ar least, it was, but now you edited your question so it's not apparent any more)

A has E for its parent and this cannot change ever. If it did, then A would not be A any more, since a commit is the hashed result of (contents + metadata).

That's the reason A' is used here, by the way.

But to answer the title question, skipping these commits is a way to avoid verbose histories with (potentially, depending on workflows, of course) lots of empty commits.

Upvotes: 1

eftshift0
eftshift0

Reputation: 30156

First, it would not be A.... it would be A''.... but the real 'problem' is that the revision would be empty because those changes would be already applied on A'. But you can keep it in history, if so you want.

Upvotes: 1

Related Questions