git-checkout older revision of a file under a new name
I have the file "main.cpp
" open in my editor.
I want to see the previous revision of "main.cpp
" in the editor too.
The way I do it now is like this.
close "main.cpp" in the editor
prompt> mv main.cpp tmp
prompt> git checkout HEAD^ main.cpp
prompt> mv main.cpp old_main.cpp
prompt> mv tmp main.cpp
prompt>
open "main.cpp" and "old_main.cpp" in the editor
Can it be simplified, so I don't have to close "main.cpp" in the editor?
What I'm hoping for is a variant of git-checkout
that can do this.
UPDATE: im using git on mac osx 10.5.7
prompt> git --version
git version 1.6.0.4
prompt>
UPDATE2: Jakub Narębski answer is:
prompt> git show HEAD^:dir1/dir2/dir3/main.cpp > old_main.cpp
prompt>
UPDATE3: Karmi's answer, for a specific revision:
prompt> git show 4c274dd91dc:higgs/Higgs.xcodeproj/project.pbxproj > old_project.pbxproj
prompt>
Solution 1:
You can use git show
for that:
git show HEAD^:main.cpp > old_main.cpp
(Note that there is colon [:
] character between HEAD^
and main.cpp
.) The <revision>:<path>
syntax is described in git rev-parse manpage, next to last point in the "Specifying revisions" section:
<rev>:<path>
, e.g.HEAD:README
,:README
,master:./README
A suffix
:
followed by a path names the blob or tree at the given path in the tree-ish object named by the part before the colon.:path
(with an empty part before the colon) is a special case of the syntax described next: content recorded in the index at the given path. A path starting with./
or../
is relative to the current working directory. The given path will be converted to be relative to the working tree’s root directory. This is most useful to address a blob or tree from a commit or tree that has the same tree structure as the working tree.
Note that <path>
here is FULL path relative to the top directory of your project, i.e. the directory with .git/
directory. (Or, to be more exact, to "<revision>", which in general can be any <tree-ish>, i.e. something that represents tree.)
If you want to use path relative to the current directory, you need to use ./<path>
syntax (or ../path
to go up from current directory).
Edit 2015-01-15: added information about relative path syntax
You can get in most cases the same output using low-level (plumbing) git cat-file
command:
git cat-file blob HEAD^:main.cpp > old_main.cpp
Solution 2:
Just to add to Jakub's answer: you don't even have to redirect the output to a file with >
, if you are only interested in skimming the file contents in the terminal. You can just run $ git show 58a3db6:path/to/your/file.txt
.
Solution 3:
Singular use case
In order to get consistent checkout behavior including autocrlf
etc., use a secondary folder (TEMP as example) and restore the file state from an older / different like this:
git --work-tree TEMP/ restore -s <commit> main.cpp
mv TEMP/main.cpp old_main.cpp
Note:
git show <commit>:main.cpp > old_main.cpp
.. will just produce a raw read from the repository.
Use a 2nd work tree - anonymous or linked
For more comfort working with alternative file states (without the need for renaming) use a secondary "anonymous" directory as a (long term) parallel work tree like this:
# one time setup
mkdir WD2
cd WD2
echo gitdir: WD1 > .git
# operate freely here with an alternative file set while the same branch is checked out in git
git restore -s <commit> main.cpp
(WD2 : path to secondary dir. WD1 : path to primary dir - Absolute or relative)
Note: Any kind of git project work (restore / add / commit / switch ..., build tasks) can be done with that alternative file set - as if suddenly the work tree files in WD1 would have been swapped. Hard links could be used for efficiently mirroring unchanged files in huge repos.
Similarly a "linked working tree" can be used via git-worktree (new since git v2.6.7). This causes somewhat more git overhead, but allows to checkout and work on a different branch (or detached head) simultaneously without using an extra repo.