可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I\'m afraid I couldn\'t find anything quite like this particular scenario.
I have a git repository with a lot of history: 500+ branches, 500+ tags, going back to mid-2007. It contains ~19,500 commits. We\'d like to remove all of the history before Jan 1, 2010, to make it smaller and easier to deal with (we would keep a complete copy of the history in an archive repository).
I know the commit that I want to have become the root of the new repository. I can\'t, however, figure out the correct git mojo to truncate the repo to start with that commit. I\'m guessing some variant of
git filter-branch
involving grafts would be necessary; it might also be necessary to treat each of the 200+ branches we want to keep separately and then patch the repo back together (something I do know how to do).
Has anyone ever done something like this? I\'ve got git 1.7.2.3 if that matters.
回答1:
Just create a graft of the parent of your new root commit to no parent (or to an empty commit, e.g. the real root commit of your repository). E.g. echo \"<NEW-ROOT-SHA1>\" > .git/info/grafts
After creating the graft, it takes effect right away; you should be able to look at git log
and see that the unwanted old commits have gone away:
$ echo 4a46bc886318679d8b15e05aea40b83ff6c3bd47 > .git/info/grafts
$ git log --decorate | tail --lines=11
commit cb3da2d4d8c3378919844b29e815bfd5fdc0210c
Author: Your Name <your.email@example.com>
Date: Fri May 24 14:04:10 2013 +0200
Another message
commit 4a46bc886318679d8b15e05aea40b83ff6c3bd47 (grafted)
Author: Your Name <your.email@example.com>
Date: Thu May 23 22:27:48 2013 +0200
Some message
If all looks as intended, you can just do a simple git filter-branch -- --all
to make it permanent.
BEWARE: after doing the filter-branch step, all commit ids will have changed, so anybody using the old repo must never merge with anyone using the new repo.
回答2:
Maybe it\'s too late to post a reply, but as this page is the first Google\'s result, it may still be helpful.
If you want to free some space in your git repo, but do not want to rebuild all your commits (rebase or graft), and still be able to push/pull/merge from people who has the full repo, you may use the git clone shallow clone (--depth parameter).
; Clone the original repo into limitedRepo
git clone file:///path_to/originalRepo limitedRepo --depth=10
; Remove the original repo, to free up some space
rm -rf originalRepo
cd limitedRepo
git remote rm origin
You may be able to shallow your existing repo, by following these steps:
; Shallow to last 5 commits
git rev-parse HEAD~5 > .git/shallow
; Manually remove all other branches, tags and remotes that refers to old commits
; Prune unreachable objects
git fsck --unreachable ; Will show you the list of what will be deleted
git gc --prune=now ; Will actually delete your data
Ps: Older versions of git didn\'t support clone/push/pull from/to shallow repos.
回答3:
This method is easy to understand and works fine. The argument to the script ($1
) is a reference (tag, hash, ...) to the commit starting from which you want to keep your history.
#!/bin/bash
git checkout --orphan temp $1 # create a new branch without parent history
git commit -m \"Truncated history\" # create a first commit on this branch
git rebase --onto temp $1 master # now rebase the part of master branch that we want to keep onto this branch
git branch -D temp # delete the temp branch
# The following 2 commands are optional - they keep your git repo in good shape.
git prune --progress # delete all the objects w/o references
git gc --aggressive # aggressively collect garbage; may take a lot of time on large repos
NOTE that old tags will still remain present; so you might need to remove them manually
remark: I know this is almost the same aswer as @yoyodin, but there are some important extra commands and informations here. I tried to edit the answer, but since it is a substantial change to @yoyodin\'s answer, my edit was rejected, so here\'s the information!
回答4:
Try this method How to truncate git history :
#!/bin/bash
git checkout --orphan temp $1
git commit -m \"Truncated history\"
git rebase --onto temp $1 master
git branch -D temp
Here $1
is SHA-1 of the commit you want to keep and the script will create new branch that contains all commits between $1
and master
and all the older history is dropped. Note that this simple script assumes that you do not have existing branch called temp
. Also note that this script does not clear the git data for old history. Run git gc --prune=all && git repack -a -f -F -d
after you\'ve verified that you truly want to lose all history. You may also need rebase --preserve-merges
but be warned that the git implementation of that feature is not perfect. Inspect the results manually if you use that.
回答5:
As an alternative to rewriting history, consider using git replace
as in this article from the Pro Git book. The example discussed involves replacing a parent commit to simulate the beginning of a tree, while still keeping the full history as a separate branch for safekeeping.
回答6:
If you want to keep the upstream repository with full history, but local smaller checkouts, do a shallow clone with git clone --depth=1 [repo]
.
After pushing a commit, you can do
git fetch --depth=1
to prune the old commits. This makes the old commits and their objects unreachable.
git reflog expire --expire-unreachable=now --all
. To expire all old commits and their objects
git gc --aggressive --prune=all
to remove the old objects
See also How to remove local git history after a commit?.
Note that you cannot push this \"shallow\" repository to somewhere else: \"shallow update not allowed\". See Remote rejected (shallow update not allowed) after changing Git remote URL. If you want to to that, you have to stick with grafting.
回答7:
I needed to read several answers and some other info to understand what I was doing.
1. Ignore everything older than a certain commit
The file .git/info/grafts
can define fake parents for a commit. A line with just a commit id, says that the commit doesn\'t have a parent. If we wanted to say that we care only about the last 2000 commits, we can type:
git rev-parse HEAD~2000 > .git/info/grafts
git rev-parse gives us the commit id of the 2000th parent of the current commit. The above command will overwrite the grafts file if present. Check if it\'s there first.
2. Rewrite the Git history (optional)
If you want to make this grafted fake parent a real one, then run:
git filter-branch -- --all
It will change all commit ids. Every copy of this repository needs to be updated forcefully.
3. Clean up disk space
I didn\'t done step 2, because I wanted my copy to stay compatible with the upstream. I just wanted to save some disk space. In order to forget all the old commits:
git prune
git gc
Alternative: shallow copies
If you have a shallow copy of another repository and just want to save some disk space, you can update .git/shallow
. But be careful that nothing is pointing at a commit from before. So you could run something like this:
git fetch --prune
git rev-parse HEAD~2000 > .git/shallow
git prune
git gc
The entry in shallow works like a graft. But be careful not to use grafts and shallow at the same time. At least, don\'t have the same entries in there, it will fail.
If you still have some old references (tags, branches, remote heads) that point to older commits, they won\'t be cleaned up and you won\'t save more disk space.
回答8:
When rebase or push to head/master this error may occurred
remote: GitLab: You are not allowed to access some of the refs!
To git@giturl:main/xyz.git
! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to \'git@giturl:main/xyz.git\'
To resolve this issue in git dashboard should remove master branch from \"Protected branches\"
then you can run this command
git push -f origin master
or
git rebase --onto temp $1 master
回答9:
you can delete the directory, files and also the entire history related to the dir or file using the below mentioned jar [ download it] and the commands
bfg.jar file:
https://rtyley.github.io/bfg-repo-cleaner/
git clone --bare repo-url
cd repo_dir
java -jar bfg.jar --delete-folders folder_name
git reflog expire --expire=now --all && git gc --prune=now --aggressive
git push --mirror repo_url
回答10:
- remove git data, rm .git
- git init
- add a git remote
- force push