简体   繁体   中英

Git: Rebase a complete project including branch structure

In a project which is to be transferred from Mercurial to git, a Mercurial-specific file (pretty early in the history) needs to be rewritten ( X in the diagram below). After this step, the whole history should be transferred as if that file had always been in its new state, luckily this should not result in any merge conflicts on its own.

A---B---X
     \
      \--C---D---G---H          master
          \     /
           E---F---I            feature_branch

should result in

A---B---X---C'---D'---G'---H'   master
             \       /
              E'----F'---I'     feature_branch

The closest I could get was to rebase master onto X with the -p option, but that still produced a merge conflict for G' , although the diff from D to G could have been applied without problems.

Rebase is not the right tool for such complex history rewriting. filter-branch is the right tool for this. The easiest way is probably to put your file in some folder not in your repo and the run a tree filter on --all --not A that copies that file into your working dir.

Based on Chronial's answer, this were the commands I used (after doing a backup of course):

B=abcd
X=1234
git filter-branch --parent-filter "sed -e s/$B/$X/g" --tree-filter \
  "git checkout X $(git diff-tree --no-commit-id --name-only -r $X | tr '\n'  ' ')" \
  -- --all --not X

Here, first all parent references to B are replaced by references to X , then the files changed by this commit are inserted into the tree. This operation is applied into all revisions which are not ancestors of X themselves.

And then, after checking that everything worked as expected and after making another backup (in case I ever need it in the future for reference):

git for-each-ref --format='%(refname)' refs/original | xargs -n1 git update-ref -d

This removes all the refs/original/... refs which are created for backup purposes automatically by git filter-branch .

If one wants to irrevocably remove all traces of the previous history and save on disk space, now might be a good time to collect the garbage:

git gc --prune=now

Instead of writing a detailed solution someone else made ny answer very easy. This is a visual (interactive tutorial) that will explain to you what you need to do.

http://pcottle.github.io/learnGitBranching/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM