Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Really flatten a git merge

There're few question about "flattening merge" on StackOverflow, with an answer usually being "git rebase". These answers though miss one crucial point - order of commits.

Suppose there's a branch A with commits of Jun 1 and Aug 1, and branch B with commit of Jul 1 (UPDATE to reinstate the usecase described below: branches are fully independent and don't have common ancestry, for example coming from 2 different repositories). When merging B into A, there will be following history (per git log):

Merged branch 'B'
Aug 1
Jul 1
Jun 1

Now, what I'm looking for is the way to get the same result, but without merge commit (and thus with underlying linear history in that order, and yes, that means re-parenting commits). git rebase doesn't help here, as with it, you will get following histories:

Jul 1
Aug 1
Jun 1

or

Aug 1
Jun 1
Jul 1

In other words, git rebase always stacks one branch on top of another, while I'm looking for solution which will intersperse commits sorted by author's commit date.

Apparently, for simple cases, needed arrangement can be achieved by manually postprocessing git rebase with git rebase -i, but that's not practical for large histories, so I'd be looking for automated command/script.

Usecase? If A and B represent different parts of the same project which happened to be in different repos and time has come to correct that by merging them together, then it's natural to want the linear history unfolding in the actual order of development.

like image 632
pfalcon Avatar asked Sep 04 '12 19:09

pfalcon


1 Answers

After some thinking, I figured out how to do How do I run git rebase --interactive in non-interactive manner? , which also provides completely scripted solution for this question.

1. Bring 2 branches from different repositories into one repository (git remote add + git fetch)

2. Rebase (non-interactively) one branch on top of another (order matters, consider first commit of which branch you'd like to have as first commit of consolidated branch).

3. Prepare following script (rebase-reoder-by-date):

#!/bin/sh
awk '
/^pick/ {
            printf "%s %s ", $1, $2;
            system("echo -n `git show --format='%ai' -s " $2 "`");
            for (i = 3; i <= NF; i++) printf " %s", $i; printf "\n";
        }
' $1 | sort -k3 > $1.tmp
mv $1.tmp $1

4. Run: GIT_SEQUENCE_EDITOR=./rebase-reoder-by-date git rebase -i <initial commit>

Disclaimer: all these operations should happen on copies of original repositories, review/validate/test combined branch to make sure it is what you expected and contains what you expect, keep backups handy.

like image 163
pfalcon Avatar answered Oct 17 '22 02:10

pfalcon