13

Imagine a scenario where a project has an existing git tree you're 100% satisfied with. Now you discover some ancient source code predating migration to git and would like to make it a part of git history.

There are many ways how to achieve this but to my knowledge it always ends up with a new git tree, i.e. where all the existing commits have different IDs.

In this specific case it doesn't seem to be necessary, I'm not changing anything but the first commit's parent. Is there a way to do this?

Miro Kropacek
  • 2,742
  • 4
  • 26
  • 41
  • As far as I know, no, if you even changed one letter of a commit author's name from a commit a year old, you would have to reapply everything on top of that commit. But, if you can tolerate a deep rebase like this or maybe a filter-branch, then why do the actual SHA-1 hashes matter to you? – Tim Biegeleisen Aug 20 '17 at 11:39
  • Sure, it's more a convenience than a technical issue -- for instance if you have a github repo and some of the issues point to specific commit IDs in a comment, the URLs would become invalid after such change. – Miro Kropacek Aug 20 '17 at 11:44
  • 1
    Got it...let me upvote you...maybe VonC or @torek will have an answer. – Tim Biegeleisen Aug 20 '17 at 11:44
  • 2
    See https://git-scm.com/docs/git-replace and https://git-scm.com/book/en/v2/Git-Tools-Replace – ElpieKay Aug 20 '17 at 13:58
  • Tip: use tags rather than commit id's for use in your URLs. – cst1992 Aug 21 '17 at 10:35
  • @ElpieKay just noticed your comment, wow, what an excellent suggestion. Feel free to post it as an answer! – Miro Kropacek Feb 15 '20 at 10:31

3 Answers3

25

No, this is fundamentally impossible. A commit’s id is the hash of its combined content. That includes not only the whole tree and file content, but also the commit message, author information, and the reference to its parent.

So by changing the parent of a commit, you are changing its content and as such invalidate its previous id. Git will have to recalculate its hash in order to integrate the commit into the history. Otherwise it would reject that commit as being broken and leave your repository in a broken state.

The fact that any commit id matches the hash of its content, and that this is true for any direct or indirect parent is a core part of Git’s integrity. You cannot avoid this.

So no, you cannot do what you want without affecting commit hashes. What you maybe could do is simply add another completely unrelated branch that has no connection to your current branches. That way you wouldn’t affect your existing commits but you would also have a way to integrate that old history into the repository so it would be stored inside—not integrated but at least it’s there.

poke
  • 369,085
  • 72
  • 557
  • 602
  • 1
    Exactly. In this way git behaves similar to cryptocurrencies (they are both essentially blockchains). By altering a commit deep in the branch, you are doing the same as altering a bitcoin transaction. This should not be done and it is more than welcome that by changing every future commit's hash, this commit change will not go unnoticed. There still is a difference compared to bitcoin; git does not require proof of work, so rebase is possible. – jg6 Jun 18 '20 at 15:55
  • @sijanec Yes, there is a common aspect with blockchains, although I personally don’t think Git is a blockchain but that they both just share underlying principles. I’ve covered that in [another answer](https://stackoverflow.com/a/46195087/216074) :) – poke Jun 19 '20 at 04:03
  • Git _could_ allow commits' metadata to contain a list of "previous commit ids" which would allow rebased commits to still be resolved by their original commit-id even after rebasing or amending - I'm itching for that kind of functionality as my apps' error logs contain git hashes, which becoming broken-references (and thus useless for troubleshooting purposes) if that commit is ever rebased. – Dai Jun 07 '23 at 05:46
  • @Dai Sounds like you should just avoid rebasing commits that are used in production. Just like it’s usually the recommendation to avoid rebasing any commits that have been published since you will be breaking other contributors that way. – poke Jun 07 '23 at 20:39
1

I agree that it is almost impossible, but it would be technically possible.

You should create a commit after the old one so that after the rebase, your new commit ends up with the same hash

Of course this is quite hard to do and is not guaranteed that exists another hash, different from the current parent that satisfies this condition

Francesco
  • 4,052
  • 2
  • 21
  • 29
  • 1
    Even though it’s possible to find hash collision, finding a hash collision for a fixed hash (in this case the original root commit hash) is incredibly difficult, specially with SHA1. And I would actually go that far to say that a collision that is not only a valid commit but also matches OP’s history they want to import, is **practically impossible** to find. – poke Aug 20 '17 at 14:18
  • In fact I said technically possible. Answered just for sake of knowledge, but it seems that my answer is not liked so I will delete it eventually – Francesco Aug 20 '17 at 14:20
  • @Francesco Don't delete your answer, it makes the situation worse and irreversible. If anybody feels that it's wrongly downvoted, they'll upvote it. But if you delete the answer, you'll prevent that. – cst1992 Aug 21 '17 at 10:37
  • @cst1992 Please [do *not* upvote just to cancel out downvotes](https://meta.stackoverflow.com/q/311406/216074). That’s not what votes are for. Up-/downvote based on the post, not on the score. – poke Aug 22 '17 at 06:12
  • @poke You misunderstand me. I upvoted because I felt I should, not because the post had downvotes. In other words, even if the post had 0, 1 or 2 upvotes, I would've upvoted it anyway. – cst1992 Aug 22 '17 at 08:51
  • @cst1992 Okay yeah, then I misunderstood you. You made it sound like you were expecting people to “correct” the downvotes. (For what it's worth, I didn't downvote this post) – poke Aug 22 '17 at 09:38
  • @poke My only intention is to tell the OP to let the community decide on the whole. – cst1992 Aug 22 '17 at 09:39
-2

yes, If you want to save the existing commit hashes: Just create a new_branch before you rebase the current branch. So that when you checkout to new_branch all the history will be seen.