Multitut
Multitut

Reputation: 2169

Remove files from a bare Git Repository Globally

I would like to remove a couple big files someone pushed into our git repository, so everybody else may pull from the repo without downloading them.

I already tried ignoring those files, and also removing/commiting/pushing them from the host that pushed them with no luck.

I have access to the server and the bare repo

Thanks!

Upvotes: 6

Views: 6690

Answers (4)

Jose Quinteiro
Jose Quinteiro

Reputation: 489

There's also the BFG Repo-Cleaner which is much, much faster than git-filter-branch. However, it will not remove files that are referenced in a branch. Consult Dave's answer to remove those.

Upvotes: 0

TimWolla
TimWolla

Reputation: 32731

You have to rewrite the history using git filter-branch or similar techniques. See this example to remove the file Rakefile in the github help:

git filter-branch --force --index-filter \
  'git rm --cached --ignore-unmatch Rakefile' \
  --prune-empty -- --all

You should be aware that everyone that already cloned your repository needs to hard reset their branches to the one on the remote or they'll reintroduce the files.

Upvotes: 2

Dave
Dave

Reputation: 3633

git filter-branch is your answer here.

From the bare repository, you have several choices.

1) You want to remove a file or files, from every commit.

$ git filter-branch --index-filter \
               'git rm --cached --ignore-unmatch junk/bigfile' -- --all

or

$ git filter-branch --index-filter \
               'git rm --cached --ignore-unmatch -r junk/' -- --all

2) You want to find a file, regardless of its path, and remove all history of its existence..

$ git filter-branch --index-filter \
      'mv $GIT_INDEX_FILE /tmp/index;
       GIT_INDEX_FILE=/tmp/index git ls-files -s|
       grep -v FILENAME|git update-index --index-info' -- --all

3) You want to find a specific committed file, and remove only that file. For example if you commit a large binary, and later replace the file with a smaller file, you need to find the blob containing the original large file, and erase it.

$ git ls-tree -r <commit> | grep SOMEFILE
100644 blob 4cbedad5b4ab88f700bf27ae5a32bdb3627fa632    SOMEFILE
$ git filter-branch --index-filter \
      'mv $GIT_INDEX_FILE /tmp/index;
       GIT_INDEX_FILE=/tmp/index git ls-files -s|
       grep -v 4cbedad5b4ab88f700bf27ae5a32bdb3627fa632|
       git update-index --index-info'  -- --all

Each time you do this, the current set of "refs" or branch heads is backed up into the refs/original directory. You can always copy these back to refs/heads to restore your repository.

If the file(s) you are removing result in an empty commit, add the '--prune-empty' option to the git-filter-branch command line. This will allow git to completely discard the commit.

As long as refs/original contains the original heads, git will never prune the excised files or blobs.

Once you are completely happy with the results, the repository itself can be shrunk

$ rm -rf refs/original
$ git fsck
$ git prune
$ git gc
$ git repack -a

And you are done.

WARNING: git-filter-branch will REWRITE EVERY COMMIT. Make sure there are no uncommitted/unpushed working changed. Everyone must be committed and pushed before doing this.

Once complete, each person should do the following $ git fetch --all $ git reset --hard @{upstream}

Upvotes: 9

Dave
Dave

Reputation: 3633

If the files you want to remove were commited on their own, you can use the rebase command to simply eliminate the commit.

1) checkout a working copy

$ git clone -s bare_repo.git
$ cd bare_repo

2) use git-log to find the commit

$ git log
384b1a3306c1247559563f855e2adf5ced80678b good commit
8abb0e7cf306ceb209cb5c4aa3b422b9460fdb64 bad commit

3) Use git rebase to rewrite the history, leaving out that commit

$ git rebase -i 8abb0e7cf306ceb209cb5c4aa3b422b9460fdb64^   <--- note the ^**

4) The bad commit should be the top line. Delete the line, save and exit. 5) git-log should show your history with the bad commit gone. 5) push the changes back. Use the -f flag to force the updates

$ git push -f origin master

6) You can now delete the working tree

Upvotes: 2

Related Questions