After doing a git-p4 clone --use-clientspec
, I would like to add an extra entry to the clientspec, and import the current state of the added entry to my Git repository.
After I extend the clientspec, a git-p4 rebase
does nothing (probably because there was no new relevant changelist since the last committed change, all I did was update the clientspec)
I tried doing a git-p4 sync --use-client-spec
, but this complains that fast-import failed because the new tip does not contain my initial commit.
Is there a way to extend the client spec, without having to git-p4 clone
a new Git repository from scratch?
As of writing, I could not find a way to get git-p4
to import additional paths from a Perforce clientspec directly. However, I believe that I've devised a way to manually do it and have git-p4
honor it.
Disclaimer: I take no responsibility for any damage that the following steps might cause. It probably would be a good idea to back up your .git
tree first.
As you say, just adding a path to the Perforce clientspec and doing a git p4 rebase
initially does not do anything. However, I noticed that git p4 rebase
will add files from that path after they are modified in Perforce and if the new path is within git-p4
's depot-paths
list. (depot-paths
is the initial list of depot paths provided to git p4 clone
.) Therefore you need:
git-p4
into believing that it added that initial copy itself.git-p4
to include the new path in its depot-paths
list.Thus you can sync a copy of the files from Perforce, making sure that they're consistent with the files already imported from Perforce, and then you can explicitly add them to your Git repository.
git-p4
apparently does not store its depot-paths
list nor the last imported Perforce change number anywhere other than in Git commit messages, so you can trick git-p4
by replicating its metadata in your own commit message.
Finally, you can move p4/master
(and p4/HEAD
, which is an alias to p4/master
) to point to your new commit so that future git p4 rebase
commands treat that commit as something imported from Perforce.
Check out the commit corresponding to p4/master
. Make sure that you don't have any staged or unstaged changes. Stash them if you do.
Add the new path to the Perforce clientspec used by git-p4
. In the steps below, I'll refer to this as //depot/new/path/
.
Run git log
to look at the commit message from the Perforce change you last imported. It will have a line that looks like:
[git-p4: depot-paths = "//depot/tree/": change = 12345]
Make a note of the Perforce change number.
In your Perforce client, sync your added path to that change number. For example: p4 sync //depot/new/path/...@12345
Recursively copy those newly synced files from your Perforce client into the corresponding location in your Git repository. (Some care might be needed here if there are symlinks.)
Run git add
on that new path in your Git repository.
Run git commit
. You can mostly say whatever you want in your commit message (e.g. "Initial import of //depot/new/path/ from CLN 12345"). However, at the end of the message you must copy the git-p4
metadata line that you observed before:
[git-p4: depot-paths = "//depot/tree/": change = 12345]
If //depot/new/path/
is not a subdirectory of //depot/tree
, then you must amend depot-paths
to add the new path:
[git-p4: depot-paths = "//depot/new/path/,//depot/tree/": change = 12345]
The depot-paths
list must be sorted by ASCII value (i.e., //depot/foo-bar/
should precede //depot/foo/bar/
).
Run git log
again. Confirm that the git-p4
line in the commit message looks like ones from imported Perforce changes. Make a note of the SHA1 hash of your commit.
Navigate to the root of your Git repository. Edit .git/refs/remotes/p4/master
. Remove the old SHA1 hash listed and replace it with the SHA1 hash of your commit. (If .git/refs/remotes/p4/master
does not exist, check .git/packed-refs
and update the appropriate line there.)
Now your Git repository includes a copy of the files from //depot/new/path/
from change 12345, and it should pick up any changes to those files from future Perforce changes.
Obviously the new path will exist in your Git repository only after your commit that imported those files, so git bisect
won't be useful if it straddles that boundary and involves those files.
Since modified files get automatically added if they're included in your Perforce clientspec (and are contained within git-p4
's depot-paths
), in some cases you potentially could avoid all of this work. For example, if you know in advance that someone is going to be adding a new directory to the Perforce depot and that directory is already included by your depot-paths
but not by your clientspec, you can just preemptively add it to your Perforce clientspec. You then should be able to get that new path automatically after it's actually added to Perforce.
Alternatively you could add the new path to your Perforce clientspec and then submit a Perforce change that touches all of the files in that path. I do not recommend doing that, however, as that could be disruptive to others (and imagine if everyone else did that). I mention it only for completeness.
@jamesdlin's answer is what worked for me. While researching ideas for how to solve this, I came across a couple other stackoverflow answers that were interesting. I wonder if they could be combined to create an elegant solution. I'm mentioning the idea here in case it helps someone else. This idea is a variation of what's described in How to copy commits from one Git repo to another? and borrows an idea from git clone multiple p4 paths in one git repo.
git p4 clone newstuff ...etc...
git remote add newstuff /path/to/newstuff
git merge
, with --allow-unrelated-histories
if needed.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With