43

I created a Gist on GitHub and I saw information I don't want anyone to see. I updated the file since, but everybody can still access the old revision of the file.

Except deleting the Gist, is there a way to delete that particular revision definitely?

I saw that I'm not the only one having that kind of problem (Git: delete a single remote revision) but I didn't manage to remove the revision. The process indicated here seems to help remove some files. I want to remove the whole revision.

Zeitounator
  • 38,476
  • 7
  • 53
  • 66
Cyril N.
  • 38,875
  • 36
  • 142
  • 243

8 Answers8

37

Github has a help page about removing sensitive data:

http://help.github.com/removing-sensitive-data/

As gists are just git repositories, you should be able to locally clone your gist, do the clean-up there and do a forced push to overwrite the github version with the cleaned repo.

Yes, after thinking about it: If <commit> is the commit you want to "remove", do

 git rebase -i <commit>^

mark the line for <commit> as edit, save and quit.

git will set up the working directory to the state after you comitted <commit>. Fix the file, use git add and git commit --amend to fix the commit. Then do git rebase --continue. If the only thing, the next commit did, was to remove the sensitive data, it will probably be automatically dropped because it doesn't contain any changes after the now-amended commit.

Then, do a git push -f to force the update (because it is now non-fast-forward, meaning it changes already published git history).

Tilman Vogel
  • 9,337
  • 4
  • 33
  • 32
  • Thanks for your link. They didn't indicate how to remove a specific revision, but your idea of forcing an overwrite on a revision is interesting. I'll do a check and update that page regarding my results. Thanks – Cyril N. May 06 '11 at 14:39
  • What do you mean by "Then, drop the commit message from in the commit message editor." ? After changing to squash, I go back to my terminal, and then what do I do? (I'm new at Git :/) – Cyril N. May 09 '11 at 14:53
  • Ok, `git rebase -i` should first open an editor for you, listing recent commits. Initially they all have `pick` at the beginning. Change the `pick` of the successor of the unwanted commit to `squash`. Save this control file and exit the editor. Squash will merge the squashed commit into the unwanted commit. Next, git should open an editor for you listing the squashed commit messages of the unwanted commit and its successor. I guess, you want to just drop everything from the first (unwanted) commit. Save, quit. git should complete the rebase and leave you with a cleaned history. – Tilman Vogel May 09 '11 at 20:28
  • Sorry, my first reply was erroneous, I just fixed it, please read again, just in case... – Tilman Vogel May 09 '11 at 20:32
  • That's odd, after the first edit, where I indicate squash, I save and close, but I don't have an other editors that pops out, and if I redo a git rebase -i, it says the rebase has already started :/ – Cyril N. May 10 '11 at 09:21
  • Hm, what OS are you on? Maybe you need to set `GIT_EDITOR` or `git config core.editor` in order to set an editor which blocks until the edit is saved and done? In order to cancel the currently running rebase, do `git rebase --abort`. – Tilman Vogel May 10 '11 at 15:21
  • I didn't managed to make it work, I'm probably lame on that, but the time you took to help me and your complete answer is rewarded ;) – Cyril N. May 20 '11 at 07:16
  • @cx42net, you should really get git set up such that the editor invocation works right. `git rebase -i` is really a very valuable tool if used right. Also, commit message editing works the same way, so I am really puzzled what could be wrong here. – Tilman Vogel May 20 '11 at 22:45
  • Note that if your gist only has two commits, you'll probably need to do an amend instead. See http://stackoverflow.com/questions/598672/git-how-to-squash-the-first-two-commits – Peter Ehrlich Oct 25 '12 at 02:11
29

The accepted answer is good but a bit difficult to follow. Here's the same answer but a bit sweeter.

As Tilman Vogel says, gists are just repositories and so this approach works for github repositories as well as gists.

Let's assume that there is just one version that contains a password that you don't want to show. You've checked in the new version with the password removed and want to get rid of the previous version. You should be able to adapt this process if there are a number of commits showing the password.

The first thing is that the repair has to be done on your local machine (not in github). To do this start by cloning the gist locally. The gist's page on github should show you how to create a private clone if you click on the private clone URL. Something like:

git clone git@gist.github.com:421xxx1.git gist-421xxx1

This gives you a local copy that you need to rebase (meaning muck around with the versions).

cd gist-421xxx1
git rebase -i eexxaa^

Where eeccaa is the (first) version containing the password. You can get this number from the gist page revisions column. The ^ is required. The command means 'let me change the verisons from eexxaa to the latest, interactively. The command opens up an editor populated with a command on each line for each version in the repo. The default command is 'pick' meaning 'use or keep this version'.

The first lines in the editor should look something like

pick eexxaa    <- the version with the password
pick ffxxbb    <- the first version without the password

Change this to

pick eexxaa    
squash ffxxbb 

I.e. Change the word 'pick' to 'squash' on the version without the password. This will ask the rebase to squash the new (passwordless) version into the old (password carrying) one, essentially deleting version eexxaa. Obviously your versions will be other than eexxaa or ffxxbb don't literally use eexxaa or ffxxbb anywhere!

As @kand notes, you should squash every version that contained the password.

In the editor save and quit (if it's vi :x). The rebase should now open a new editor showing the commit messages for the two versions and asking for a single combined commit message. For a gist these messages are quite likely to be empty but you do need to put something in here or the rebase will abort. Type a message, save it and quit and the rebase should complete.

You now have a repository without the password-containing version. To get this back to the gist use:

git push -f

This will force the changes onto the github repo. Hit refresh and you should be able to check in the browser that the offending version has gone from the revisions column on the right hand side.

Thats it!

Mogsdad
  • 44,709
  • 21
  • 151
  • 275
meesern
  • 2,518
  • 27
  • 29
  • 1
    Not totally sure if I did this correctly, but I think you have to do the 'squash' change for every version that has the password in it. So if you have multiple versions between the first version without the password and the first version with the password, those all have to be squashed. – kand Mar 04 '13 at 19:03
  • It's possible to keep empty commit message, see https://stackoverflow.com/a/43755666/254109 – xmedeko Feb 06 '18 at 08:26
4

If you are not concerned about showing any of the revisions on the gist, you can do the following to eliminate all history and just show one revision.

git clone some-gist-repo
cd some-gist-repo
git rebase -i --root $tip

You would be able to see all the commits for that gist in your editor. Just pick the first one and replace everything else with s or squash. Once done, save and add a commit message and then do a force push to master like this and you are good.

git push -f origin master

The only revision that would be visible is the addition of file(s) and thats it.

Rafay
  • 6,108
  • 11
  • 51
  • 71
2

If you want to completely delete something from the repository you need to use git filter-branch.

http://git-scm.com/docs/git-filter-branch

rtn
  • 127,556
  • 20
  • 111
  • 121
  • I tried some of those indicated on the filter-branch without any success. I'll mix your answer with the others and try to find a way to fix my problem. Thanks for your answer! :) – Cyril N. May 06 '11 at 14:40
  • upvoted the answer, because this is the way to go in these circumstances. Deleting the repository will not help, because if you want to be shared you need to clean up sensitive info anyway. I would recommend to delete repo while nobody cloned it with this sensitive data. Then apply filter-branch to cleanup the data and then resubmit to github – Eugene Sajine May 06 '11 at 20:03
  • OTOH if you want to remove a commit you need to use rebase. if the commit you want to remove is 10 commits ago from current HEAD, then do: git rebase -i HEAD~16 edit the file by removing the line with the commit from the file and keeping other commits untouched and then save and exit the editor. This commit will be lost, now you have to force push this branch to the repo at github. Make sure you rebase other branches if they were spawned from the one your working with, so this commit will not be kept/referenced anywhere in the history. – Eugene Sajine May 06 '11 at 20:31
  • @Eugene, the problem is that with rebase, not only that revision is gone, but all changes from that revision get dropped too. I.e. in principle all descendant versions change. Here, it seems that only one revision shall be dropped while all descendants shall keep the same content. – Tilman Vogel May 06 '11 at 20:42
  • @myself, a solution could be to use `git rebase -i` and just use `fixup` to merge the unwanted revision with its direct successor which removes the unwanted data – Tilman Vogel May 06 '11 at 20:43
  • @Tilman Vogel, yes you're correct, but OP is pretty explicit that he wants to remove the whole revision and that's the way to do that. And yes, the removal of commit might lead to conflicts or to a new state of the code, so thanks for pointing that out – Eugene Sajine May 06 '11 at 20:47
  • @Eugene, I think the `squash` or `fixup` will just make that unpleasant "intermediate" state inaccessible – Tilman Vogel May 06 '11 at 20:53
  • @Tilman Vogel, that's quite interesting approach, creative;) gotta check if this will leave no traces though;) – Eugene Sajine May 06 '11 at 20:53
1

tested @ 2022-03




many solution based on squash way.

I just say delete last one (or more) commits directly
 (without squash, no new commit version generate), which may have common situation.

drop commit solution

when git rebase -i eexxaa^ step,
just mark last unwant commit as drop, save it.

finally git push -f
then the drop version also delete in gist page.

where get the repo url of gist ?

just open the gist page > copy url in broswer addressbar,
 use git clone $the_url, it works.

note: use http(s) also need github access token rather than password;
 access token only need gist permission (can do force push)

yurenchen
  • 1,897
  • 19
  • 17
  • 1
    At http push if said "Repository not found", add gist permission (the only one with "Create gists") to the access token. – Sam Apr 22 '22 at 08:52
0

Adding to meesern's answer. When you try to squash or fixup and rebase--continue, you are required to add a comment or --allow-empty-message. This is time consuming, and somehow my commits did not go away from the gist's revision list by doing that way.

I found a simpler solution: You can just delete the unnecessary commit lines on your rebase to-do list, :wq!, git rebase --continue, and git push -f.

ShunS
  • 1
0

I tried the other answers here but had two problems:

  1. I couldn't rebase it, I think it was because the repository is with commits without messages.
  2. I couldn't push it (yes, with force).

I solved those two problems by first creating another branch on the first commit, and cherry-picking the rest of the commits one-by-one, without committing them automatically (so that I can edit them before commit).

After that, I reset the master branch to the new branch: git switch master && git reset --hard temp.

And before pushing, I changed the remote to the SSH version:

git remote set-url origin git@github.com:<<gist id>>.git

And then, using git push --force it pushed and changed the gist revisions.

baruchiro
  • 5,088
  • 5
  • 44
  • 66
0

None of the previous answers were fully baked or working for me, so I rolled my own. Sharing it here in case it's useful to anyone. There is some error checking in the script, but please review it and check what you are doing, because this does have the potential to destroy data.

Save the script below and execute, supplying the URL to your Gist as the parameter. If the URL supplies has a path to a specific revision, that will be used to rebase, otherwise it will reset your gist to the "tip"—all previous commits will be removed.

There will be a pause after the initial clone so you can make additional edits if you want.

gist-clean.sh

#!/usr/bin/env bash

BASE_URL='gist.github.com'
GHUSER=$(git config --get user.name 2>/dev/null)

_usage() {
cat <<EOF

Reset a GitHub gist to clean up or remove sensitive information
usage: ${0##*/} <gist-url>

  if the URL supplied contains a revision ID (hash),
  then that revision will be used as the base.

  to get URLs to specific revisions:
    - browse to the gist on ${BASE_URL}${GHUSER:+/$GHUSER}
    - click "Revisions"
    - locate the revision you want to base from
    - click the 3 dots next to the filename -> "View file"
    - copy the URL

EOF
}

case $1 in
    -h|--help|'') _usage; exit;;
esac

[[ -n $1 ]] || { echo "supply a gist URL"; exit; }
[[ -n $GHUSER ]] || { echo 1>&2 "couldn't fetch GitHub username"; exit 1; }

if [[ $1 =~ ^https://${BASE_URL}/${GHUSER}/([a-f0-9]{32,40})/?([a-f0-9]{32,40})? ]]; then
    GIST_URL=${BASH_REMATCH[0]}
    GIST_ID=${BASH_REMATCH[1]}
    REV_HASH=${BASH_REMATCH[2]}
    CLONE_URL="https://${BASE_URL}/${GIST_ID}.git"
    TEMP_DIR="/tmp/gist${GIST_ID}"
    rm -rf "${TEMP_DIR}" 2>/dev/null
    mkdir -p "${TEMP_DIR}"
    if ! git clone "${CLONE_URL}" "${TEMP_DIR}" ; then
        exit 1
    fi
    cd "${TEMP_DIR}" || exit 1
    if [[ -n ${REV_HASH} ]]; then
        git reset --hard "${REV_HASH}"
    fi
    BRANCH=$(git symbolic-ref --short HEAD)
    cat <<-EOF
    ┌──────────────────────────────────────┐
    │                                      │
    │ PAUSED - YOU CAN NOW EDIT THE FILES  │
    │                                      │
    │           !!! WARNING !!!            │
    │                                      │
    │ ALL CONTENTS OF THE REMOTE GIST WILL │
    │  BE REPLACED BY THE LOCAL COPY, AND  │
    │     ALL REVISIONS WILL BE LOST!      │
    │                                      │
    └──────────────────────────────────────┘
    EOF
    read -r -p 'press <ENTER> to continue or ⌃c to ABORT '
    rm -rf .git
    git init
    git add .
    git commit -m 'initial commit'
    git remote add origin "git@github.com:${GIST_ID}.git"
    git push --set-upstream origin "$BRANCH" --force
    cd ..
    rm -rf "${TEMP_DIR}"
    open "${GIST_URL}"
else
    echo 1>&2 "does not appear to be a valid gist URL"
    exit 1
fi

Example:

./gist-clean.sh https://gist.github.com/your-git-username/f184a9c638b75525a65b3e1a7298e6d7/30e87b313bdba9a4bd92746418217ddda958b8cd
luckman212
  • 473
  • 1
  • 7
  • 15