Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • Home
  • SEARCH
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 904345
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 15, 20262026-05-15T16:01:59+00:00 2026-05-15T16:01:59+00:00

I have a git repo in /foo/bar/baz with a large commit history and multiple

  • 0

I have a git repo in /foo/bar/baz with a large commit history and multiple branches.

I now want /foo/qux to be in the same repo as /foo/bar/baz, which means that I need them both to be in a repo rooted at /foo. However, I want to preserve history of changes that I’ve made to /foo/bar/baz.

I first thought of git format-patch followed by apply, but commit messages aren’t preserved.

So,

I need to reroot the repo

(1) to an arbitrarily higher ancestor directory
(2) while preserving my commit history by making it look like I’ve been comitting to /foo/bar/baz all along

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-15T16:02:00+00:00Added an answer on May 15, 2026 at 4:02 pm

    What you want is git filter-branch, which can move a whole repository into a subtree, preserving history by making it look as if it’s always been that way. Back up your repository before using this!

    Here’s the magic. In /foo/bar, run:

    git filter-branch --commit-filter '
        TREE="$1";
        shift;
        SUBTREE=`echo -e 040000 tree $TREE"\tbar" | git mktree`
        git commit-tree $SUBTREE "$@"' -- --all
    

    That will make the /foo/bar repository have another ‘bar’ subdirectory with all its contents throughout its whole history. Then you can move the entire repo up to the foo level and add baz code to it.

    Update:

    Okay, here’s what’s going on. A commit is a link to a “tree” (think of it as a SHA representing a whole filesystem subdirectory’s contents) plus some “parent” SHA’s and some metadata link author/message/etc. The git commit-tree command is the low-level bit that wraps all this together. The parameter to --commit-filter gets treated as a shell function and run in place of git commit-tree during the filter process, and has to act like it.

    What I’m doing is taking the first parameter, the original tree to commit, and building a new “tree object” that says it’s in a subfolder via git mktree, another low-level git command. To do that, I have to pipe into it something that looks like a git tree i.e. a set of (mode SP type SP SHA TAB filename) lines; thus the echo command. The output of mktree is then substituted for the first parameter when I chain to the real commit-tree; "$@" is a way to pass all the other parameters intact, having stripped the first off with shift. See git help mktree and git help commit-tree for info.

    So, if you need multiple levels, you have to nest a few extra levels of tree objects (this isn’t tested but is the general idea):

    git filter-branch --commit-filter '
        TREE="$1"
        shift
        SUBTREE1=`echo -e 040000 tree $TREE"\tbar" | git mktree`
        SUBTREE2=`echo -e 040000 tree $SUBTREE1"\tb" | git mktree`
        SUBTREE3=`echo -e 040000 tree $SUBTREE2"\ta" | git mktree`
        git commit-tree $SUBTREE3 "$@"' -- --all
    

    That should shift the real contents down into a/b/bar (note the reversed order).

    Update: Integrated improvements From Matthew Alpert’s answer below. Without -- --all this only works on the currently-checked out branch, but since the question is asking about a whole repo, it makes more sense to do it this way than branch-by-branch.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.