0

I have a git repository and found an old version of some of the corresponding files that I now want to insert into the git history for reference. The problem is that I do not want it to have any effect on the rest of the history. I only want to have all the history of the code in one place and thus be able to find all previous versions in the history. (Also, it is just a local repository and thus I do not have to worry about rewriting the history.) I tried to use git rebase with the -Xtheirs strategy but it only removed conflicting changes but kept all non-conflicting ones. Here is an exemplary repository:

mkdir insert_commit
cd insert_commit
git init

echo a > file1
git add file1
git commit -m "A"
# file1 now contains
# a

echo b > file1
git add file1
git commit -m "B"
# file1 now contains
# b

echo c >> file1
git add file1
git commit -m "C"
# file1 now contains
# b
# c

So the history is A->B->C. Now I have a version of the code that I will call X that is supposed to go between B and C, resulting in the history A->B->X->C. The files in X are:

file1:
x

file2:
x

I want to insert X as specified above, but I do not want the end result C to change, meaning I want to have C as:

file1:
b
c

file2:
-> does not exist

My approach was to do:

git rebase -i HEAD~2 -Xtheirs
# select to edit "B"
echo x > file1
echo x > file2
# (or in reality copy all files of the old version into the repository)
git add file1 file2
git commit -m "X"
# file1 now contains
# x
# file2 now contains
# x
git rebase --continue
# file1 now correctly contains
# b
# c
# file2 now incorrectly still exists and contains
# x

Is there any way other than to insert a revert commit directly behind "X" to keep the history after the insertion point unchanged?

VishnuVS
  • 1,055
  • 2
  • 14
  • 29
jotasi
  • 5,077
  • 2
  • 29
  • 51
  • This depends entirely on what you mean by "without it having any effect on the rest of the history". If you mean "without rewriting the following commits", then no, that is not possible – Lasse V. Karlsen Aug 24 '18 at 15:20
  • A Git repository can story anything at all, provided there is a reference to it (in a form of a tag or a branch). So the simplest way is to 1) tag that commit; 2) push the tag; 3) do not use the commit in "the rest of the history". – kostix Aug 24 '18 at 15:31
  • You can always branch off B and create X on a branch. That would not affect the contents of C; it would not even change C's hash or rewrite any history. Still you'd have X at hand in the same repo when you want to look back at it, diff it with other commits etc. This approach also seems most fitting to such a "Neanderthal" version which never was developed further: A leaf in a branch. – Peter - Reinstate Monica Aug 24 '18 at 16:23

2 Answers2

1

It sounds like you want this version integrated into the history, but without changing the content of any other commit. (Initially when you said "without affecting history" it sounded like you wanted to avoid history rewrite, but later you clarify that a rewrite is ok. But the problem with rebase is, it doesn't keep the content as-is, since ours is only a conflict resolution strategy.)

In that case, you can reparent instead of rebasing. There are several ways to go about this, so please refer to the git filter-branch docs (https://git-scm.com/docs/git-filter-branch) with attention to the --parent-filter option and related examples.

Mark Adelsberger
  • 42,148
  • 4
  • 35
  • 52
1

You can use git replace to create a "replacement commit" for the first commit in the tree without affecting subsequent history.

Say that the Git history of my project starts with "version two":

$ git init
Initialised empty Git repository in /tmp/change-history/.git/
$ echo version two > a.txt
$ git add .
$ git commit -m "version two"
[master (root-commit) 0b5010c] version two
 1 file changed, 1 insertion(+)
 create mode 100644 a.txt

And then I discover the old "version one" of the project. I create an "orphan branch", to add this version as a new root commit:

$ git checkout --orphan ancient-history
Switched to a new branch 'ancient-history'
$ echo version one > a.txt
$ git add .
$ git commit -m "version one"
[ancient-history (root-commit) cdd0fd9] version one
 1 file changed, 1 insertion(+)
 create mode 100644 a.txt

Back on the master branch, I create a replacement commit for the first commit on the branch:

$ git checkout master
Switched to branch 'master'
$ git replace --graft 0b5010c ancient-history

Now the "version one" commit appears as the parent of the "version two" commit:

$ git log --oneline
0b5010c version two
cdd0fd9 version one
$ git diff cdd0fd9..0b5010c
diff --git a/a.txt b/a.txt
index 9bc69cf..6702fe2 100644
--- a/a.txt
+++ b/a.txt
@@ -1 +1 @@
-version one
+version two
legoscia
  • 39,593
  • 22
  • 116
  • 167
  • 1
    This is actually very close to what I want. The only problem left is, that I not necessarily want to insert the commit as the new root of the repository and your solution only works in that case. There is an easy fix though. Namely instead of an `--orphan` branch you can use a normal branch, which is branched of at the original parent ("A" in the example in the question). If you want, feel free to include this into your answer or let me know if you prefer, that I edit it in. – jotasi Aug 27 '18 at 07:53
  • 1
    Oops, I mean "B" in the example in the question. – jotasi Aug 27 '18 at 08:29