1

I have two Git repositories with separate histories. After much researching and a lot of tinkering, I wound up with a history that looks like this (using YYYY-DD as pseudo commit-hashes):

HEAD---2016-09---2016-08---2016-07---2016-06
                     \-----2015-10---2015-09

Note that this history appears to have two "roots", as the 2015-10 sequence was merged/grafted into the middle. The important thing is that the files in the 2016-07 history and the 2015-10 history contain completely different files with nothing in common.

I would like to combine this history into one complete line of commits, in original commit order from oldest to newest, with no skips (i.e. disappearing content that reappears later). In other words, here is what I want to end up with:

HEAD---2016-09---(2016-08)---2016-07---2016-06---2015-10---2015-09

I put (2016-08) in parentheses, because as a merge commit I don't even think I need it if all goes correctly.

At first I thought do a git replace --edit 2016-08 to remove its 2015-10 parent, and then a git replace --edit 2016-06 to put the 2015-10 as its parent (see https://stackoverflow.com/a/37001417/421049), and sure enough, after doing a git filter-branch --tag-name-filter cat -- --all I got a single sequence that looked like what I wanted.

But then I started thinking: because the content was completely different in the two "tails", won't the content in 2015-10 "disappear" in 2016-06 and then "come back" in 2016-08? (I confess I can't immediately verify whether it did or not right now; I erased that attempt and I'm too tired to do it again tonight.) How can I effectively "merge" (in the everyday sense) the two tails, as if the content in 2016-06 was added onto the content in 2015-10? That is, whatever commit that replaces 2016-06 will have all the content in 2015-10 along with the content in the original 2016-06? However I want the new 2016-06 to have its original commit date, log message, etc.

Then, after that's done, how do I remove the "merge" commit 2016-08 from the history, as it's not needed anymore? I assume I can use git rebase --onto 2016-08~ 2016-08 HEAD from https://stackoverflow.com/a/3705310/421049. I tried it in the initial attempt, but it didn't work --- I assume it had something to do with the content that "disappeared" in 2016-07 and 2016-06 because I just restitched the tails in a different sequence, but I'm not sure.

I apologize if this is a duplicate question, but after hours of working with this and getting deep into histories (and gingerly poking around in vi), I have a little "Git fatigue" for the day. Thank you in advance.

Community
  • 1
  • 1
Garret Wilson
  • 18,219
  • 30
  • 144
  • 272

1 Answers1

2

on a simplified example, i was able to

git checkout -b middle 2016-07
git rebase 2015-10

this replays your commits 2016-07 and 2016-06 on top of 2015-10

git checkout master

assuming your master points to 2016-09 or a descendant

git rebase middle

wich replays 2016-09 (or more, depending on your master) on top of the new middle we just created. this rebase will also discard the merge commit.

if, as you say, the files in the 2016-07 history and the 2015-10 history contain completely different files with nothing in common this should give you a nice history without conflicts.

lucanLepus
  • 161
  • 1
  • 7
  • Wow, thank you---I have no idea the magic going on here, but it seems to work! Everything lined up in order, and even the merge commit is gone. The only oddity is that in Bitbucket while all the commits from the `2015-10` commit on back show the correct date in the timeline, everything from `2016-06` forward shows a date of "X minutes ago" in Bitbucket. Yet the raw commits seem to have the correct dates, and they show up correctly in Git and TortoiseGit. Any idea why? In any case I'm going to add a bounty just to reward you or whomever winds up with the answer. – Garret Wilson May 14 '17 at 23:51
  • I dont know much about bitbucket, but this could be related to bitbucket tracking (and showing you) when a commit was actually pushed to it. The commits after 2015-10 got rebased, this changed their parent commits and thereby the commit-id - for bitbucket these could be considered "new". 2015-10 - 2015-09 didnt get changed, still the same commit-id. So that could explain the discepancy in your display. – lucanLepus May 15 '17 at 16:03
  • That makes sense. @lucanLepus, this is so awesome --- I'm just waiting until Stack Overflow lets me put a bounty on this so I can reward your answer. In the meantime, the last thing I have to do is reorder a few commits (which were entered manually after the fact, with the correct back-dated timestamps). I suppose I'll do a manual, interact rebase --- there only a few commits out of order. If you have any tips for this let me know. – Garret Wilson May 15 '17 at 17:23
  • reordering with interactive rebase is pretty straight forward, the command line version lets you just move the lines around, most guis do drag&drop. re-dating commits i have never done, but e.g. [this answer](http://stackoverflow.com/questions/454734/how-can-one-change-the-timestamp-of-an-old-commit-in-git/5017265#5017265) should get you through it – lucanLepus May 15 '17 at 18:32