What is the proper way to revert my local GIT repo to a specific date (commit)?
I want to modify the sources as they would have looked on a specific day.
I've read to run git reset --hard {HEAD} where {HEAD} is the commit to rest. Does that command truly reset the repo? That is does the command only reset indexes and leave the sources intact or are sources modified to that specific commit and all subsequent pulls are deleted?
I realize that resetting my local repo will mean a bandwidth hit when I restore everything. :)
Darrell
On Sep 27, 2012, at 18:58, Darrell Anderson humanreadable@yahoo.com wrote:
What is the proper way to revert my local GIT repo to a specific date (commit)?
I want to modify the sources as they would have looked on a specific day.
I've read to run git reset --hard {HEAD} where {HEAD} is the commit to rest. Does that command truly reset the repo? That is does the command only reset indexes and leave the sources intact or are sources modified to that specific commit and all subsequent pulls are deleted?
No, you've hard reset to that state. The only possible thing I can think of are files that you have created but not tracked, which may still exist in the directory.
I realize that resetting my local repo will mean a bandwidth hit when I restore everything. :)
No, don't think so. You already have a copy of the local repo, and you're not deleting any commits... So I think you could reset up back to {HEAD}.
Better yet, just do git checkout <commit>? to switch to that view of the commit, then checkout master to seitch back to your working dir :D
Either that, or my tiredness is exponentially growing.
I realize that resetting my local repo will mean a
bandwidth hit when I restore everything. :)
No, don't think so. You already have a copy of the local repo, and you're not deleting any commits... So I think you could reset up back to {HEAD}.
That is where I'm confused. I _do_ want to delete all commits more recent than the date to which I reset. Otherwise I am building packages with the same current sources. I won't accomplish anything. I am looking for a way to reset my local repo to commit xxxxxxxx and delete all commits after that date. The final result is a local repo that looks exactly as GIT did on the day of commit xxxxxxxx.
I want to do this to troubleshoot a difficult bug. After installing a GIT package set from several months ago, I know the bug did not exist then. Something happened thereafter. I want to build packages from my local repo but the sources must look exactly the same as whatever date I choose.
I want to start as far back as April 1 and then proceed forward until the bug reappears.
When I do a git log I want the sources to actually reflect the state of that date and not the illusion of that date. I need to do this to the whole repo and not just a specific package module.
Darrell
That is where I'm confused. I _do_ want to delete all commits more recent than the date to which I reset. Otherwise I am building packages with the same current sources. I won't accomplish anything. I am looking for a way to reset my local repo to commit xxxxxxxx and delete all commits after that date. The final result is a local repo that looks exactly as GIT did on the day of commit xxxxxxxx.
I want to do this to troubleshoot a difficult bug. After installing a GIT package set from several months ago, I know the bug did not exist then. Something happened thereafter. I want to build packages from my local repo but the sources must look exactly the same as whatever date I choose.
I want to start as far back as April 1 and then proceed forward until the bug reappears.
When I do a git log I want the sources to actually reflect the state of that date and not the illusion of that date. I need to do this to the whole repo and not just a specific package module.
Does anybody know how to do this?
The root problem is commits are module based. The Trinity GIT repo consists of more than 110 modules. To my knowledge there is no easy one-step 'git reset --hard {commit}' option available to revert an entire local Trinity repo to a previous state because commit hashes are not common among all Trinity modules.
Everything I read online addresses using 'git reset --hard {commit}' but is always focused on projects with only one repo. The Trinity repo is really 110+ repos.
The only option I see thus far is writing a script to query each Trinity module for the last commit on a specific date and have the script perform a 'git reset --hard {commit}' for each module.
Is there a way to perform 'git reset --hard' based on date rather than commit?
The 'git log --until" command queries the last commit on a specific date. I don't know how to extract the commit hash from that query.
To troubleshoot regressions, a future solution probably creates and archives a set of tarball snapshots with each resync of the local repo.
Darrell
On Friday 28 of September 2012 21:46:46 Darrell Anderson wrote:
Does anybody know how to do this?
The root problem is commits are module based. The Trinity GIT repo consists of more than 110 modules. To my knowledge there is no easy one-step 'git reset --hard {commit}' option available to revert an entire local Trinity repo to a previous state because commit hashes are not common among all Trinity modules.
Everything I read online addresses using 'git reset --hard {commit}' but is always focused on projects with only one repo. The Trinity repo is really 110+ repos.
The only option I see thus far is writing a script to query each Trinity module for the last commit on a specific date and have the script perform a 'git reset --hard {commit}' for each module.
Is there a way to perform 'git reset --hard' based on date rather than commit?
The 'git log --until" command queries the last commit on a specific date. I don't know how to extract the commit hash from that query.
To troubleshoot regressions, a future solution probably creates and archives a set of tarball snapshots with each resync of the local repo.
Switching the whole tree is fairly simple. First of all - you do not need git reset, but git checkout. As follows (on top of tree):
git checkout _revision_ && git submodule update && git submodule foreach "git submodule update"
The first - "checkout" - is used to switch to the desired version (see below). Second - "submodule update" - ensures switch all modules comply with the state of the tree version. Third - "submodule foreach ..." - ensures switch all nested modules comply with the state of the tree version.
Alternatively, you can simplify using --recursive:
git checkout _revision_ && git submodule update --recursive
And now, how to determine the required _revision_. To your original question probably the simplest answer is: "@{2012-04-01 00:00:00}"
git checkout "@{2012-04-01 00:00:00}" && git submodule update --recursive
Git according to the date determines, in which revision was at given date and time, performs checkout root of tree to appropriate state for this revision and subsequent "submodule update" ensures all modules to switch also to the appropriate state.
Is it sufficient?
Slavek --
Is it sufficient?
Whew! My head hurts!
How do I work with this checkout branch? Does the 'checkout' command actually copy the files in each module to a new location/directory?
My build scripts are configured to copy the sources from each GIT module to my build space. I would modify the scripts to look in this new checkout location/branch/directory to copy the sources. Or, I would write a short script to create tarballs from this checkout directory and then build from those tarballs, which my build scripts already support.
Still fuzzy in my head, but hope is improving. :)
Darrell
On Saturday 29 of September 2012 01:47:10 Darrell Anderson wrote:
Is it sufficient?
Whew! My head hurts!
How do I work with this checkout branch? Does the 'checkout' command actually copy the files in each module to a new location/directory?
My build scripts are configured to copy the sources from each GIT module to my build space. I would modify the scripts to look in this new checkout location/branch/directory to copy the sources. Or, I would write a short script to create tarballs from this checkout directory and then build from those tarballs, which my build scripts already support.
Still fuzzy in my head, but hope is improving. :)
Darrell
Checkout does not create a new directory structure, but switch your working tree to the desired revision.
So your other scripts do not need to change. Using checkout you switch your working git tree to the desired version, then you will do tasks that you need - like building. And by further checkout you switch your working git tree to the next desired version. Everything is still in the same working folder.
For example - switch whole tree to v3.5.13-sru branch:
git checkout v3.5.13-sru && git submodule update --recursive
...and switch back to current state of master branch:
git checkout master && git submodule update --recursive
Note: In this switching may occur a little problem with modules that are not contained in the desired version.
Slavek --
Checkout does not create a new directory structure, but switch your working tree to the desired revision.
So your other scripts do not need to change. Using checkout you switch your working git tree to the desired version, then you will do tasks that you need - like building. And by further checkout you switch your working git tree to the next desired version. Everything is still in the same working folder.
For example - switch whole tree to v3.5.13-sru branch:
git checkout v3.5.13-sru && git submodule update --recursive
...and switch back to current state of master branch:
git checkout master && git submodule update --recursive
Note: In this switching may occur a little problem with modules that are not contained in the desired version.
So checkout only creates a viewing illusion. That is, the package sources remain the same as the most recent re-sync and only the view a person has is different.
As my build scripts just copy the package sources directly from GIT, the view illusion does not help.
I am not grasping how my build scripts can distinguish the difference. I understand how my eyes distinguish the difference because GIT creates the illusion of what I am allowed to see. Yet the underlying sources in the package tree remain exactly the same.
Darrell
On Saturday 29 of September 2012 02:13:56 Darrell Anderson wrote:
So checkout only creates a viewing illusion. That is, the package sources remain the same as the most recent re-sync and only the view a person has is different.
As my build scripts just copy the package sources directly from GIT, the view illusion does not help.
I am not grasping how my build scripts can distinguish the difference. I understand how my eyes distinguish the difference because GIT creates the illusion of what I am allowed to see. Yet the underlying sources in the package tree remain exactly the same.
If you use in your scripts working tree contents, scripts use what you checkout before using scripts. Checkout simply ensures that the working tree will look like as it was at the required revision.
But if you use in your scripts git calls - for example git archive, you have to make an adjustment in those scripts.
Slavek --
If you use in your scripts working tree contents, scripts use what you checkout before using scripts. Checkout simply ensures that the working tree will look like as it was at the required revision.
But if you use in your scripts git calls - for example git archive, you have to make an adjustment in those scripts.
This sounds like compiling directly in the GIT tree rather than copying "out of source." I am and have been following the wiki to copy the sources to a different location to build "out of source."
Darrell
On Saturday 29 of September 2012 02:44:05 Darrell Anderson wrote:
If you use in your scripts working tree contents, scripts use what you checkout before using scripts. Checkout simply ensures that the working tree will look like as it was at the required revision.
But if you use in your scripts git calls - for example git archive, you have to make an adjustment in those scripts.
This sounds like compiling directly in the GIT tree rather than copying "out of source." I am and have been following the wiki to copy the sources to a different location to build "out of source."
Darrell
How you make: copying "out of source"? Copying the current contents of your git working tree? Well - then this is exactly what the checkout prepare.
You can checkout your git working tree to state of 2012-04-01, then copy current contents of your working tree (precisely sources in state of 2012-04-01) "out of source" and build.
Slavek --
On 29 Sep 2012, Darrell Anderson outgrape:
So checkout only creates a viewing illusion. That is, the package sources remain the same as the most recent re-sync and only the view a person has is different.
Well, that's only true inasmuch as *everything* a version control system shows you is an 'illusion' and the *real* content is a bunch of gzipped loose objects and packfiles underneath .git/objects. That's irrelevant, though -- nobody works with those. Everybody works with the working copy, and that's what 'git checkout' switches between.
As my build scripts just copy the package sources directly from GIT,
i.e. they copy them from the working tree. That's what 'git checkout' updates, so you're fine. (Unless, of course, you mean it's getting them from gitweb or something. I presume not becasue that would be just crazy :) )
I am not grasping how my build scripts can distinguish the difference. I understand how my eyes distinguish the difference because GIT creates the illusion of what I am allowed to see. Yet the underlying sources in the package tree remain exactly the same.
Nope. 'git checkout' switches those sources to the sources as they were at the requested commit. (It carries uncommitted changes over into the new tree, as best it can, and refuses to switch if it would lose them.)
On Friday 28 of September 2012 21:46:46 Darrell Anderson wrote:
The 'git log --until" command queries the last commit on a specific date. I don't know how to extract the commit hash from that query.
Just a few things that may be helpful:
git rev-parse "@{2012-04-01 00:00:00}"
git log --pretty=format:"%ci; %h; %s" v3.5.13..HEAD
Slávek --
On 28 Sep 2012, Darrell Anderson told this:
I realize that resetting my local repo will mean a
bandwidth hit when I restore everything. :)
No, don't think so. You already have a copy of the local repo, and you're not deleting any commits... So I think you could reset up back to {HEAD}.
That is where I'm confused. I _do_ want to delete all commits more recent than the date to which I reset. Otherwise I am building packages with the same current sources. I won't accomplish anything. I am looking for a way to reset my local repo to commit xxxxxxxx and delete all commits after that date. The final result is a local repo that looks exactly as GIT did on the day of commit xxxxxxxx.
This is possible, but...
I want to do this to troubleshoot a difficult bug. After installing a GIT package set from several months ago, I know the bug did not exist then. Something happened thereafter. I want to build packages from my local repo but the sources must look exactly the same as whatever date I choose.
... this has nothing to do with deleting commits. It's just checking out an earlier revision, something that git can of course do, or what's the point of a version control system? Making the sources look exactly the same as on some specific date is not something that is very well defined, because a git repository is a slice through a distributed system, so there is no single atomic view of the repository as at a given date. But you can do
git checkout $(git log --until $date -n 1 --pretty=%H) git submodule update
which will at least give you *a* view of the repo as on that day (specificically, the state of the repo when the first commit with that date hit it).
Later commits still exist in the repository: you are just on a 'detached HEAD', i.e. not on any branch. Don't commit in this state: do a 'git checkout master && git submodule update' (or some other branch name instead of master) first.
But you don't want to do this anyway: you want to use 'git bisect', which is designed for this sort of binary-searching for bugs with unknown origin. (Note that after every 'git bisect good/bad' you will need to do a 'git submodule update' to bring the submodules up to date properly.)
I want to start as far back as April 1 and then proceed forward until the bug reappears.
If you've deleted all commits after that date, proceeding forward would be impossible: the commits are gone.
But you don't want to do this anyway: you want to use 'git bisect', which is designed for this sort of binary-searching for bugs with unknown origin. (Note that after every 'git bisect good/bad' you will need to do a 'git submodule update' to bring the submodules up to date properly.)
Thank you for the explanation.
Like 'git reset --hard', seems every explanation I read is focused on a repo for a single product/package and not a multi-layered repo like Trinity. As I mentioned in a previous mail, the Trinity repo is really 134 (or so) repos, or 134 products. Whereas I can easily 'git reset --hard' or 'git bisect' an individual Trinity package/module, I can't easily bisect the entire Trinity source tree. At least, I am not seeing how to do this.
The particular regression (bug reports 1111 and 178) I am helping debug involves several Trinity packages. That is, at least tdelibs and k3b are involved, probably tdebase too. Yet tdelibs affects all packages. The regression might have been introduced in the many commits with the new TDEHW libs, which includes tdebase. Any reset or bisect of tdelibs or tdebase likely requires all dependent packages to be reset/bisected too.
The challenge is that Trinity packages are all interrelated. Proper testing requires all packages be rebuilt the same as they were on the same date.
For me to troubleshoot by building packages from a specific date requires me to reset (bisect) many Trinity modules, possibly all.
At this point nobody yet knows when this regression started because the particular feature is not something everybody uses every day. Just today, we discovered the bug is masked when used through NFS shares, hence a previous leaning the problem was distro specific or PEBKAC.
Based upon the bug report dates, the regression appeared some time before the middle of July. A package set I found in my backups from March 27 does not exhibit the regression, but based upon the recent news about NFS masking, I should retest those packages without that layer.
I don't mind the work involved with rebuilding packages, testing, etc. I just am not seeing how to get there because of the complex relationship of all Trinity packages. :(
I might start storing tarball snapshots each time I re-sync my local tree and then always build only from tarballs rather than my local GIT tree. For sure I'm going to become more rigorous about archiving package sets, which would allow faster testing of regressions.
Darrell
On 29 Sep 2012, Darrell Anderson said:
But you don't want to do this anyway: you want to use 'git bisect', which is designed for this sort of binary-searching for bugs with unknown origin. (Note that after every 'git bisect good/bad' you will need to do a 'git submodule update' to bring the submodules up to date properly.)
Thank you for the explanation.
Like 'git reset --hard', seems every explanation I read is focused on a repo for a single product/package and not a multi-layered repo like Trinity. As I mentioned in a previous mail, the Trinity repo is really 134 (or so) repos, or 134 products. Whereas I can easily 'git reset --hard' or 'git bisect' an individual Trinity package/module, I can't easily bisect the entire Trinity source tree. At least, I am not seeing how to do this.
You can 'git bisect' the top-level repo, and 'git submodule update' between each step -- but if there were multiple commits in a submodule which were skipped over by the overarching module, 'git bisect' will not descend into them. It doesn't really understand submodules.