Enjoy the Git workflow while working with Perforce!

Here are some of the advantages over Perforce with Git workflow I've found:

  • File diff, time-lapse view and things alike can be done locally without network;
  • Several independent changes to the same file can be separated to individual changelist with ease;
  • Local branches made easy and cheap;
  • Tooling around git can be integrated into workflow, e.g. git integration with IDEs, git hooks, tig;

To use Git with Perforce, we have

git-p4.py – A tool for bidirectional operation between a Perforce depot and git.

Installing git-p4

git-p4 usually comes with git installation, so most of the time no extra download and installation are needed, though installation of p4 is required anyway.

But if your git installation was built with NO_PYTHON=1:

fatal: git was built without support for git-p4 (NO_PYTHON=1).

or encounter the following error:

git: 'p4' is not a git command. See 'git --help'.

Then you need to download git-p4.py at https://raw.githubusercontent.com/git/git/master/git-p4.py manually, put it into one of your PATH directory, run chmod +x, and use it as git-p4.py or git p4.py instead of git p4.

Alternatively, rename the downloaded git-p4.py to git-p4, so that you can use it as git p4.

(Note that currently git-p4.py works with python2 only.)

Configuring Perforce for Command Line Use

Before everything begins, we need to configure Perforce for command line use.

Global Settings

p4 set P4PORT=perforce.company.com:1666
p4 set P4USER="Your Name"
p4 set P4CLIENT=Workspace_Name
p4 set P4EDITOR=vim

On Windows, 'p4 set' sets Perforce variables in the Windows registry to the specified values. If you omit the value, the variable is unset. On other platforms, 'p4 set' sets Perforce variables in the P4ENVIRO file.

Notes:

  • You can use p4 set to list current variable settings.
  • Corresponding environment variables take precedence over p4 set.

Per Workspace Settings

Via .p4config

Note: This does NOT work on Cygwin! See Per Workspace Settings via .gitconfig or use global settings.

To set per workspace settings via .p4config, you may need to create the target directory for import beforehand, and cd to that directory.

Create a config file (e.g. .p4config) in the workspace root or in its parent directories with workspace-specific settings in it:

P4PORT=perforce.company.com:1666
P4USER="Your Name"
P4CLIENT=Workspace_Name

And make perforce aware of this by running

p4 set P4CONFIG=.p4config

Note that P4CONFIG

Contains a file name without a path. The specified file is used to store other Perforce environment variables. The current working directory (returned by PWD) and its parents are searched for the file. If a file is found, the variable settings within the file are used. If additional files are found in parent directories, and they contain variable settings not already found in other files, those variable settings are also used.

More about P4CONFIG on P4CONFIG // P4 Command Reference.

Via .git/config

To set per workspace settings via .git/config, you need to create the target directory for import beforehand, cd to that directory, and run git init.

All config related to git p4 command are put under the prefix git-p4..

# The -p flag specifies the server's listen address, overriding the
# value of $P4PORT in the environment and the default (perforce:1666).
git config git-p4.port "..."

# The -c flag specifies the client name, overriding the value of
# $P4CLIENT in the environment and the default (the hostname).
git config git-p4.client "..."

# The -u flag specifies the user name, overriding the value of
# $P4USER, $USER, and $USERNAME in the environment.
git config git-p4.user "..."

# The -P flag specifies the password, overriding the value of
# $P4PASSWD in the environment.
git config git-p4.password "..."

# The -H flag specifies the host name, overriding the value of
# $P4HOST in the environment and the default (the hostname).
git config git-p4.host "..."

# The -r flag specifies the number of times a sync command should be
# retried if the network times out (takes longer than N seconds to
# respond to a single I/O operation) during sync command execution.
git config git-p4.retries "..."

Importing Depot

The very first step of working in Git workflow with Perforce depot is to import the depot to a Git repository.

Note: The workspace root folder used by Git-p4 should be different from the one that Perforce uses; i.e. you will need two different workspaces for a single project, one for use by Perforce, and the other for use by Git-p4. Otherwise, it will cause problems when running git-p4 submit to submit your local changes.

For example, if you were using /a/dir/to/your/project as the workspace root in Perforce, I suggest to move it to /a/dir/to/your/project.p4 and import your depot to /a/dir/to/your/project via git-p4.

To import a depot into a git repository:

# Import an all-in-one commit with all files in the latest changelist of the
# specified depot path.
git p4 clone //depot/my/project

# Import one commit per changelist in the history of the specified depot path.
git p4 clone //depot/my/project@all

# Import an all-in-one commit with all files under the specified depot path
# from the state at changelist 20451.
git p4 clone //depot/my/project@20451

# Import only changelist 20451.
# Note: Files which are in the depot path, but are not modified within the
#       specified changelist will not get imported.
git p4 clone //depot/my/project@20451,20451

# Import only changelists 20451 through 24601.
# Note: Files which are in the depot path, but are not modified within the
#       specified changelist range will not get imported.
git p4 clone //depot/my/project@20451,24601

Note: If you've already created the target directory for import and is in that directory, you need to run git p4 clone //??? .. Replace //??? with your actual depot path specification and note the trailing ., which tells git to clone into current directory.

If you need all files under a certain depot path, with history starting from a given changelist, or you know which changelist the history begins with, you can execute the following commands to speed up the initial clone. Since you are giving a changelist number to start with, git-p4 is able to skip scanning and possible importing of changelists preceding the given one, which speeds up the process.

# Import all files in the specified depot path at the state of given changelist
git p4 clone //depot/my/project@20451          # Method 1
# or only import files not only in the specified depot path
# but also modified in the given changelist.
git p4 clone //depot/my/project@20451,20451    # Method 2

# Import history of the specified depot path from the given changelist to latest
git p4 rebase

Method 1 and 2 have the same effect as to the files imported if the specified changelist is the first changelist regarding the specified depot path. However, method 2 has the advantage of keeping the original changelist description, while method 1 will discard it and rewrite the description as Initial import of //depot/my/project/ from the state at revision @20451.

If your depot is very large, and importing all of them in a single shot often results in failure due to network error. You may consider import only some of the changelists at a time.

# The initial import: Import one changelist to bootstrap.
# Import all files in the specified depot path at the state of given changelist
git p4 clone //depot/my/project@20451          # Method 1
# or only import files not only in the specified depot path
# but also modified in the given changelist.
git p4 clone //depot/my/project@20451,20451    # Method 2


# Secondly, import other changelists part by part.
# Sync at most 100 changelists at a time. (Specified by `--max-changes`)
# `--changes-block-size` is the number of changelists to be searched at a time.
git p4 sync --changes-block-size=100000 --max-changes=100

# Repeat this sync process until all changelists have been imported.


# Finally, reset local master branch to point to p4/master
git reset --hard p4/master

Configuring P4 Workspace

After or before importing code in Perforce to Git, we need to create/edit a perforce workspace which has workspace mappings include the path imported.

In addition, if you are going to run git-p4 under Cygwin or other linux-like environment, you need to put the linux-like environment path into the alt roots of the workspace.

For example,

Workspace Root
(Windows path)
-> Alt roots
(Linux path)
D:\depot\proj1\dir2.p4 -> /cygdrive/d/depot/proj1/dir2.p4

Working in Git

Once a Perforce depot is imported to a Git repository, we can work in Git.

Git-p4 workflow follows this pattern:

  1. Edit files
  2. Submit edits to Git (git add, git commit)
  3. Repeat 1-2
  4. git p4 rebase
  5. git p4 submit

And that's it with no more steps.

Compared to Git workflow:

  1. Edit files
  2. Submit edits to Git (git add, git commit)
  3. Repeat 1-2
  4. git pull --rebase
  5. git push

Comparison of Commands in p4, git-p4 and git

p4 git-p4 git
p4 clone git p4 clone git clone
p4 sync git p4 sync git fetch
git p4 rebase * git fetch && git rebase
p4 submit git p4 submit or
git p4 commit
git commit && git push

* git p4 rebase is basically equivalent to git p4 sync && git rebase p4/master.

Skipping editing changelist description

When we work in git, we use git commit message as an equivalent to Perforce changelist description. However, by default, when we run git p4 submit, it asks to edit existing commit message before submitting. To simply use git commit message and skip this editing, run the following command:

git config --global git-p4.skipSubmitEdit true

Configuring the Imported Repository

To make Git and Perforce work in harmony on Windows or other platforms, we need to do some config in Git (and Perforce).

Setting Line Ending

On Windows, we may need to check out files in CRLF line ending.

git config core.autocrlf true

Setting this variable to "true" is almost the same as setting the text attribute to "auto" on all files except that text files are not guaranteed to be normalized: files that contain CRLF in the repository will not be touched. Use this setting if you want to have CRLF line endings in your working directory even though the repository does not have normalized line endings. This variable can be set to input, in which case no output conversion is performed.

Existing files are not modified when new config applied, so we need to remove all the files from index, and reset the state.

!!Note: Be sure to back up uncommitted changes, or they will get lost forever after hard reset.

git rm --cached -r .
git reset --hard

See Dealing with line endings - User Documentation for more details.

Ignoring Executable Bit Changes

On Windows, we may need to ignore the change of executable bit.

git config core.filemode false

Tells Git if the executable bit of files in the working tree is to be honored.

Some filesystems lose the executable bit when a file that is marked as executable is checked out, or checks out an non-executable file with executable bit on. git-clone(1) or git-init(1) probe the filesystem to see if it handles the executable bit correctly and this variable is automatically set as necessary.

A repository, however, may be on a filesystem that handles the filemode correctly, and this variable is set to true when created, but later may be made accessible from another environment that loses the filemode (e.g. exporting ext4 via CIFS mount, visiting a Cygwin created repository with Git for Windows or Eclipse). In such a case it may be necessary to set this variable to false. See git- update-index(1).

The default is true (when core.filemode is not specified in the config file).

Setting Authorship

Check current settings in Perforce Visual first:

Connection --> Edit Current User... --> Full name
                                    \-> Email

Then change directory to the Git repository, and do the same config in Git for the imported repository.

git config user.name "Your Name"
git config user.email "[email protected]"

Troubleshooting

Patch does not apply

error: patch failed: path/to/the/edited/file:42
error: path/to/the/edited/file: patch does not apply
Unfortunately applying the change failed!

Solution 1:

If a file is to be checked in with different line ending from the one when checked out, git p4 will complain that patch does not apply.

We may check whether this is the problem by following these steps:

  1. Reconcile Offline Work in Perforce;

    In Perforce Visual, right click on a Depot/Workspace folder, select Reconcile Offline Work….

  2. Make diff of the changed files

    Remember to recognize line ending differences.

    In Perforce P4Merge window:

    File --> Comparison Method --> Recognize Line Ending and White Space Differences
    

    If the whole file are shown in green, then we know that the line ending is changed.

To solve the problem, make sure the line ending config in Perforce workspace matches the config (core.autocrlf) in Git repo.

Check the line ending config for Perforce workspace:

Connection --> Edit Current Workspace... --> Advanced --> Line ending characters for text

Solution 2:

This problem may also caused by other things. Alternatively, we may choose to do the submit process in Perforce Visual:

  1. Navigate to the directory where changes reside in Perforce Visual;
  2. Right click on the directory, Select Reconcile Offline Work…;
  3. Check the files to be submitted;
  4. Submit the changelist.

More Help