-1

The target commit may have parents and descendants.

it needs to replace the old commit in place,

so it's not as simple as cherry command.

My question will wait for an exact solution.

asker
  • 2,159
  • 3
  • 22
  • 27
  • The hash of a given commit depends upon a bunch of things including the content, author, date, and the hash of its parent. If you change a commit's hash (by `--amend` or rebasing) this will also change the hashes of all of its "children". You can fake this with grafts, but I think the *precise* thing you're asking for isn't possible. – nickgrim Aug 16 '11 at 10:08
  • Maybe you could tell us the problem you're trying to solve (rather than the solution that you want)? – nickgrim Aug 16 '11 at 10:09

3 Answers3

4

No, you can't do that.

The point of SHA-1 is to prevent changes like these. The whole git architecture depends on the assumption that SHA-1 uniquely identify the object in all git repository. No way to workaround this (not without redesigning everything, that is).

The details are explained in the Git Magic book.

J-16 SDiZ
  • 26,473
  • 4
  • 65
  • 84
  • It's very improbable,but it still has the CHANCE. That's what my question bases upon. – asker Aug 16 '11 at 07:53
  • 1
    It is to "... prevent accidental or malicious data corruption.". Computer see changes as changes, what you are doing is just the same as "malicious data corruption". There were some discussion on that on the git list, search for SHA-512 on it. – J-16 SDiZ Aug 16 '11 at 07:55
  • 1
    Please refer to the comments under this answer if you have problem understanding it MAY happen(though the chance is slim): http://stackoverflow.com/questions/7062192/about-gits-merge-and-rebase/7062773#7062773 – asker Aug 16 '11 at 07:57
  • Just as a matter of fact. Git does not store *changes* (as `diff`, like cvs do), it store the *state* (the `treeish` thingy). If you want to (let's say) delete a file, you need to change all the commit containing the file. – J-16 SDiZ Aug 16 '11 at 07:59
  • I DO know that git stores snapshot instead of delta,thanks to the previous answer:) – asker Aug 16 '11 at 08:01
  • @asker: I agree with J-1's answer, and don't think you will find another solution. A `rebase --interactive` to remove the commit you don't want, plus a `git fetch` remains your best bet... but it is hardly an 'in place' solution. – VonC Aug 16 '11 at 08:09
  • Right,to make it `in place` needs to change the parent and son of a specific node. – asker Aug 16 '11 at 08:12
  • Or, if you so hated that commit. You can remove the commit object file, then `git-log` will never show up that commit again. The drawback would be.... you don't be able to do `push`/`pull` (like a shadow `git clone --depth` repository) – J-16 SDiZ Aug 16 '11 at 08:20
  • I don't hate it,just want to change it's SHA-1.I know it's not available out of the box, the work-around is to `cherry` another commit with the same content,and then **replace that old commit**.But how to do the step in bold? – asker Aug 16 '11 at 08:28
  • @asker, ok, lets see my new answer is better. For me, it is too ugly to be considered "works". – J-16 SDiZ Aug 16 '11 at 09:59
0

I'm not familiar with Git but in Mercurial, you can do this: Pop the latest commit from the repository and save it in a "patch" (hg qimport). The result is the repo without any trace of the latest commit plus a patch that would give you the starting state.

So the recipe would be to pop stuff from the repo until the commit to modify becomes HEAD. Pop that, too, modify the patch (or apply the patch without commit and modify the workspace).

Now you can commit the new version and apply all the other patches.

Since Git and Mercurial are very similar, there is probably a Git command to achieve the same but I don't know its name. Maybe this answer can help: https://serverfault.com/questions/12373/how-do-i-edit-gits-history-to-correct-an-incorrect-email-address-name

Community
  • 1
  • 1
Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • Changing others' commit is not polite maybe...it's better to change only your own commit. – asker Aug 16 '11 at 08:35
  • "Better" is the wrong term. If your new commit collides with the commit of someone else, you will have to make changes. This isn't an issue of "good/bad" but of pure mathematics. If that doesn't suit you, Git, Mercurial and any other DVCS isn't the right tool for you. – Aaron Digulla Aug 16 '11 at 08:40
  • Git can do this too (before Hg do). But the asker want to keep the commitid (the long one, not the local single number one) -- I don't think Hg can do that. – J-16 SDiZ Aug 17 '11 at 01:40
  • @J-16: I don't see where he says he wants to keep the commit ID. The question says "How to *change* the SHA-1..." – Aaron Digulla Aug 17 '11 at 08:57
0

Okay, let's see if this helps.

WARNING:

  • This break (some) pull / push / fetch.
  • Not all git command support this.
  • It does not share with other users.
  • This does not change the commit, it replace it.

Are you sure you want to do this? Scroll down if yes.


This is called graft point. You create a file .git/info/grafts and have the following info:

<commit-id> <new-parent-of-the-commit>

Let's say you have this:

/---D
A---B---C

Now you want to replace B with D (without changing the commit id), you put this in graft:

<commit-id-of-C> <commit-id-of-D>

It keeps the old commitid, with the limitation stated above.

J-16 SDiZ
  • 26,473
  • 4
  • 65
  • 84
  • (And I lied again, git 1.6.6 have `git-replace`. But it is **even uglier**. So ugly that I won't try to explain it. Check the ProGit blog if you want) – J-16 SDiZ Aug 16 '11 at 10:02
  • You can make it permanent with `git filter-branch` but that does re-write the commit SHA1 values, which you said you didn't want... – Philip Oakley Aug 16 '11 at 15:36