Issue
We have multiple documentation files which are updated per release inside our repo. We now decide we want to keep previous versions of the documentation inside the HEAD
commit of our repo.
We decide we’d like all versions past-and-present to live inside sub-folders of the original doc/
folder. Great, except if we just move the current in-dev docs to say indev/
and copy-paste docs from different places in time, we’re going to lose the commit history of specific files, and generally create a huge ugly diff. My question is: is there a way to preserve such history for older versions of these (currently existant) files.
A minimal reproducer of sorts:
- Document for the first release in just the
doc/
folder.
$ git init
$ mkdir doc
$ touch doc/index.html
$ echo "<h1>Hello world!</h1>" >> doc/index.html
$ git add doc/index.html
$ git commit -m "init"
$ echo "<p>This package allows you to...</p>" >> doc/index.html
$ git commit -a -m "basic docs"
$ git tag 1.0
So the history looks like:
$ git blame doc/index.html
commit 0: doc/index.html "<h1>Hello world!</h1>"
commit 1: doc/index.html "<p>This package allows you to...</p>"
- Start documenting for the second release…
$ echo "<p>New feature: ...</p>" >> doc/index.html
$ git commit -a -m "document new feature"
$ git blame doc/index.html
commit 0: doc/index.html "<h1>Hello world!</h1>"
commit 1: doc/index.html "<p>This package allows you to...</p>"
commit 2: doc/index.html "<p>New feature: ...</p>"
- Realise you want to keep older doc versions in the repo’s
HEAD
$ mkdir doc/1.0 doc/2.0
$ git mv doc/index.html doc/2.0/index.html
$ git blame doc/2.0/index.html
commit 0: doc/2.0/index.html "<h1>Hello world!</h1>"
commit 1: doc/2.0/index.html "<p>This package allows you to...</p>"
commit 2: doc/2.0/index.html "<p>New feature: ...</p>"
-
???
-
Profit!
$ tree
.
└── doc
├── 1.0
│ └── index.html
└── 2.0
└── index.html
$ git blame doc/1.0/index.html
commit 0: doc/1.0/index.html "<h1>Hello world!</h1>"
commit 1: doc/1.0/index.html "<p>This package allows you to...</p>"
Solution
This is possible by some (mis)use of merging diverged branches.
Thanks to Raymond Chen for their comments and article on the matter!
Following the reproducer in my original question, at step 4 we could first commit moving the current docs to a sub-folder.
$ git commit -m "move current docs to 2.0 sub-folder"
$ tree
.
└── doc
└── 2.0
└── index.html
Then we deal with having a blameable doc/1.0/index.html
. We can create a branch from the commit before we start updating the docs for 2.0
, which has the then-1.0
docs already moved to doc/1.0
.
$ git checkout -b temp <hash>
$ git mv doc/index.html doc/1.0/index.html
$ git commit -m "move older docs to 1.0 sub-folder"
We can go back to our main branch and merge this temporary branch.
$ git checkout main
$ git merge --no-commit --no-ff temp
CONFLICT (rename/rename): doc/index.html renamed to doc/2.0/index.html in HEAD and to doc/1.0/index.html in temp.
$ git status
On branch main
You have unmerged paths.
Unmerged paths:
added by them: doc/1.0/index.html
added by us: doc/2.0/index.html
both deleted: doc/index.html
We resolve the conflicts by checking out the files from the respective branches.
$ git checkout temp -- doc/1.0/index.html
$ git checkout HEAD -- doc/2.0/index.html
$ git rm doc/index.html
$ git status
On branch main
All conflicts fixed but you are still merging.
Changes to be committed:
new file: doc/1.0/index.html
$ git commit -m "merge older version of docs"
And we’re done!
$ tree
.
└── doc
├── 1.0
│ └── index.html
└── 2.0
└── index.html
$ git blame doc/1.0/index.html
commit 0: doc/1.0/index.html "<h1>Hello world!</h1>"
commit 1: doc/1.0/index.html "<p>This package allows you to...</p>"
Note we don’t just git checkout temp -- doc/1.0/index.html
without merging first, as we would lose the history.
Answered By – honno
This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0