Skip to content

Instantly share code, notes, and snippets.

@oconnor663
Created October 4, 2017 17:02
Show Gist options
  • Save oconnor663/8ef94b337a1614e40969f7a3ff2bffba to your computer and use it in GitHub Desktop.
Save oconnor663/8ef94b337a1614e40969f7a3ff2bffba to your computer and use it in GitHub Desktop.
edit a git commit without changing the hash
#! /bin/bash
d="$(mktemp -d)"
# Make a git repo with one file in it.
mkdir "$d/good"
cd "$d/good"
git init
echo good > file.txt
git add -A
git commit -m "first commit"
# Copy the whole thing.
cp -r "$d/good" "$d/bad"
# Go in the copy and edit the object that holds file.txt. Its path is always
# the same because, unlike the commit object, it doesn't contain any
# timestamps.
# NOTE: The blob object contains its own length, so if we wanted to substitute
# something other than another 4 bytes in there, we'd need to edit the length
# too.
file_hash_path=".git/objects/12/799ccbe7ce445b11b7bd4833bcc2c2ce1b48b7"
chmod +w "$d/bad/$file_hash_path"
cat "$d/good/$file_hash_path" \
| python2 -c "import zlib, sys; sys.stdout.write(zlib.decompress(sys.stdin.read()))" \
| sed 's/good/💩/' \
| python2 -c "import zlib, sys; sys.stdout.write(zlib.compress(sys.stdin.read()))" \
> "$d/bad/$file_hash_path"
echo "Here's a commit from the good repo:"
echo
git -C "$d/good" show -p
echo
echo "And here's "the same commit" from the bad repo:"
echo
git -C "$d/bad" show -p
@y-nk
Copy link

y-nk commented May 9, 2019

@oconnor663 could this also be used to remove the root commit ?

@oconnor663
Copy link
Author

I'm not sure I understand the question. Could you say more?

@y-nk
Copy link

y-nk commented May 9, 2019

@oconnor663 i'm looking for a way to change/delete the root commit of a repo without rebasing (which would change the hash of the following commits). i'm still experimenting with this script to fix the root commit of the repo i work on (the author info has some typos) ; in case i can't achieve fixing it, i was willing to delete the root commit.

The reason why i want to avoid rebasing is to avoid loosing the git(hub) history (closed/merged PR, snippets linked to hashes, etc...) of this repo but at the same time i'm just trying to fix old mistakes made 250+ commits ago...

(edit: i edited the original question for clarity, in case someone drops by later)

@oconnor663
Copy link
Author

I don't think you'll be able to get away with that. Git is willing to interact with bad commit objects locally, but usually once you try to transfer them over the network protocol (i.e. push them to GitHub), they get rejected. (If they didn't, that would be a fairly massive oversight by the GitHub security team.)

@y-nk
Copy link

y-nk commented May 22, 2019

@oconnor663 thanks for clarification :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment