P4 Shelve: What is actually saved? - version-control

I've used a number of version control systems over the years, and would say I've mastered SVN and Mercurial, but now I have a contract which requires me to use perforce. I have the basics under control, but occasionally I find an area where it's not clear exactly what perforce is doing.
Shelving changes is one of these.
This week I was in a situation where I was in the middle of a piece of work, and needed to change focus and work on a quick fix for someone. The old work was based on an older revision, and for the new piece of work I needed to be at the latest. So I...
Shelved my current changelist.
Updated my workspace to the latest revision
Did my work
Submitted it.
Unshelved my original changes
I knew I was at the latest revision when I unshelved, but "That's OK, I needed to update anyway". What surprised me was that I didn't need to resolve any files. Unsure about why that would be I...
Reverted my workspace
Updated to the revision I'd originally been working at
Unshelved my files again (I hadn't deleted the shelved version)
Updated to the latest revision
At this point perforce asked me to resolve files, and it wasn't a trivial resolve (i.e. not one that could have been done automatically).
This has left me with questions:
Is shelve just copying a file out of the way, and then copying it back? or is it storing a delta?
Is it possible to cause other's changes to be undone by using shelve?
How should I be working when this situation arises in the future?

p4 shelve saves your files on the Perforce server, but doesn't remove your pending changes from your current workspace. After issuing the p4 shelve command, you could have issued a p4 revert command to restore your workspace to the unmodified versions of your files, but from your description, it looks like you didn't do that.
So your update to the latest revision step (p4 sync) brought all the unopened files up to the head revision, but left your opened files as they were before you shelved them.
Your unshelve command had no real effect, since the files were already in the state you left them in before you shelved them.
As to your questions:
shelve is copying the files (probably as a delta, but it's not important to me as a user) to a place where you (or your coworkers) can get them later, but it's not "out of the way," since it doesn't automatically revert your shelved changes in your local workspace
shelving itself doesn't change the head revision of the file in Perforce; it's more like a micro branch. However, when you unshelve a file, you may have to integrate the changes you made before shelving the file with changes that have been made to the file since it was shelved. This can lead to others' changes being undone if you're not careful.
Strenuously.

Related

How to undo a resolve in perforce?

I am new to this and facing some trouble while checking in my code for the first time.
I have a bunch of opened files in my client. After making my changes, I did a sync to sync my client to depot. Then I did p4 resolve to resolve the changes. Now, for some files, I had few conflicts. I mistakenly messed up those files and I am not sure how my version is different than the most recent checked-in version in the depot. So, this is what I was trying to do...
Sync back to a previous change list, then again do a sync to the HEAD and do p4 resolve- however now it's saying there there is nothing to be resolved.
I did a p4 revert to revert my changes, then again modified my files and did sync-> resolve. However again, I'm getting "nothing to be resolved" message.
I am using p4 command line. How can I get back to my old state and resolve the changes?
If you originally made the changes on your local machine and didn't submit them to a branch or shelve them, then you probably wiped out the state of those changes when you ran p4 revert (if not before).
If you then synced back to the HEAD and manually redid your changes at that point, then there's genuinely nothing to resolve because you already had the latest revision from the depot before you made your changes.
I would advise checking that your pending changelist has exactly the changes you want and nothing more, either by right-clicking and choosing "Diff against have revision" in p4v, or using p4 diff from the command-line. If there's nothing unexpected in there, then submit those changes.

How does Perforce deal with changes made after merge/integrate, but before submit?

I have seen behaviour in Perforce that I am unable to explain. I took a branch of the trunk and worked on this regularly committing my changes and occasionally merging from the trunk to my branch to ensure there were not going to major conflicts when I reintegrated.
When this work was complete, I used the Perforce Merge/Integrate option to apply the changes to the trunk. After sending these changes for code review, I made some changes on the trunk. At this point, none of the changes had been committed to the trunk.
When I went to commit all of these changes, the diff showed the files exactly as I would expect. After submitting the changelist, the changes which were submitted were not the same as what was shown in the diff window. Instead, the changes that I'd made since the Merge/Integrate were not there. Doing a diff between the server and my local copy on the trunk had all of the changes to the same files made after the code review. As such, I had to do a second commit to mend the broken build.
I'm confused how this happened as I thought Perforce only kept one local copy of each file on the client?
Even if there is a flag showing the files have been tampered, where were the files it submitted? It definitely showed the trunk paths in the commit window, but I guess it could have got the files from the branch?
Another question would be, how should I have best dealt with the above scenario when using Perforce version control?
One mistake we've all made is to (a) integrate a file from one branch to another, (b) resolve it as "accept merged", (c) make local changes to the file prior to (d) submit. If you don't explicitly open the file for edit after step (b) and before step (c), the server has no knowledge of your local changes.
You made your first mistake editing things directly on your copy of trunk. Always use a task branch. It probably didn't cause the issue you were seeing, but if you'd messed up your task branch it wouldn't have broken the build. When looking at your local copy of trunk, ensure you've refreshed it from the depot. You'll get little yellow triangles if your local copy of a trunk file is out of date, editing and committing an out of date file on your copy of trunk is bound to lead to "odd" behaviour.
I'm confused how this happened as I thought Perforce only kept one local copy of each file on the client?
One copy for trunk, one copy for each task branch.

Mercurial: Can you track changes across a file that has been renamed to another tracked file?

I know that you can track changes to renamed files from a repo to it's clone. However, I seem to have an issue when I rename a file to a file name that is already being tracked. In essence, I want to copy over a tracked file.
Files in original repo:
application.txt
special.txt
Then clone the repo, delete application.txt and rename special.txt to be application.txt
I would expect that the next time I made changes to special.txt in the original repo, the changes would carry over to application.txt. However, it doesn't. I get this message
local changed special.txt which remote deleted
use (c)hanged version or (d)eleted?
Trying this same thing out in Git seems to have the same results. Renaming a file to a brand new name has no issues while trying to rename a file that has already been 'taken' causes conflicts. Is there any way around this?
I wouldn't really call this a bug, as you have for all purposes just changed the contents of a file that mercurial is already tracking. Mercurial tracks files by file name and extension, and you could make the case that this is no different than just replacing the entire contents of the file.
I just had this problem in a real world project with Mercurial. GIT is also seeing bogus conflicts (special.txt deleted and updated).
Bazaar has proper rename support and it merges this case correctly (changes to special.txt are carried over and application.txt get updated as expected).
The problem with Bazaar though (at least for me) is that it lacks IntelliJ support. There are 2 plugins, the most recent has not been updated for 3 years, and last time i tried it was unusable with recent IntelliJ versions.
Since "bzr mv" and "bzr rename" need to be invoked by the IDE at the time of refactoring, the lack of support makes Bazaar unusable for me.
If you want IntelliJ support for this, vote here: http://youtrack.jetbrains.com/issue/IDEABKL-5344

How can I do a partial update (i.e., get isolated changesets) from subversion with subclipse?

If a file is committed several times with various changes, how can I fetch one change at a time, i.e., one changeset at a time?
I use eclipse, subversion, and subclipse, and I can't change the former two for the time being (or the MS platform..).
In my Team/Synchronization view in eclipse (using subclipse), choosing the changeset model, a file seems to be listed only in the latest relevant changeset even if all changesets are listed. So an earlier changeset doesn't necessarily show the full set of files in the original commit, nor the original diff for a file in a commit.
Update: I'm thinking about using changesets for simplified code review, so I'd like the partial update represented for all the files commited in one changeset. It's easy to get diffs and specific revisions for specific files in eclipse, but I'd like to step through all the changes in one specific commit/ changeset in a practical manner.
As I'm sure you know, svn up will by default grab the latest revision of the file.
However, you can use the -r parameter to svn up to grab a particular revision of a file. So if you know a file was committed in revisions 5, 7, and 9, you could do this:
svn up -r5 myfile
svn up -r7 myfile
svn up -r9 myfile
I believe (but I don't have an installation of it in front of me) that Subclipse has a similar option, labeled something like "Update to Revision..."
Subversion does not support atomic changesets.
(Note: If anyone can prove me wrong, I'll happily switch accepted answer.)
I've compared Git and Subversion using TortoiseGit and TortoiseSVN (and looked at what is possible on the command line).
With both Svn and Git I can update to a certain revision, or see and update to different versions of only one file at a time.
With both Tortoise clients can I see individual commits (revisions) from the repository and look at changes between a revision and the previous revision. (Note that I can't seem to do this in Eclipse, ref the question.)
Only with Git, however, can I update to or cherry-pick an isolated commit. The closest I've seen to this functionality in Subversion is to update to head and then revert a certain revision with a "subtractive merge"...
Test setup: make a project, check out or clone the project, make 2 separate commits to repository from elsewhere, including at least one file that is modified in both commits.
Then, with Git: fetch remote changes.
Then, with both Git and Subversion: look at the log.

Can someone explain the perforce integration options?

Specifically:
Why do I need to explicitly enable "Enable baseless merges" all the time? I am integrating from my branch to the trunk.
What does "Enable integrate over
deleted targets" mean? Shouldn't it
do this by default? If the file
doesn't exist, and you integrate to
that branch with the file, it should
create the file, right??
What does "Do not get latest revision
of selected files" have to do with
integrating? I should be choosing a
source revision, and a target (to
create a new target revision).
What does "Disregard indirect
integration history" mean? I've never used it, since it sounds scary.
I would be grateful to know, as I am a little unsure of what options to enable when I am trying to do various integration tasks from our trunk to various branches or vice versa. (I am not the buildmaster, but hey, I want to know what he knows).
Why do I need to explicitly enable
"Enable baseless merges" all the time?
I am integrating from my branch to the
trunk.
Can't help you here. Something is not right.
What does "Enable integrate over
deleted targets" mean?
If the target file has been deleted and the source file has changed, will re-branch the source file on top of the target file. Without this option, a file on the branch, that has been changed on the branch and deleted on the trunk, would not be allowed to be integrated back into the trunk.
Shouldn't it do this by default?
Not if you are integrating a file back into the trunk, which you branched from the trunk, then deleted on the trunk. Normally 'p4 integrate' avoids mixing outstanding edits with a deleted file. You have to use the advanced options to tell it how to deal with a deleted file.
If the file doesn't exist, and you
integrate to that branch with the
file, it should create the file,
right?
When integrating a file, that previously never existed (i.e., it was added to the branch), from one location to another, yes, Perforce will simply create it in the location into which you are integrating. However, if the file originally came from the trunk, was deleted on the trunk, and now you're trying to integrate it back into the trunk from the branch, you have to tell it what to do via these integration options. Here's the command line switches to which these options correspond:
Enable integrations around deleted revisions = -d
Integrate over deleted targets = -Dt
Delete target file when source is deleted = -Ds
Try to integrate changes when source is deleted and re-added = -Di
You can learn more about them in the integrate command help (type "p4 help integrate" at the command line).
What does "Do not get latest revision
of selected files" have to do with
integrating?
This tells Perforce to use the workspace revision of the target file. By default, the head revision of the target file is automatically retrieved into the workspace before integrating. Say you have made one revision to a branch file and integrated it back into the trunk. The trunk and branch now have two revisions of this file. You submit a change to the branch file so it now has 3 revisions. You sync the branch file back to revision 2. If you were to do a normal integration right now, Perforce would assume you want to integrate everything up to the head revision and would integrate revision 3 of the branch file into the trunk. If you were to select this option, it would say, "all revision(s) already integrated" because you have revision 2 in your workspace. It would be the same as attempting to integrate with the "Limit the range of the integration:" option set to "Integrate all revisions up to:" Revision 2.
What does "Disregard indirect
integration history" mean? I've never
used it, since it sounds scary.
I can't figure out, nor find any info about, what this does.
In general, to merge two files, perforce looks for a "base", the closest revision to the two files, and uses that to provide a much better diff than just directly running a diffing the two files. See Knowledge Base Article. Without knowing your perforce setup, I couldn't say what was going wrong, however, p4win has some nice graphical tools to visualize branches, you might be able to determine why perforce can't find a base for you. This is also what "Disregard indirect integration history" does: stops it from looking for the base.
For the "don't sync to head": when integrating, your "target" is the files in your local client, which you aren't specifying a revision for; instead, perforce will either sync your revision head (if you don't use "-h"), or will use the one you currently have. You can't specify an arbitrary revision because your local client only has a particular one.
"Enable integrate over deleted targets" can lead to problems if done blindly. Here's an example: Imagine you refactor your code in your next release branch, and eliminate a source file as a result - the functionality was merged into some other source files. You then fix a bug in that original source file in a maintenance branch for the previous release. If you integrate over delete by default, the dead source file comes back, but it won't be built and the bug wouldn't have been fixed. It'd better to be warned that this occurred so you could manually merge the fix into the other source files.