Reputation: 1248
I have a git repository for a system sys/master
which I created after some time the system was created. I have a backup of the system sys_bk
that was done before the repository creation.
What is the recommended way of adding the sys_bk
version to the current repository as a tagged version without affecting the recent version of the system?
FYI, differences between sys_bk
and sys/master
are huge.
Upvotes: 0
Views: 46
Reputation: 45659
I think the real unanswered question here is, how do you want this new(/old) commit to appear in history? Today you have a history that starts at some later date
D -- E -- F <--(master)
and now you have some older version A
. Several users (jof in his answer, StephenNewell and torek in comments) have mentioned ways to add A
to your repo. This gets you something like
D -- E -- F <--(master)
A <--(sys_bk)
Then StephenNewell suggests merging the unrelated histories, but really I doubt that's what you want to do. You specified not changing the current versions of the project, so at best it'd be a special type of evil merge. Essentially you'd end up with
D -- E -- F -- M <--(master)
/
A <--(sys_bk)
but the content (TREE
) at M
would not be the default/expected merge result for that history; rather it would be a duplicate of the TREE
at F
. So that makes a merge that could cause trouble down the line, and besides it doesn't reflect A
's true place in the project history very well.
One option would be to just leave the histories unrelated. You could keep the sys_bk
branch that you used to bring A
into the repo, and/or you could tag A
(which sounds like what you were planning to do), and it would be preserved for anyone that cares to look for it. (Well, visibility is probably simplest if you keep the branch rather than just a tag; depending on how you document what you're doing.)
Another reasonable thing to consider is making it so A
looks like a parent of D
. There are a couple ways to go about this, with pros and cons.
History Rewrite
Rewriting the history to physically wire A
in as D
's parent (roughly) is an option where you pay the cost up-front, and then everything works smoothly from then on. But depending how many people share your repo, the up-front cost could be quite large, and everyone pays it whether they care about A
or not.
If you want to use this option, consult the docs for git filter-branch
with the --parent-filter
option. In the end you'd get something like
A -- d -- e -- f <--(master)
I'm using d
to identify a new commit whose TREE
is exactly like D
. (Everything about it is like D
, except it has a parent - A
- whereas D
had no parent.) This is slightly different than the typical "rewritten commit" from a rebase - especially in the case of d
- which is why I'm using lower-case instead of prime notation. But the upshot is the same: these are new commits.
That means that, assuming master
(and/or any other refs) have already been pushed to a remote, you'll have to either "force push" - git push -f
- to overwrite those refs with the new ones, or just discard the remote and put a new one in its place. Either way, every other user will be put in a broken state which they'll have to correct carefully to avoid undoing what you've done (see "Recovering from Upstream Rebase" in the git rebase
docs).
Object Replacement
A less invasive approach is to update individual repositories "as needed" to make them act as if A
were a parent of D
. In this case, anyone who's not concerned about seeing A
as a parent of D
is totally unaffected. The down side is that (a) it requires setup on each repo that wants it, and (b) it has some known bugs/quirks - see the git replace
docs.
To facilitate this, you'd want to make a copy of commit D
. You do this in a manner similar to the history rewrite, except you create a new branch to rewrite and leave all other branches alone.
So you'd work out an expression that refers to D
. (Maybe you get its commit ID, or in our example case we could use master~2
.)
git checkout master~2
git checkout -b sys_bk_replacement
Then run git filter-branch
in much the same way as you would for a full rewrite, but specifying only the sys_bk_replacement
branch (not --all
as you probably would've for a full rewrite). This would give you
D -- E -- F <--(master)
A <--(sys_bk)
\
d <--(sys_bk_replacement)
and anyone wanting A
to look like D
's parent could use git replace
to substitute d
for D
.
Upvotes: 1
Reputation: 314
The simplest approach that comes to mind would be to utilize git's git checkout --orphan <branch>
command, such that you create a branch with no parent and the contents of your sys_bk
folder as the initial commit.
An example workflow:
git checkout --orphan sys_bk
(checkout a new branch with no parent)git rm -rf .
(remove all files from the working directory)cp /path/to/sys_bk/* ./
(move sys_bk
files into working directory)git add --all .
(add all new sys_bk
files to index)git commit -m "Add sys_bk"
Upvotes: 1