From 20385ead8f4167bb3becca5a5d861aa9612c22ae Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Tue, 5 Mar 2019 11:00:40 -0800 Subject: [PATCH] filter-repo: allow rename collision if files are identical We previously would abort if we had been requested to rename files and that caused two different files to go to the same path. However, if the files have identical contents and mode, then we can treat the request as a desire from the user to just coalesce the extra copies. Signed-off-by: Elijah Newren --- git-filter-repo | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/git-filter-repo b/git-filter-repo index 9351b34..ad84250 100755 --- a/git-filter-repo +++ b/git-filter-repo @@ -2843,16 +2843,30 @@ class RepoFilter(object): continue # Filtering criteria excluded this file; move on to next one if change.filename in new_file_changes: # Getting here means that path renaming is in effect, and caused one - # path to collide with another. That's usually bad, but sometimes - # people have a file named OLDFILE in old revisions of history, and they - # rename to NEWFILE, and would like to rewrite history so that all - # revisions refer to it as NEWFILE. As such, we can allow a collision - # when (at least) one of the two paths is a deletion. Note that if - # OLDFILE and NEWFILE are unrelated this also allows the rewrite to - # continue, which makes sense since OLDFILE is no longer in the way. + # path to collide with another. That's usually bad, but can be okay + # under two circumstances: + # 1) Sometimes people have a file named OLDFILE in old revisions of + # history, and they rename to NEWFILE, and would like to rewrite + # history so that all revisions refer to it as NEWFILE. As such, + # we can allow a collision when (at least) one of the two paths + # is a deletion. Note that if OLDFILE and NEWFILE are unrelated + # this also allows the rewrite to continue, which makes sense + # since OLDFILE is no longer in the way. + # 2) If OLDFILE and NEWFILE are exactly equal, then writing them + # both to the same location poses no problem; we only need one + # file. (This could come up if someone copied a file in some + # commit, then later either deleted the file or kept it exactly + # in sync with the original with any changes, and then decides + # they want to rewrite history to only have one of the two files) + colliding_change = new_file_changes[change.filename] if change.type == 'D': # We can just throw this one away and keep the other continue + elif change.type == 'M' and ( + change.mode == colliding_change.mode and + change.blob_id == colliding_change.blob_id): + # The two are identical, so we can throw this one away and keep other + continue elif new_file_changes[change.filename].type != 'D': raise SystemExit("File renaming caused colliding pathnames!\n" + " Commit: {}\n".format(commit.original_id) +