Make the current commit the only (initial) commit in a Git repository?

283,441

Solution 1

Here's the brute-force approach. It also removes the configuration of the repository.

Note: This does NOT work if the repository has submodules! If you are using submodules, you should use e.g. interactive rebase

Step 1: remove all history (Make sure you have backup, this cannot be reverted)

cat .git/config  # note <github-uri>
rm -rf .git

Step 2: reconstruct the Git repo with only the current content

git init
git add .
git commit -m "Initial commit"

Step 3: push to GitHub.

git remote add origin <github-uri>
git push -u --force origin main

Solution 2

The only solution that works for me (and keeps submodules working) is

git checkout --orphan newBranch
git add -A  # Add all files and commit them
git commit
git branch -D master  # Deletes the master branch
git branch -m master  # Rename the current branch to master
git push -f origin master  # Force push master branch to github
git gc --aggressive --prune=all     # remove the old files

Deleting .git/ always causes huge issues when I have submodules. Using git rebase --root would somehow cause conflicts for me (and take long since I had a lot of history).

Solution 3

This is my favoured approach:

git branch new_branch_name $(echo "commit message" | git commit-tree HEAD^{tree})

This will create a new branch with one commit that adds everything in HEAD. It doesn't alter anything else, so it's completely safe.

Solution 4

The other option, which could turn out to be a lot of work if you have a lot of commits, is an interactive rebase (assuming your git version is >=1.7.12):git rebase --root -i

When presented with a list of commits in your editor:

  • Change "pick" to "reword" for the first commit
  • Change "pick" to "fixup" every other commit

Save and close. Git will start rebasing.

At the end you would have a new root commit that is a combination of all the ones that came after it.

The advantage is that you don't have to delete your repository and if you have second thoughts you always have a fallback.

If you really do want to nuke your history, reset master to this commit and delete all other branches.

Solution 5

Variant of larsmans's proposed method:

Save your untrackfiles list:

git ls-files --others --exclude-standard > /tmp/my_untracked_files

Save your git configuration:

mv .git/config /tmp/

Then perform larsmans's first steps:

rm -rf .git
git init
git add .

Restore your config:

mv /tmp/config .git/

Untrack you untracked files:

cat /tmp/my_untracked_files | xargs -0 git rm --cached

Then commit:

git commit -m "Initial commit"

And finally push to your repository:

git push -u --force origin master
Share:
283,441
kaese
Author by

kaese

Updated on July 08, 2022

Comments

  • kaese
    kaese almost 2 years

    I currently have a local Git repository, which I push to a Github repository.

    The local repository has ~10 commits, and the Github repository is a synchronised duplicate of this.

    What I'd like to do is remove ALL the version history from the local Git repository, so the current contents of the repository appear as the only commit (and therefore older versions of files within the repository are not stored).

    I'd then like to push these changes to Github.

    I have investigated Git rebase, but this appears to be more suited to removing specific versions. Another potential solution is to delete the local repo, and create a new one - though this would probably create a lot of work!

    ETA: There are specific directories / files that are untracked - if possible I would like to maintain the untracking of these files.

  • kaese
    kaese about 12 years
    Thanks larsmans - I have opted to use this as my solution. Though initialising the Git repo loses record of untracked files in the old repo, this is probably a simpler solution for my problem.
  • Fred Foo
    Fred Foo about 12 years
    @kaese: I think your .gitignore should handle those, right?
  • gru
    gru over 10 years
    this should be the correct answer! just add a git push -f origin master as the last op and sun will shine again on your fresh repo! :)
  • lalebarde
    lalebarde about 10 years
    Save your .git/config before, and restore it after.
  • Jone Polvora
    Jone Polvora about 10 years
    This solutions works locally. What if I have a remote master? Will have side effects ?
  • Brad
    Brad about 10 years
    Does this not keep old commits around?
  • echo
    echo about 10 years
    @JonePolvora git fetch; git reset --hard origin/master stackoverflow.com/questions/4785107/…
  • Inuart
    Inuart over 9 years
    after doing this, will the repo free space?
  • Hirnhamster
    Hirnhamster over 9 years
    @Brad: I was wondering the same thing. Seems that --orphan only gets the last commit so that the remaining ones are thrown away when the branch is deleted. Reference: git-scm.com/docs/git-checkout
  • Valtoni Boaventura
    Valtoni Boaventura about 9 years
    Best approach! Clear, and do the work. Additionally, i rename the branch with a lot of changes from "master" to "local-work" and "new_branch_name" to "master". In master, do following: git -m local-changes git branch -m local-changes git checkout new_branch_name git branch -m master<
  • Victor Schröder
    Victor Schröder almost 9 years
    Remove files or commits from the repository has absolutely no relation with the question (which asks to remove history, a completely different thing). The OP wants a clean history but wants to preserve current state of the repository.
  • noɥʇʎԀʎzɐɹƆ
    noɥʇʎԀʎzɐɹƆ almost 9 years
    Good for times when you're not using Github
  • pir
    pir almost 9 years
    This doesn't work with a remote repo? I've used the script, but with no success. My .git folder is still huge. I've also tried scripts by @gru and echo. Any advice?
  • Buttle Butkus
    Buttle Butkus over 8 years
    @lalebarde If you restore .git/config after git commit -m "Initial commit" then you can probably skip the git remote add ... part, assuming that was already in your config, and move straight on to pushing. It worked for me.
  • NoNameProvided
    NoNameProvided over 8 years
    Deleting the .git folder may cause problems in your git repository. If you want to delete all your commit history but keep the code in its current state, it is very safe to do it as in the following: stackoverflow.com/a/26000395/2019689
  • dsclose
    dsclose about 8 years
    The cleanest way to achieve the desired result.
  • Robert Muil
    Robert Muil about 8 years
    Be careful with this if you are trying to remove sensitive data: the presence of only a single commit in the newly pushed master branch is misleading - the history will still exist it just won't be accessible from that branch. If you have tags, for example, which point to older commits, these commits will be accessible. In fact, for anyone with a bit of git foo, I'm sure that after this git push, they will still be able to recover all history from the GitHub repository - and if you have other branches or tags, then they don't even need much git foo.
  • aquawicket
    aquawicket almost 8 years
    If you use svn to access, be sure to delete the hidden .svn folder before adding. Works great. Thanks.
  • NobleUplift
    NobleUplift over 7 years
    Is there any way to UNDO this? We did this at my company and we need to combine the two repositories together, but so far I haven't found a way to do it yet. The details are all located here.
  • abagh0703
    abagh0703 over 7 years
    Tried the accepted answer exactly as it is written and it didn't work. Tried this answer exactly as it is written, worked like a charm. This should be the accepted answer!
  • Jason Goemaat
    Jason Goemaat over 7 years
    Git will keep the old files around for a while, to get rid of them run git gc --aggressive --prune=all. In addition, git will continue to store history for any commits that are referenced with branches or tags. To check, run git tag -l and git branch -v, then delete any you find. Also double check your remote with git ls-remote, you may need to delete remote tags/branches as well or when you fetch you will get all the linked files again.
  • Tuncay Göncüoğlu
    Tuncay Göncüoğlu over 7 years
    I believe you should add @JasonGoemaat 's suggestion as the last line to your answer. Without git gc --aggressive --prune all the whole point of losing history would be missed.
  • Tuncay Göncüoğlu
    Tuncay Göncüoğlu over 7 years
    this does not produce the result asked in the question. you are discarding all changes after the commit you keep last and losing all changes since then, but the question asks to keep current files and drop history.
  • nick.graziano
    nick.graziano over 7 years
    This is what I was looking for, clears the space from all the old commits.
  • Seweryn Niemiec
    Seweryn Niemiec over 7 years
    Such clone can not be pushed to a new repository.
  • Seweryn Niemiec
    Seweryn Niemiec over 7 years
    Instead of deleting original master branch, one can rename it git branch -m master old_master and set push mode to current-branch-only git config --local push.default current. This way one can keep historical commits in separate branch and work in sync with repo in the fresh master.
  • Alireza
    Alireza over 7 years
    the last command should be '--prune=all' (i.e. w/ the equals sign).
  • TomKeegasi
    TomKeegasi about 7 years
    This looks really short and sleek, the only thing I don't understand or haven't seen yet is HEAD^{tree}, could somebody explain? Apart from that I'd read this as "create new branch from given commit, created by creating a new commit-object with given commit-message from ___"
  • dan_waterworth
    dan_waterworth about 7 years
    The definitive place to look for answers to questions about git reference syntax is in the git-rev-parse docs. What's happening here is git-commit-tree requires a reference to a tree (a snapshot of the repo), but HEAD is a revision. To find the tree associated with a commit we use the <rev>^{<type>} form.
  • Admin
    Admin about 7 years
    So many bad answers in the world and after an hour I finally got this to do my bidding!
  • Ivan Rave
    Ivan Rave about 7 years
  • beppe9000
    beppe9000 almost 7 years
    @RobertMuil is it safe now? Could you edit it if not?
  • Robert Muil
    Robert Muil almost 7 years
    @beppe9000 I don't know for sure, but I don't think it is: the wiki hasn't changed since I made my previous comment. I won't edit because I don't know an easy solution apart from completely deleting all repos...
  • nights
    nights almost 7 years
    thats what he's doing in step 1: rm -rf .git ?
  • Armand
    Armand over 6 years
    If I run this, on the push, I get ` ! [remote rejected] master -> master (non-fast-forward)` would be nice if this worked on a push to remote origin
  • do0g
    do0g over 6 years
    @Armand, you need to push with -f. This will force the remote repo to be updated with the branch you've created locally.
  • Felipe Alvarez
    Felipe Alvarez over 6 years
    Nice answer. Works well. Finally say git push --force <remote> new_branch_name:<remote-branch>
  • Zuzu Corneliu
    Zuzu Corneliu about 6 years
    Does this send only the modified portions of the repository? e.g. if I have a large file F already in the top commit and do this, will the forced push send F's contents again over the wire?
  • mgiaco
    mgiaco almost 6 years
    This does not work. I do get this error: git branch -M master -f error: refname refs/heads/newBranch not found
  • Kris79
    Kris79 over 5 years
    Above still not removed all history what I had to change was one extra command at the end: git push origin --mirror
  • Shafique Jamal
    Shafique Jamal about 5 years
    Thanks for this. Just FYI: your script to kill the history for each branch could use some updating - it gives the following errors: git-hash: not found and Support for <GIT_DIR>/info/grafts is deprecated
  • Sam Watkins
    Sam Watkins about 5 years
    @ShafiqueJamal, thanks, the little "git-hash" script is git log HEAD~${1:-0} -n1 --format=%H, here, sam.aiki.info/b/git-hash It would be better to put it all in one script for public consumption. If I ever use it again, I might figure out how to do it with the new feature that replaces "grafts".
  • not2qubit
    not2qubit about 5 years
    One of the main points is to be able to see where it was forked from.
  • not2qubit
    not2qubit about 5 years
    I think you forgot to force push master to complete the procedure.
  • not2qubit
    not2qubit about 5 years
    It would be useful to know how to circumvent that limitation. Can someone explain why this can't be force pushed?
  • Matthias M
    Matthias M about 5 years
    The answer to your question: stackoverflow.com/questions/6900103/…
  • Begueradj
    Begueradj about 5 years
    After rebase completed, I can not push: error: failed to push some refs to
  • Carl
    Carl about 5 years
    @Begueradj if you've already pushed the branch you rebased, then you will need to force push git push --force-with-lease. force-with-lease is used because it is less destructive than --force.
  • Ben Richards
    Ben Richards over 4 years
    I had to make a slight modification. git branch will include an asterisk next to your checked out branch, which will then be globbed, causing it to resolve to all files or folders as if those were branch names too. Instead, I used git branch --format="%(refname:lstrip=2)" which gave me just the branch names.
  • Shafique Jamal
    Shafique Jamal over 4 years
    @not2qubit: Thanks for this. What would be the exact command? git push --force origin master, or git push --force-with-lease? Apparently the latter is safer (see stackoverflow.com/questions/5509543/…)
  • Shafique Jamal
    Shafique Jamal over 4 years
    @BenRichards. Interesting. I'll try this again at some point with a folder that matches a branch name to test it, then update the answer. Thanks.
  • D. Ben Knoble
    D. Ben Knoble over 4 years
    Gah! Dont make me provide my unhidden, unprotected password at the command line! Also, the output of git branch is typically poorly suited for scripting. You may want to look at the plumbing tools.
  • Mogens TrasherDK
    Mogens TrasherDK over 4 years
    Nice addition, when seen in context of @Zeelot 's answer.
  • AnoE
    AnoE over 4 years
    Yup, Zeelot's has the commands which basically do this (just differently, by starting completely over, which might just be fine for OP). @MogensTrasherDK
  • Mike76
    Mike76 over 4 years
    This should be the accepted answer. Deleting .git and similar stuff is unsafe since it does not guarantee the same tree state after recommiting the files.
  • Royi
    Royi over 4 years
    Important note for thos working with GitLab, BitBucket, etc... stackoverflow.com/questions/48029867
  • thanos.a
    thanos.a over 4 years
    I just did this and it is fine
  • Tarik.J
    Tarik.J over 4 years
    Perfect solution, thank you! Worth mentioning that when I did it on a protected master branch I got a "pre hook declined error" I had to unprotect the branch and retry. Worked like a charm.
  • Jonathan
    Jonathan almost 4 years
    So this answer is not a real solution?
  • JE_Muc
    JE_Muc over 3 years
    This was the only working solution in my case! Thanks!
  • kjyv
    kjyv over 3 years
    This does the job but wouldn't free disk space until issuing git reflog expire --expire-unreachable=all --all followed by the mentioned git gc (it might do that some time later automatically, dunno)
  • Peroxy
    Peroxy over 3 years
    And everything in one line: git branch newbranch $(echo "commit message" | git commit-tree HEAD^{tree}) | git push --force origin newbranch:master
  • Richard Barker
    Richard Barker about 3 years
    Using @Zeelot's answer below was the easiest and least destructive way to purge the history. It should be the selected answer
  • Howard
    Howard almost 3 years
    shpuld be "main" instead of "master" for more recently created repos
  • mwag
    mwag over 2 years
    why not use mv .git .git-old which would be safer, then remove .git-old when finished? Also, you can initially run git ls-files > files.txt and then add them back with a simple cat files.txt | awk '{print "git add " $0 }' | sh
  • derekbaker783
    derekbaker783 about 2 years
    How does this answer differ from the community wiki answer, or otherwise add value?
  • bugske
    bugske almost 2 years
    Hi, related to this full history rewrite, is there some ways to actually forbid this as part of repositories permissions in bitbucket cloud ?