I recently converted an svn repository with git svn
. Unfortunately the svn history has a number of empty commit messages. This is a problem when I rebase and
You can use cherry pick:
git checkout -b temp_branch master
git checkout
git cherry-pick --allow-empty-message first_commit_to_include^..my_branch
# delete old my_branch and rename temp_branch to my_branch
git branch -D my_branch
git branch -m my_branch
As I commented before, this totally destroys comments if you happen to have newlines in them. Here's a perl script that does this without being destructive:
#!/usr/bin/perl
my $data = "";
while(<STDIN>) {
$data .= $_;
}
if($data =~ /^\s*$/) { $data="[Empty message]\n"; }
print "$data";
Then, just git filter-branch -f --msg-filter /path/to/perlfilter.pl
Aborting commit due to empty commit message.
You won't have this issue with Git 2.17 (Q1 2018), since "git rebase
" learned to take a new option: "--allow-empty-message
". (which is the default one in Git 2.19, see below)
See commit a6c612b (04 Feb 2018) by Genki Sky (``).
(Merged by Junio C Hamano -- gitster -- in commit 2f6128d, 21 Feb 2018)
rebase
: add--allow-empty-message
optionThis option allows commits with empty commit messages to be rebased, matching the same option in
git-commit
andgit-cherry-pick
.
While empty log messages are frowned upon, sometimes one finds them in older repositories (e.g. translated from another VCS), or have other reasons for desiring them.
The option is available ingit-commit
andgit-cherry-pick
, so it is natural to make other git tools play nicely with them.
Adding this as an option allows the default to be "give the user a chance to fix", while not interrupting the user's workflow otherwise.
Elan Ruusamäe confirms in the comments:
works like a charm. built with mentioned commit applied. +
git rebase --root HEAD --allow-empty-message
Successfully rebased and updated detached HEAD.
git checkout -B master
With Git 2.19 (Q3 2018), --allow-empty-message
is the default option:
See commit b00bf1c, commit 1634688, commit 0661e49, commit 4d34dff, commit 983f464, commit c840e1a, commit 9929430 (27 Jun 2018), and commit d4e8062, commit 5dacd4a (25 Jun 2018) by Elijah Newren (newren).
(Merged by Junio C Hamano -- gitster -- in commit 0ce5a69, 24 Jul 2018)
git-rebase
: make--allow-empty-message
the default
rebase
backends currently behave differently with empty commit messages, largely as a side-effect of the different underlying commands on which they are based.
am
-based rebases apply commits with an empty commit message without stopping or requiring the user to specify an extra flag.
(It is interesting to note thatam
-based rebases are the default rebase type, and no one has ever requested a--no-allow-empty-message
flag to change this behavior.)
merge-based and interactive-based rebases (which are ultimately based ongit commit
), will currently halt on any such commits and require the user to manually specify what to do with the commit and continue.One possible rationale for the difference in behavior is that the purpose of an "
am
" based rebase is solely to transplant an existing history, while an "interactive" rebase is one whose purpose is to polish a series before making it publishable.
Thus, stopping and asking for confirmation for a possible problem is more appropriate in the latter case.However, there are two problems with this rationale:
- 1) merge-based rebases are also non-interactive and there are multiple types of rebases that use the interactive machinery but are not explicitly interactive (e.g. when either
--rebase-merges
or--keep-empty
are specified without--interactive
).
These rebases are also used solely to transplant an existing history, and thus also should default to--allow-empty-message
.- 2) this rationale only says that the user is more accepting of stopping in the case of an explicitly interactive rebase, not that stopping for this particular reason actually makes sense.
Exploring whether it makes sense, requires backing up and analyzing the underlying commands...If
git-commit
did not error out on empty commits by default, accidental creation of commits with empty messages would be a very common occurrence (this check has caught me many times).
Further, nearly all such empty commit messages would be considered an accidental error (as evidenced by a huge amount of documentation across version control systems and in various blog posts explaining how important commit messages are).
A simple check for what would otherwise be a common error thus made a lot of sense, andgit-commit
gained an--allow-empty-message
flag for special case overrides.
This has made commits with empty messages very rare.There are two sources for commits with empty messages for rebase (and cherry-pick):
- (a) commits created in git where the user previously specified
--allow-empty-message
to git-commit, and- (b) commits imported into git from other version control systems.
In case (a), the user has already explicitly specified that there is something special about this commit that makes them not want to specify a commit message; forcing them to re-specify with every cherry-pick or rebase seems more likely to be infuriating than helpful.
In case (b), the commit is highly unlikely to have been authored by the person who has imported the history and is doing the rebase or cherry-pick, and thus the user is unlikely to be the appropriate person to write a commit message for it.
Stopping and expecting the user to modify the commit before proceeding thus seems counter-productive.Further, note that while empty commit messages was a common error case for
git-commit
to deal with, it is a rare case for rebase (or cherry-pick).
The fact that it is rare raises the question of why it would be worth checking and stopping on this particular condition and not others.For example, why doesn't an interactive rebase automatically stop if the commit message's first line is 2000 columns long, or is missing a blank line after the first line, or has every line indented with five spaces, or any number of other myriad problems?
Finally, note that if a user doing an interactive rebase does have the necessary knowledge to add a message for any such commit and wants to do so, it is rather simple for them to change the appropriate line from 'pick' to 'reword'.
The fact that the subject is empty in the todo list that the user edits should even serve as a way to notify them.As far as I can tell, the fact that merge-based and interactive-based rebases stop on commits with empty commit messages is solely a by-product of having been based on
git-commit
.
It went without notice for a long time precisely because such cases are rare. The rareness of this situation made it difficult to reason about, so when folks did eventually notice this behavior, they assumed it was there for a good reason and just added an--allow-empty-message
flag.
In my opinion, stopping on such messages not desirable in any of these cases, even the (explicitly) interactive case.
Note: "git rebase
" etc. in Git 2.19 fails to abort when given an empty
commit log message as result of editing, which has been corrected in Git 2.20 (Q4 2018).
sequencer
: fix--allow-empty-message
behavior, make it smarterIn commit b00bf1c ("
git-rebase
: make--allow-empty-message
the default", 2018-06-27, Git v2.19.0-rc0), several arguments were given for transplanting empty commits without halting and asking the user for confirmation on each commit.These arguments were incomplete because the logic clearly assumed the only cases under consideration were transplanting of commits with empty messages (see the comment about "There are two sources for commits with empty messages).
It didn't discuss or even consider rewords, squashes, etc. where the user is explicitly asked for a new commit message and provides an empty one.
(My bad, I totally should have thought about that at the time, but just didn't.)Rewords and squashes are significantly different, though, as described by SZEDER:
Let's suppose you start an interactive rebase, choose a commit to squash, save the instruction sheet, rebase fires up your editor, and then you notice that you mistakenly chose the wrong commit to squash. What do you do, how do you abort? Before [that commit] you could clear the commit message, exit the editor, and then rebase would say "Aborting commit due to empty commit message.", and you get to run 'git rebase --abort', and start over. But [since that commit, ...] saving the commit message as is would let rebase continue and create a bunch of unnecessary objects, and then you would have to use the reflog to return to the pre-rebase state.
Also, he states:
The instructions in the commit message template, which is shown for '
reword
' and 'squash
', too, still say...# Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit.
These are sound arguments that when editing commit messages during a sequencer operation, that if the commit message is empty then the operation should halt and ask the user to correct.
The arguments in commit b00bf1c (referenced above) still apply when transplanting previously created commits with empty commit messages, so the sequencer should not halt for those.Furthermore, all rationale so far applies equally for cherry-pick as for rebase.
Therefore, make the code:
- default to
--allow-empty-message
when transplanting an existing commit, and to- default to halting when the user is asked to edit a commit message and provides an empty one -- for both rebase and cherry-pick.
Note, when dealing with empty commits, make sure to use Git 2.25+ (Q2 2020).
See "How to fill in an empty commit message?" (last section).
With Git 2.26 (Q1 2020), the documentation is updated
See commit 10cdb9f, commit 2ac0d62, commit 8295ed6, commit 76340c8, commit 980b482, commit c2417d3, commit 6d04ce7, commit 52eb738, commit 8af14f0, commit be50c93, commit befb89c, commit 9a70f3d, commit 93122c9, commit 55d2b6d, commit 8a997ed, commit 7db00f0, commit e98c426, commit d48e5e2 (15 Feb 2020), and commit a9ae8fd, commit 22a69fd (16 Jan 2020) by Elijah Newren (newren).
(Merged by Junio C Hamano -- gitster -- in commit 8c22bd9, 02 Mar 2020)
git-rebase.txt: update description of --allow-empty-message
Signed-off-by: Elijah Newren
Commit b00bf1c9a8dd ("
git-rebase
: make --allow-empty-message the default", 2018-06-27, Git v2.19.0-rc0 -- merge listed in batch #4) made --allow-empty-message the default and thus turned --allow-empty-message into a no-op but did not update the documentation to reflect this.Update the documentation now, and hide the option from the normal -h output since it is not useful.
The git rebase man page now includes:
--allow-empty-message:
No-op.
Rebasing commits with an empty message used to fail and this option would override that behavior, allowing commits with empty messages to be rebased. Now commits with an empty message do not cause rebasing to halt.
With Git 2.26 (Q1 2020), "git rebase
" has learned to use the merge backend (i.e. the machinery that drives "rebase -i
") by default, while allowing "--apply
" option to use the "apply
" backend (e.g. the moral equivalent of "format-patch piped to am
").
(The rebase.backend
configuration variable can be set to customize.)
It manages empty commits better:
See commit 10cdb9f, commit 2ac0d62, commit 8295ed6, commit 76340c8, commit 980b482, commit c2417d3, commit 6d04ce7, commit 52eb738, commit 8af14f0, commit be50c93, commit befb89c, commit 9a70f3d, commit 93122c9, commit 55d2b6d, commit 8a997ed, commit 7db00f0, commit e98c426, commit d48e5e2 (15 Feb 2020), and commit a9ae8fd, commit 22a69fd (16 Jan 2020) by Elijah Newren (newren).
(Merged by Junio C Hamano -- gitster -- in commit 8c22bd9, 02 Mar 2020)
rebase (interactive-backend): fix handling of commits that become empty
Signed-off-by: Elijah Newren
As established in the previous commit and commit b00bf1c9a8dd ("
git-rebase
: make --allow-empty-message the default", 2018-06-27, Git v2.19.0-rc0 -- merge listed in batch #4), the behavior for rebase with different backends in various edge or corner cases is often more happenstance than design.This commit addresses another such corner case: commits which "become empty".
A careful reader may note that there are two types of commits which would become empty due to a rebase:
[clean cherry-pick]
Commits which are clean cherry-picks of upstream commits, as determined bygit log --cherry-mark ...
.
Re-applying these commits would result in an empty set of changes and a duplicative commit message; i.e. these are commits that have "already been applied" upstream.[become empty]
Commits which are not empty to start, are not clean cherry-picks of upstream commits, but which still become empty after being rebased.
This happens e.g. when a commit has changes which are a strict subset of the changes in an upstream commit, or when the changes of a commit can be found spread across or among several upstream commits.Clearly, in both cases the changes in the commit in question are found upstream already, but the commit message may not be in the latter case.
When cherry-mark can determine a commit is already upstream, then because of how cherry-mark works this means the upstream commit message was about the exact same set of changes.
Thus, the commit messages can be assumed to be fully interchangeable (and are in fact likely to be completely identical).
As such, the clean cherry-pick case represents a case when there is no information to be gained by keeping the extra commit around.
All rebase types have always dropped these commits, and no one to my knowledge has ever requested that we do otherwise.
For many of the become empty cases (and likely even most), we will also be able to drop the commit without loss of information -- but this isn't quite always the case.
Since these commits represent cases that were not clean cherry-picks, there is no upstream commit message explaining the same set of changes.
Projects with good commit message hygiene will likely have the explanation from our commit message contained within or spread among the relevant upstream commits, but not all projects run that way.
As such, the commit message of the commit being rebased may have reasoning that suggests additional changes that should be made to adapt to the new base, or it may have information that someone wants to add as a note to another commit, or perhaps someone even wants to create an empty commit with the commit message as-is.
Junio commented on the "become-empty" types of commits as follows:
WRT a change that ends up being empty (as opposed to a change that is empty from the beginning), I'd think that the current behaviour is desireable one.
"am
" based rebase is solely to transplant an existing history and want to stop much less than "interactive" one whose purpose is to polish a series before making it publishable, and asking for confirmation ("this has become empty--do you want to drop it?") is more appropriate from the workflow point of view.I would simply add that his arguments for "am"-based rebases actually apply to all non-explicitly-interactive rebases.
Also, since we are stating that different cases should have different defaults, it may be worth providing a flag to allow users to select which behavior they want for these commits.
Introduce a new command line flag for selecting the desired behavior: --empty={drop,keep,ask}
with the definitions:
drop
: drop commits which become emptykeep
: keep commits which become emptyask
: provide the user a chance to interact and pick what to do with commits which become empty on a case-by-case basisIn line with Junio's suggestion, if the
--empty
flag is not specified, pick defaults as follows:
- explicitly interactive: ask
- otherwise: drop
To replace empty commit messages with some template, you can do something like this:
git filter-branch -f --msg-filter '
read msg
if [ -n "$msg" ] ; then
echo "$msg"
else
echo "The commit message was empty"
fi'
You can recommit and continue with an empty commit message:
Aborting commit due to empty commit message.
Could not apply XXX... XXX
$ git commit --allow-empty -C $(<"$(git rev-parse --git-dir)/rebase-merge/onto")
$ git rebase --continue
If you have multiple lines you could also use cat:
git filter-branch -f --msg-filter \
'msg=$(cat); if [ "$msg" = "" ]; then echo "Here was an empty commit message"; else echo "$msg"; fi'
This handles commit messages with multiple lines as well as messages that contain empty lines for spacing.