Reputation: 3791
I recently inherited a project and found out that the git repo tree is broken.
The first blue commit contains ALL the code of the app plus some changes in the commit.
I have two questions.
Any ideas would be appreciated.
Upvotes: 3
Views: 301
Reputation: 10667
Unrelated histories can be joined together using git filter-branch
. Here's an excerpt from the manpage:
To set a commit (which typically is at the tip of another history) to be the
parent of the current initial commit, in order to paste the other history behind
the current history:
git filter-branch --parent-filter 'sed "s/^\$/-p <graft-id>/"' HEAD
(if the parent string is empty - which happens when we are dealing with the
initial commit - add graftcommit as a parent). Note that this assumes history
with a single root (that is, no merge without common ancestors happened). If
this is not the case, use:
git filter-branch --parent-filter \
'test $GIT_COMMIT = <commit-id> && echo "-p <graft-id>" || cat' HEAD
or even simpler:
git replace --graft $commit-id $graft-id
git filter-branch $graft-id..HEAD
In your case, $commit-id
is the first blue commit and $graft-id
is the last red.
Here's an example of the complete procedure:
Let's create a repo and some red commits:
$ git init
$ echo a >a
$ git add a
$ git commit -m c1
[master (root-commit) 6a6b98f] c1
1 file changed, 1 insertion(+)
create mode 100644 a
$ echo b >>a
$ git add a
$ git commit -m c2
[master d91d385] c2
1 file changed, 1 insertion(+)
Now create an unrelated branch o1
and add some blue commits:
$ git checkout --orphan=o1
Switched to a new branch 'o1'
$ echo c >>a
$ git add a
$ git commit -m c3
[o1 (root-commit) ed2b106] c3
1 file changed, 3 insertions(+)
create mode 100644 a
$ echo d >>a
$ git add a
$ git commit -m c4
[o1 5b655a6] c4
1 file changed, 1 insertion(+)
Check that we got what we wanted:
$ git log --format=short --graph --all
* commit 5b655a615f8a729c123d89180ca1928451b465b2 (HEAD -> o1)
|
| c4
|
* commit ed2b106d7bd0ffef317a723f2921808bc8ad9f45
c3
* commit d91d385c7811ba07f4092133c435b55323562686 (master)
|
| c2
|
* commit 6a6b98fca7150839f607d9d55c6b9f10861375f8
c1
Create a graft commit for ed2b106
(c3, first blue) with d91d385
(c2, last red) as its new parent:
$ git replace --graft ed2b106d7bd0ffef317a723f2921808bc8ad9f45 d91d385c7811ba07f4092133c435b55323562686
$ git log --format=short --graph --all
* commit 5b655a615f8a729c123d89180ca1928451b465b2 (HEAD -> o1)
|
| c4
|
* commit ed2b106d7bd0ffef317a723f2921808bc8ad9f45 (replaced)
|
| c3
|
| * commit 4656e5bca003770b1a35aff10e3ffb51f7fb1ad9
|/
| c3
|
* commit d91d385c7811ba07f4092133c435b55323562686 (master)
|
| c2
|
* commit 6a6b98fca7150839f607d9d55c6b9f10861375f8
c1
We got 4656e5b
(fixed c3) as a replacement with fixed parents, but that replacement is only local, so we now need to rewrite all the blue commits:
$ git filter-branch d91d385c7811ba07f4092133c435b55323562686..HEAD
Rewrite 5b655a615f8a729c123d89180ca1928451b465b2 (2/2) (0 seconds passed, remaining 0 predicted)
Ref 'refs/heads/o1' was rewritten
$ git log --format=short --graph
* commit 2cf6b0d3a0ee2deff99bbe327d065f90c82c1c2b (HEAD -> o1)
|
| c4
|
* commit 4656e5bca003770b1a35aff10e3ffb51f7fb1ad9
|
| c3
|
* commit d91d385c7811ba07f4092133c435b55323562686 (master)
|
| c2
|
* commit 6a6b98fca7150839f607d9d55c6b9f10861375f8
c1
The 4656e5b
(fixed c3) was already good (same as ed2b106
, the original c3, just with different parent), but 5b655a6
(c4) was rewritten so that its parent is 4656e5b
(fixed c3) instead of ed2b106
(original c3). We can now safely drop the replacement as ed2b106
is no longer used in our history:
$ git replace -d ed2b106d7bd0ffef317a723f2921808bc8ad9f45
Deleted replace ref 'ed2b106d7bd0ffef317a723f2921808bc8ad9f45'
Upvotes: 2