lmi
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[lmi] Retrieve file from git as of a particular date


From: Greg Chicares
Subject: [lmi] Retrieve file from git as of a particular date
Date: Fri, 14 Jun 2019 15:24:23 +0000
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.6.1

Often we make a set of local changes, then move them aside (e.g., into
a different subdirectory), and then undertake a different task in a
clean checkout. The motivation might be to modify output in some way
that can't go into production until it's been formally accepted by
others. We may have quite a few pending changesets, and acceptances
are asynchronous. The problem is that these changesets conflict with
each other and with normal evolution in HEAD, so when one is eventually
accepted, it can be hard to see what the intended change was.

When we later want to commit the changes in, say,
  /opt/lmi/pending/foo.cpp  dated 2019-03-21
it's handy to retrieve 'foo.cpp' as it stood on the date it was moved
to a "pending" directory--so that we can see what the intended changes
were, and figure out how to apply them to current HEAD. Perhaps only
three lines need to change, but fifty other lines have meanwhile
changed for other reasons in the lmi trunk.

How, then, can we retrieve a file as of a given date?

Obviously we can
  git log foo.cpp
and manually find the last SHA1 preceding the given date, and then
  git show $sha1:$selected_file
but that's tedious.

This didn't look promising:
  git show HEAD@{20181014}:antediluvian_stubs.cpp  
  fatal: Log for 'HEAD' only has 973 entries.
We have thousands of commits:
  git log --oneline|wc -l
  8016
so I suppose the problem is that the git "reflog" doesn't extend back
to the original commits.

Then I tried:
  git rev-list -1 --before=2018-10-14 master
which does seem to give the desired SHA1. Furthermore, I can do this:
  git show `git rev-list -1 --before=2018-10-14 master`:antediluvian_stubs.cpp
and even

  for z in antediluvian_stubs.cpp [...other files...] interest_rates.cpp ; \
  do git show `git rev-list -1 --before=2018-10-14 master`:${z} \
    >/opt/lmi/pending/antecedents/$z; done

to get a whole set of originals as they were just before a change was
made (and then set aside).

Vadim--am I missing a better way to do this? The 'rev-list' command
seems kind of finicky:
  okay:  git rev-list -1 --before=2018-10-14 master
  fails: git rev-list -1 --before=2018-10-14
  ????:  git rev-list -1 --before=20181014 master
The last of those three commands "succeeds" in the sense that its
return code is zero, but it prints the SHA1 of HEAD.

Apparently git accepts "YYYY-MM-DD" but misinterprets "YYYYMMDD".
Retrying a simpler command from above:

# as above, without hyphens--no good
  git show HEAD@{20181014}:antediluvian_stubs.cpp  
  fatal: Log for 'HEAD' only has 973 entries.
# Does that syntax mean the 20,181,014th preceding commit?

# with hyphens--seems to work, but see next example
  git show HEAD@{2018-10-14}:antediluvian_stubs.cpp

# move date back a decade--no good (because of "reflog"?)
  git show HEAD@{2008-10-14}:antediluvian_stubs.cpp 
  warning: Log for 'HEAD' only goes back to Thu, 11 Oct 2018 23:33:18 +0000.

The rev-list method does however let me go back a decade:
  git show `git rev-list -1 --before=2008-10-14 master`:antediluvian_stubs.cpp
That works, so it's the best solution I've found.

There are other ways we could approach the motivating problem.
For example, when moving a file aside, we might also store:
  - the contemporary unmodified original
  - a patch embodying the change
yet that makes extra work that would often turn out to be unneeded.
Or we could use 'git stash', which I have found to be useful for
short-lived changes--but after several months the changes tend to
go stale and can't be popped cleanly; besides, the contents are
hard to view, and liable to be lost due to a fumbled command, so
that's not a good solution for changes that may be put aside for
months. We could also use git branches, but that alternative is
very much like using a distinct "pending" directory--it's just a
matter of storing changes in the OS filesystem or git's own--so I
don't see any great advantage there. The essential problem is that
merges are difficult, and really must be done manually.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]