开发者

git: how to re-order (severely) a commit sequence

I'm building a retrospective project history from zip snapshots. I have already built a long branc开发者_JS百科h sequence of commits from snapshots that were to hand. I have now added at the end some more 'found' snapshots that should be at various places 'in the middle' of the commit sequence.

I'm trying to use the git rebase -i <startCommit> to re-order the git snapshots. I simply swap around the pick list order. This should be simply a case of re-writing the commit objects, but keeping the underlying trees the same (because the snapshots haven't changed).

It looks like rebase, in this case, is still trying to create patches and having lots of conflicts, rather than doing the simple re-arrangement. Is there a more appropriate command for this particular case? I have no merges, and only the one branch. The whole repo is still very local and private.


don't bother with rebase. Make a new branch. If X is sha1 or treeish of commit to use, then:

git checkout X -- .
git add -A
git commit -C X

Repeat for all commits in the chronological order that you want.

An example where we reverse the order of the last 5 commits:

git checkout -b temp old_branch~5
git checkout old_branch -- .
git add -A
git commit -C old_branch
git checkout old_branch~1 -- .
git add -A
git commit -C old_branch~1
git checkout old_branch~2 -- .
git add -A
git commit -C old_branch~2
git checkout old_branch~3 -- .
git add -A
git commit -C old_branch~3
git checkout old_branch~4 -- .
git add -A
git commit -C old_branch~4

git push . HEAD:old_branch -f
git checkout old_branch
git branch -d temp

git log -5 # to see the new history

hope this helps.


I can't help make the rebase easier, but I can explain why it isn't a "simple re-arrangement." As an example, take one file that has one line of text appended per revision. On the first commit, it looks like:

Commit 1

On the second commit, since you originally put them out of order, it looks like:

Commit 1
Commit 2
Commit 3

On the third commit, which was your second snapshot, it looks like:

Commit 1
Commit 2

Git is dealing with patches, so to git, the series of commits looks like:

  • Add a file with a line that says "Commit 1"
  • Add lines that say "Commit 2" and "Commit 3" after the line that says "Commit 1"
  • Remove the line that says "Commit 3" after the line that says "Commit 2"

When you reorder it, it looks like:

  • Add a file with a line that says "Commit 1"
  • Remove the line that says "Commit 3" after the line that says "Commit 2"
  • Add lines that say "Commit 2" and "Commit 3" after the line that says "Commit 1"

It gets to the second step, sees no lines with "Commit 2" to match against, doesn't know what to do, so requires a manual merge.

You manually resolve the merge, then on the next step, git sees 2 lines where it was expecting one, and again requires a manual merge.


If your history looks like this:

a->b->c->d->e->f

Where e and f are supposed to be placed somewhere in between a and d

You can still do the rebase -i, but put editon the commit before where you want the snap shot inserted. When git pauses for that edit, place the snapshot in your working dir and add/commit it. Continue the rebase till the next spot, rinse, repeat.

In case it needs to be said, you will also want to remove the initially misplaced commits, e and f, that deal with the misplaced snap shots.


Tried a lot of options and answers, checkouts and resets during re-base conflict instead of manual fixes. Tried to do this without manual steps and without workarounds. However, most intuitive and transparent way to prevent git from interfering your files appears to be an empty commit:

git: how to re-order (severely) a commit sequence

Let's say task is to insert v3 into history:

  • go to v5, do clean checkout, do manual backup of v5
  • go to v3, delete all files, commit empty
  • start re-base (main to master)
  • if case is complicated (which is supposed if this SO question was found), conflict will occur immediately; Unstage all files, delete, copy from v5 backup, stage all, add ignored; Before re-base continues, ensure that project folder is equal to v5 backup folder
  • continue re-base (changing commit messages may be necessary?)

Still had errors in the end, but checkouts were finally same.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜