git prune: standard and as part of fetch

2020-08-08

 | 

~3 min read

 | 

498 words

What Is Pruning?

Pruning is part of the Git’s garbage collection. It’s a way to prune references to unreachable or “orphaned” Git objects.

Typically, pruning has to do with local objects that have become detached. An object can become orphaned in a number of ways, but if you ever get the following message from Git, you know you’ve reached an orphan:

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

      git checkout -b <new-branch-name>

HEAD is now at 5178bec... an awesome new feature!

Common ways this happens is when altering history, for example with a git reset or git rebase.

Prune As Part Of Fetch

If we wanted to remove the detached objects, we can use git gc and git prune in tandem. This, however, is quite different from the more common place I’ve seen the term prune in Git, which is as an option of the fetch command.

git fetch --prune

This will keep your local references to the remote repository up-to-date. It does not delete a local version of the branch, only the ref to the remote version. An example might be helpful to visualize this:

  1. You had pull down the branch feat-abc from master:

    git checkout -t origin/feat-abc
    git branch --all

    Will print the following:

    * feat-abc
      main
      remotes/origin/HEAD -> origin/main
      remotes/origin/feat-abc
      remotes/origin/main
  2. Later, feat-abc is deleted from the remote and you fetch:

    git fetch --prune
    git branch --all

    The print out will reflect that feat-abc is no longer in the remotes:

    * feat-abc
      main
      remotes/origin/HEAD -> origin/main
      remotes/origin/main

If, after cleaning up the remote refs, you want to remove any deleted branches, you can use this one liner to help:

git branch -vv | grep '[origin/.*: gone]' | awk '{print $1}' | xargs git branch -d

I wrote more about how this works previously, here.

Updating Defaults

If you want to make this clean up done by default, you can indicate this within the .gitconfig

One setting I’ve seen suggested added to the global Git config is:

$HOME/.gitconfig
#...
[fetch]
        prune = true

Or, setting this from the command line:

git config --global fetch.prune true

Wrap Up

Using git prune is typically used as a child command of git gc and not needed to be executed directly most of the time. That said, I have found it helpful to keep things organized by updating my global git config to always prune on pull - though there are some good arguments against this as well.

For more on git prune, Atlassian has put together a nice tutorial.



Hi there and thanks for reading! My name's Stephen. I live in Chicago with my wife, Kate, and dog, Finn. Want more? See about and get in touch!