hg-to-git: handle an empty dir in hg by combining git commits
PATCH 1/1 hg-to-git: handle an empty dir in hg by combining git commits
I had a subversion repository which was then converted to hg and now is moving in to git. The first commit in the svn repo was just the creation of the empty directory. This made its way in to the hg repository fine, but converting from hg to git would cause an error. The problem was that hg-to-git.py tries to commit the change, git-commit fails, and then hg-to-git.py tries to checkout the new revision and that fails (b/c it was not created). This may have only caused an error because it was the first commit in the repository. If an empty directory was added in the middle of the repo somewhere things might have worked out fine.
This patch will detect that there are no changes to commit (using git-status), and will not perform the commit, but will instead combine the log messages of that (non-)commit with the next commit.
--- contrib/hg-to-git/hg-to-git.py | 15 +++++++++++++-- 1 files changed, 13 insertions(+), 2 deletions(-)
contrib/hg-to-git/hg-to-git.py +13 -2
@@ -139,6 +139,7 @@ if not hgvers.has_key("0"): os.system('git-init-db') # loop through every hg changeset +previous_comment = None for cset in range(int(tip) + 1): # incremental, already seen
@@ -159,6 +160,8 @@ for cset in range(int(tip) + 1): (fdcomment, filecomment) = tempfile.mkstemp() csetcomment = os.popen('hg log -r %d -v | grep -v ^changeset: | grep -v ^parent: | grep -v ^user: | grep -v ^date | grep -v ^files: | grep -v ^description: | grep -v ^tag: | grep -v ^branch:' % cset).read().strip() + if (previous_comment): + csetcomment += previous_comment os.write(fdcomment, csetcomment) os.close(fdcomment)
@@ -181,8 +184,8 @@ for cset in range(int(tip) + 1): print 'tag:', tag print '-----------------------------------------' - # checkout the parent if necessary - if cset != 0: + # checkout the parent if there is a repo to checkout from + if hgvers.has_key("0"): if hgbranch[str(cset)] == "branch-" + str(cset): print 'creating new branch', hgbranch[str(cset)] os.system('git-checkout -b %s %s' % (hgbranch[str(cset)], hgvers[parent]))
@@ -210,6 +213,14 @@ for cset in range(int(tip) + 1): # delete removed files os.system('git-ls-files -x .hg --deleted | git-update-index --remove --stdin') + # is there something that git will commit (maybe just empty dir was added) + stat = os.system('git-status -a') + if (stat != 0): + print "No changes git notices, will combine log with next commit (maybe empty dir?)" + previous_comment = "\n\n--- hg-to-git merged commit ---\n\n" + csetcomment + continue + previous_comment = None + # commit os.system(getgitenv(user, date) + 'git-commit -a -F %s' % filecomment) os.unlink(filecomment)
Signature · 1 line
1.5.2.4
Quoted 3 lines · Mark Drago
This patch will detect that there are no changes to commit (using git-status), and will not perform the commit, but will instead combine the log messages of that (non-)commit with the next commit.
I think a better approach would be to implement --no-tree-change-is-ok option to git-commit, strictly for use by foreign scm interface scripts like yours. It does not usually make sense to record a commit that has the exact same tree as its sole parent commit and that is why git-commit prevents you from making that mistake, but when data from foreign scm is involved, it is a different story. We are equipped to represent such a (perhaps insane, perhaps by mistake, or perhaps done on purpose) change and it is better to represent it bypassing the safety valve for native use.
PATCH 1/1 git-commit --allow-empty
It does not usually make sense to record a commit that has the exact same tree as its sole parent commit and that is why git-commit prevents you from making such a mistake, but when data from foreign scm is involved, it is a different story. We are equipped to represent such an (perhaps insane, perhaps by mistake, or perhaps done on purpose) empty change, and it is better to represent it bypassing the safety valve for native use.
This is primarily for use by foreign scm interface scripts.
---
* This is for 'next', on top of an earlier "allow amending '-s ours' merge".
Documentation/git-commit.txt | 8 +++++++- builtin-commit.c | 5 +++-- 2 files changed, 10 insertions(+), 3 deletions(-)
Documentation/git-commit.txt +7 -1
@@ -10,7 +10,7 @@ SYNOPSIS [verse] 'git-commit' [-a | --interactive] [-s] [-v] [-u] [(-c | -C) <commit> | -F <file> | -m <msg> | --amend] - [--no-verify] [-e] [--author <author>] + [--allow-empty] [--no-verify] [-e] [--author <author>] [--] [[-i | -o ]<file>...] DESCRIPTION
@@ -89,6 +89,12 @@ OPTIONS This option bypasses the pre-commit hook. See also link:hooks.html[hooks]. +--allow-empty:: + Usually recording a commit that has the exact same tree as its + sole parent commit and the command prevents you from making such + a mistake. This option bypasses the safety, and is primarily + for use by foreign scm interface scripts. + -e|--edit:: The message taken from file with `-F`, command line with `-m`, and from file with `-C` are usually used as the
builtin-commit.c +3 -2
@@ -46,7 +46,7 @@ static enum {static char *logfile, *force_author, *template_file;static char *edit_message, *use_message;static int all, edit_flag, also, interactive, only, amend, signoff; -static int quiet, verbose, untracked_files, no_verify; +static int quiet, verbose, untracked_files, no_verify, allow_empty;static int no_edit, initial_commit, in_merge;const char *only_include_assumed;
@@ -87,6 +87,7 @@ static struct option builtin_commit_options[] = {OPT_BOOLEAN ('n' ,"no-verify" , &no_verify,"bypass pre-commit hook" ),OPT_BOOLEAN (0 ,"amend" , &amend,"amend previous commit" ),OPT_BOOLEAN (0 ,"untracked-files" , &untracked_files,"show all untracked files" ), +OPT_BOOLEAN (0 ,"allow-empty" , &allow_empty,"ok to record an empty change" ), OPT_END() };
@@ -710,7 +711,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) }if (!prepare_log_message (index_file, prefix) && !in_merge && - !(amend &&is_a_merge (head_sha1))) { + !allow_empty && !(amend &&is_a_merge (head_sha1))) {run_status (stdout, index_file, prefix);rollback_index_files ();unlink (commit_editmsg);
Signature · 1 line
1.5.3.7-2077-ga07a
PATCH 1/1 git-commit --allow-empty
It does not usually make sense to record a commit that has the exact same tree as its sole parent commit and that is why git-commit prevents you from making such a mistake, but when data from foreign scm is involved, it is a different story. We are equipped to represent such an (perhaps insane, perhaps by mistake, or perhaps done on purpose) empty change, and it is better to represent it bypassing the safety valve for native use.
This is primarily for use by foreign scm interface scripts.
---
* And this is for 'master'.
Documentation/git-commit.txt | 8 +++++++- git-commit.sh | 13 ++++++++++--- t/t7501-commit.sh | 7 +++++++ 3 files changed, 24 insertions(+), 4 deletions(-)
Documentation/git-commit.txt +7 -1
@@ -10,7 +10,7 @@ SYNOPSIS [verse] 'git-commit' [-a | --interactive] [-s] [-v] [-u] [(-c | -C) <commit> | -F <file> | -m <msg> | --amend] - [--no-verify] [-e] [--author <author>] + [--allow-empty] [--no-verify] [-e] [--author <author>] [--] [[-i | -o ]<file>...] DESCRIPTION
@@ -89,6 +89,12 @@ OPTIONS This option bypasses the pre-commit hook. See also link:hooks.html[hooks]. +--allow-empty:: + Usually recording a commit that has the exact same tree as its + sole parent commit and the command prevents you from making such + a mistake. This option bypasses the safety, and is primarily + for use by foreign scm interface scripts. + -e|--edit:: The message taken from file with `-F`, command line with `-m`, and from file with `-C` are usually used as the
git-commit.sh +10 -3
@@ -74,6 +74,7 @@ trap ' all= also= +allow_empty=f interactive= only= logfile=
@@ -114,6 +115,10 @@ do -a|--a|--al|--all) all=t ;; + --allo|--allow|--allow-|--allow-e|--allow-em|--allow-emp|\ + --allow-empt|--allow-empty) + allow_empty=t + ;; --au=*|--aut=*|--auth=*|--autho=*|--author=*) force_author="${1#*=}" ;;
@@ -515,9 +520,11 @@ else # we need to check if there is anything to commit run_status >/dev/null fi -case "$?,$PARENTS" in -0,* | *,-p' '?*-p' '?*) - # a merge commit can record the same tree as its parent. +case "$allow_empty,$?,$PARENTS" in +t,* | ?,0,* | ?,*,-p' '?*-p' '?*) + # an explicit --allow-empty, or a merge commit can record the + # same tree as its parent. Otherwise having commitable paths + # is required. ;; *) rm -f "$GIT_DIR/COMMIT_EDITMSG" "$GIT_DIR/SQUASH_MSG"
t/t7501-commit.sh +7 -0
@@ -256,6 +256,13 @@ test_expect_success 'same tree (single parent)' ' ' +test_expect_success 'same tree (single parent) --allow-empty' ' + + git commit --allow-empty -m "forced empty" && + git cat-file commit HEAD | grep forced + +' + test_expect_success 'same tree (merge and amend merge)' ' git checkout -b side HEAD^ &&
Signature · 1 line
1.5.3.7-2077-ga07a
Re: [PATCH] git-commit --allow-empty
In reply to Junio C HamanoDocumentation/git-commit.txt OPTIONS · line 96
Quoted 5 lines · Junio C Hamano
+--allow-empty::
Documentation/git-commit.txt +4
-0+ Usually recording a commit that has the exact same tree as its + sole parent commit and the command prevents you from making such + a mistake. This option bypasses the safety, and is primarily + for use by foreign scm interface scripts.
The first sentence is rather buggy I would say.
Nicolas
Re: [PATCH] git-commit --allow-empty
Quoted 9 lines · Nicolas Pitre
Documentation/git-commit.txt OPTIONS · line 96
Quoted 5 lines · Junio C Hamano
+--allow-empty::
Documentation/git-commit.txt +4
-0+ Usually recording a commit that has the exact same tree as its + sole parent commit and the command prevents you from making such + a mistake. This option bypasses the safety, and is primarily + for use by foreign scm interface scripts.The first sentence is rather buggy I would say.
It indeed is. Sorry.
Quoted 6 lines · Junio C Hamano
Quoted 3 lines · Mark Drago
This patch will detect that there are no changes to commit (using git-status), and will not perform the commit, but will instead combine the log messages of that (non-)commit with the next commit.
Quoted 9 lines
I think a better approach would be to implement --no-tree-change-is-ok option to git-commit, strictly for use by foreign scm interface scripts like yours. It does not usually make sense to record a commit that has the exact same tree as its sole parent commit and that is why git-commit prevents you from making that mistake, but when data from foreign scm is involved, it is a different story. We are equipped to represent such a (perhaps insane, perhaps by mistake, or perhaps done on purpose) change and it is better to represent it bypassing the safety valve for native use.
So I did "git commit --allow-empty". With that, perhaps the following will fix the issue?
I won't be commiting this myself until I hear a positive Ack.
--- contrib/hg-to-git/hg-to-git.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
contrib/hg-to-git/hg-to-git.py +1 -1
@@ -211,7 +211,7 @@ for cset in range(int(tip) + 1): os.system('git-ls-files -x .hg --deleted | git-update-index --remove --stdin') # commit - os.system(getgitenv(user, date) + 'git-commit -a -F %s' % filecomment) + os.system(getgitenv(user, date) + 'git commit --allow-empty -a -F %s' % filecomment) os.unlink(filecomment) # tag
Quoted 19 lines · Junio C Hamano
Quoted 6 lines · Junio C Hamano
Quoted 3 lines · Mark Drago
This patch will detect that there are no changes to commit (using git-status), and will not perform the commit, but will instead combine the log messages of that (non-)commit with the next commit.
Quoted 9 lines
I think a better approach would be to implement --no-tree-change-is-ok option to git-commit, strictly for use by foreign scm interface scripts like yours. It does not usually make sense to record a commit that has the exact same tree as its sole parent commit and that is why git-commit prevents you from making that mistake, but when data from foreign scm is involved, it is a different story. We are equipped to represent such a (perhaps insane, perhaps by mistake, or perhaps done on purpose) change and it is better to represent it bypassing the safety valve for native use.
Quoted 4 lines
So I did "git commit --allow-empty". With that, perhaps the following will fix the issue?
I won't be commiting this myself until I hear a positive Ack.
I gave this a test and it works perfectly well. Commit away.
Thanks,
Mark.
Quoted 18 lines
--- contrib/hg-to-git/hg-to-git.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)contrib/hg-to-git/hg-to-git.py +1
-1@@ -211,7 +211,7 @@ for cset in range(int(tip) + 1): os.system('git-ls-files -x .hg --deleted | git-update-index --remove --stdin') # commit - os.system(getgitenv(user, date) + 'git-commit -a -F %s' % filecomment) + os.system(getgitenv(user, date) + 'git commit --allow-empty -a -F %s' % filecomment) os.unlink(filecomment) # tag