├── LICENSE.md.meta
├── README.md.meta
├── Editor
├── Resources
│ ├── GitMergeBox.psd
│ ├── GitMergeLogo.psd
│ ├── Licenses.txt.meta
│ ├── GitMergeStyles.asset.meta
│ ├── Licenses.txt
│ ├── GitMergeBox.psd.meta
│ ├── GitMergeLogo.psd.meta
│ └── GitMergeStyles.asset
├── Resources.meta
├── VCS.meta
├── MergeActions.meta
├── Utilities.meta
├── VCS
│ ├── VCS.cs.meta
│ ├── VCSGit.cs.meta
│ ├── VCSException.cs.meta
│ ├── VCSException.cs
│ ├── VCSGit.cs
│ └── VCS.cs
├── Resources.cs.meta
├── ThirteenPixels.GitMerge.asmdef.meta
├── GitMergeWindow.cs.meta
├── MergeManagerBase.cs.meta
├── MergeManagerPrefab.cs.meta
├── MergeManagerScene.cs.meta
├── ObjectDictionaries.cs.meta
├── GameObjectMergeActions.cs.meta
├── MergeActions
│ ├── MergeAction.cs.meta
│ ├── MergeActionExistence.cs.meta
│ ├── MergeActionParenting.cs.meta
│ ├── MergeActionChangeValues.cs.meta
│ ├── MergeActionNewComponent.cs.meta
│ ├── MergeActionNewGameObject.cs.meta
│ ├── MergeActionDeleteComponent.cs.meta
│ ├── MergeActionDeleteGameObject.cs.meta
│ ├── MergeActionExistence.cs
│ ├── MergeActionDeleteGameObject.cs
│ ├── MergeActionNewGameObject.cs
│ ├── MergeActionNewComponent.cs
│ ├── MergeActionDeleteComponent.cs
│ ├── MergeActionParenting.cs
│ ├── MergeAction.cs
│ └── MergeActionChangeValues.cs
├── Utilities
│ ├── ObjectExtensions.cs.meta
│ ├── GameObjectExtensions.cs.meta
│ ├── SerializedPropertyExtensions.cs.meta
│ ├── ObjectID.cs.meta
│ ├── PageView.cs.meta
│ ├── MergeFilter.cs.meta
│ ├── MergeFilterBar.cs.meta
│ ├── GUIBackgroundColor.cs.meta
│ ├── GUIBackgroundColor.cs
│ ├── ObjectExtensions.cs
│ ├── MergeFilterBar.cs
│ ├── ObjectID.cs
│ ├── PageView.cs
│ ├── GameObjectExtensions.cs
│ ├── MergeFilter.cs
│ └── SerializedPropertyExtensions.cs
├── ThirteenPixels.GitMerge.asmdef
├── Resources.cs
├── MergeManagerBase.cs
├── MergeManagerScene.cs
├── MergeManagerPrefab.cs
├── ObjectDictionaries.cs
├── GameObjectMergeActions.cs
└── GitMergeWindow.cs
├── Editor.meta
├── CHANGELOG.md.meta
├── package.json.meta
├── CHANGELOG.md
├── README.md
├── package.json
└── LICENSE.md
/LICENSE.md.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 785798e4822ed284b8daad687e2df88d
3 | DefaultImporter:
4 | userData:
5 |
--------------------------------------------------------------------------------
/README.md.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: b364bc2946220bf428dccb47dbcee795
3 | DefaultImporter:
4 | userData:
5 |
--------------------------------------------------------------------------------
/Editor/Resources/GitMergeBox.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FlaShG/GitMerge-for-Unity/HEAD/Editor/Resources/GitMergeBox.psd
--------------------------------------------------------------------------------
/Editor/Resources/GitMergeLogo.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FlaShG/GitMerge-for-Unity/HEAD/Editor/Resources/GitMergeLogo.psd
--------------------------------------------------------------------------------
/Editor.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 13c149b5679992c4aad3260153c5f7ae
3 | folderAsset: yes
4 | DefaultImporter:
5 | userData:
6 |
--------------------------------------------------------------------------------
/Editor/Resources/Licenses.txt.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: fcbbf2375e3889c4398c97d289eab2ac
3 | TextScriptImporter:
4 | userData:
5 |
--------------------------------------------------------------------------------
/Editor/Resources.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 718f5b21123c36448b66c0e2ec52031c
3 | folderAsset: yes
4 | DefaultImporter:
5 | userData:
6 |
--------------------------------------------------------------------------------
/Editor/Resources/GitMergeStyles.asset.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: a88667aa2092d4b46aa3ad92e778e994
3 | NativeFormatImporter:
4 | userData:
5 |
--------------------------------------------------------------------------------
/Editor/Resources/Licenses.txt:
--------------------------------------------------------------------------------
1 | Git Logo by Jason Long [used in GitMergeLogo.psd] is licensed under the Creative Commons Attribution 3.0 Unported License.
--------------------------------------------------------------------------------
/CHANGELOG.md.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 4e6e06c50abd73548b1cb0e188e376f6
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/package.json.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 90678a57e53d4b44cb92ee6041bd5a1b
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Editor/VCS.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 69dff03f1fb53f248beefa85b552d2a1
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## [0.1.0] - 2020-04-23
2 | - Add package.json and changelog.
3 | - The tool is in a halfway working state since development was forced to be on hold for five years. Thus, the version number starts at v0.1.0.
4 |
--------------------------------------------------------------------------------
/Editor/MergeActions.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: c07bea28e6453b245a26dd5bb2a75d1a
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Editor/Utilities.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 04df0253576a3944ea3e76382e336da9
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Editor/VCS/VCS.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: a08026e2ac14c0446a85134863995fd0
3 | MonoImporter:
4 | serializedVersion: 2
5 | defaultReferences: []
6 | executionOrder: 0
7 | icon: {instanceID: 0}
8 | userData:
9 |
--------------------------------------------------------------------------------
/Editor/Resources.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 67422f4e577bb17409644dcfe6bf75c8
3 | MonoImporter:
4 | serializedVersion: 2
5 | defaultReferences: []
6 | executionOrder: 0
7 | icon: {instanceID: 0}
8 | userData:
9 |
--------------------------------------------------------------------------------
/Editor/ThirteenPixels.GitMerge.asmdef.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 13e5a9e99b20be54998e95b60302a730
3 | AssemblyDefinitionImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Editor/VCS/VCSGit.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: b4b1187c33991394a9c66710b250f24b
3 | MonoImporter:
4 | serializedVersion: 2
5 | defaultReferences: []
6 | executionOrder: 0
7 | icon: {instanceID: 0}
8 | userData:
9 |
--------------------------------------------------------------------------------
/Editor/GitMergeWindow.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: aaa504546605b3a479405bee3c11cd04
3 | MonoImporter:
4 | serializedVersion: 2
5 | defaultReferences: []
6 | executionOrder: 0
7 | icon: {instanceID: 0}
8 | userData:
9 |
--------------------------------------------------------------------------------
/Editor/MergeManagerBase.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: b7759967878514e4aace05e726704e8f
3 | MonoImporter:
4 | serializedVersion: 2
5 | defaultReferences: []
6 | executionOrder: 0
7 | icon: {instanceID: 0}
8 | userData:
9 |
--------------------------------------------------------------------------------
/Editor/MergeManagerPrefab.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: f8db1a549c01168468790b325c85f3c1
3 | MonoImporter:
4 | serializedVersion: 2
5 | defaultReferences: []
6 | executionOrder: 0
7 | icon: {instanceID: 0}
8 | userData:
9 |
--------------------------------------------------------------------------------
/Editor/MergeManagerScene.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 2143b0a739488bb4698c51777c4863fc
3 | MonoImporter:
4 | serializedVersion: 2
5 | defaultReferences: []
6 | executionOrder: 0
7 | icon: {instanceID: 0}
8 | userData:
9 |
--------------------------------------------------------------------------------
/Editor/ObjectDictionaries.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: e2d4344037c6c7c4ca962a1e4037b6fe
3 | MonoImporter:
4 | serializedVersion: 2
5 | defaultReferences: []
6 | executionOrder: 0
7 | icon: {instanceID: 0}
8 | userData:
9 |
--------------------------------------------------------------------------------
/Editor/VCS/VCSException.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 339de811f43309449914e314f1366850
3 | MonoImporter:
4 | serializedVersion: 2
5 | defaultReferences: []
6 | executionOrder: 0
7 | icon: {instanceID: 0}
8 | userData:
9 |
--------------------------------------------------------------------------------
/Editor/GameObjectMergeActions.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: cfa76c0e71adc0f439476432ffe37fa3
3 | MonoImporter:
4 | serializedVersion: 2
5 | defaultReferences: []
6 | executionOrder: 0
7 | icon: {instanceID: 0}
8 | userData:
9 |
--------------------------------------------------------------------------------
/Editor/MergeActions/MergeAction.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: d9583c639208c1e49b6cc77e128f7ccb
3 | MonoImporter:
4 | serializedVersion: 2
5 | defaultReferences: []
6 | executionOrder: 0
7 | icon: {instanceID: 0}
8 | userData:
9 |
--------------------------------------------------------------------------------
/Editor/Utilities/ObjectExtensions.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 0ee0303a3ea013b4eaa610e764182b3a
3 | MonoImporter:
4 | serializedVersion: 2
5 | defaultReferences: []
6 | executionOrder: 0
7 | icon: {instanceID: 0}
8 | userData:
9 |
--------------------------------------------------------------------------------
/Editor/MergeActions/MergeActionExistence.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: f94b44d1572d0d14ea949190ef678a3a
3 | MonoImporter:
4 | serializedVersion: 2
5 | defaultReferences: []
6 | executionOrder: 0
7 | icon: {instanceID: 0}
8 | userData:
9 |
--------------------------------------------------------------------------------
/Editor/MergeActions/MergeActionParenting.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 29139dc665a42db45b67df932a04c810
3 | MonoImporter:
4 | serializedVersion: 2
5 | defaultReferences: []
6 | executionOrder: 0
7 | icon: {instanceID: 0}
8 | userData:
9 |
--------------------------------------------------------------------------------
/Editor/Utilities/GameObjectExtensions.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 327c0f7ed6330514791026c2d1ba5a5c
3 | MonoImporter:
4 | serializedVersion: 2
5 | defaultReferences: []
6 | executionOrder: 0
7 | icon: {instanceID: 0}
8 | userData:
9 |
--------------------------------------------------------------------------------
/Editor/MergeActions/MergeActionChangeValues.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 9a327ed62a5572a459e54869df134f42
3 | MonoImporter:
4 | serializedVersion: 2
5 | defaultReferences: []
6 | executionOrder: 0
7 | icon: {instanceID: 0}
8 | userData:
9 |
--------------------------------------------------------------------------------
/Editor/MergeActions/MergeActionNewComponent.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 6c13706c0946b934a95c41957ce759f5
3 | MonoImporter:
4 | serializedVersion: 2
5 | defaultReferences: []
6 | executionOrder: 0
7 | icon: {instanceID: 0}
8 | userData:
9 |
--------------------------------------------------------------------------------
/Editor/MergeActions/MergeActionNewGameObject.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: fb60feef4712bcc4a9f2d266c289a2d7
3 | MonoImporter:
4 | serializedVersion: 2
5 | defaultReferences: []
6 | executionOrder: 0
7 | icon: {instanceID: 0}
8 | userData:
9 |
--------------------------------------------------------------------------------
/Editor/Utilities/SerializedPropertyExtensions.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: e055732d013ee174fb764659113f8ea9
3 | MonoImporter:
4 | serializedVersion: 2
5 | defaultReferences: []
6 | executionOrder: 0
7 | icon: {instanceID: 0}
8 | userData:
9 |
--------------------------------------------------------------------------------
/Editor/MergeActions/MergeActionDeleteComponent.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 6414ac2f8bebc8b4bb33597977332630
3 | MonoImporter:
4 | serializedVersion: 2
5 | defaultReferences: []
6 | executionOrder: 0
7 | icon: {instanceID: 0}
8 | userData:
9 |
--------------------------------------------------------------------------------
/Editor/MergeActions/MergeActionDeleteGameObject.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 627176a0f25069f46919f6e3489eb8c3
3 | MonoImporter:
4 | serializedVersion: 2
5 | defaultReferences: []
6 | executionOrder: 0
7 | icon: {instanceID: 0}
8 | userData:
9 |
--------------------------------------------------------------------------------
/Editor/VCS/VCSException.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace GitMerge
3 | {
4 | public class VCSException : System.Exception
5 | {
6 | public VCSException(string message = "Could not find the VCS executable. Please enter the path to your VCS in the settings.") : base(message)
7 | {
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/Editor/Utilities/ObjectID.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: f3b42f26cd5372b42982f0590353b893
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Editor/Utilities/PageView.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: e670dcb0849e9cc4292d2d2e86aee42c
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Editor/Utilities/MergeFilter.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: edab603871662724cb02582fea7689be
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Editor/Utilities/MergeFilterBar.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 2342757c23c8b444d9923edcc54ada06
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Editor/Utilities/GUIBackgroundColor.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 6987b8c1c496fea44b2d36b5e09e167c
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | GitMerge-for-Unity
2 | ==================
3 |
4 | A Unity plugin which allows you to merge scene and prefab files when using git.
5 | More information: http://flashg.github.io/GitMerge-for-Unity/
6 |
7 | ## Current project state
8 |
9 | **IMPORTANT**: I've created a new version of this project that will replace this one when it's ready. There are still some edge cases to get working properly, but it will be linked here soon™.
10 |
--------------------------------------------------------------------------------
/Editor/ThirteenPixels.GitMerge.asmdef:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ThirteenPixels.GitMerge",
3 | "references": [],
4 | "includePlatforms": [
5 | "Editor"
6 | ],
7 | "excludePlatforms": [],
8 | "allowUnsafeCode": false,
9 | "overrideReferences": false,
10 | "precompiledReferences": [],
11 | "autoReferenced": true,
12 | "defineConstraints": [],
13 | "versionDefines": [],
14 | "noEngineReferences": false
15 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "de.thirteenpixels.gitmerge",
3 | "version": "0.1.0",
4 | "displayName": "GitMerge for Unity",
5 | "description": "Allows merging scene, prefab and ScriptableObject files.",
6 | "unity": "2019.2",
7 | "dependencies": {
8 | },
9 | "keywords": [
10 | "VCS",
11 | "Git",
12 | "Merging"
13 | ],
14 | "author": {
15 | "name": "13Pixels",
16 | "email": "assetstore@13pixels.de",
17 | "url": "https://www.13pixels.de"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Editor/Utilities/GUIBackgroundColor.cs:
--------------------------------------------------------------------------------
1 |
2 | using UnityEngine;
3 | using System;
4 |
5 | namespace GitMerge
6 | {
7 | #if CSHARP_7_3_OR_NEWER
8 | public readonly struct GUIBackgroundColor : IDisposable
9 | #else
10 | public struct GUIBackgroundColor : IDisposable
11 | #endif
12 | {
13 | private readonly Color previousColor;
14 |
15 | public GUIBackgroundColor(Color color)
16 | {
17 | previousColor = GUI.backgroundColor;
18 | GUI.backgroundColor = color;
19 | }
20 |
21 | public void Dispose()
22 | {
23 | GUI.backgroundColor = previousColor;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Editor/Utilities/ObjectExtensions.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 |
3 | namespace GitMerge
4 | {
5 | public static class ObjectExtensions
6 | {
7 | ///
8 | /// Get a fine, readable type string. Doesn't really need to be a Component extension method.
9 | /// Example: UnityEngine.BoxCollider => BoxCollider
10 | ///
11 | /// The object whose type we want to display
12 | /// The well readable type string
13 | public static string GetPlainType(this object o)
14 | {
15 | var s = o.GetType().ToString();
16 | var i = s.LastIndexOf('.');
17 | if (i >= 0)
18 | {
19 | s = s.Substring(i + 1);
20 | }
21 | return s;
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/Editor/MergeActions/MergeActionExistence.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace GitMerge
3 | {
4 | using UnityEngine;
5 |
6 | ///
7 | /// The abstract base MergeAction for all MergeActions that manage whether or not an object exists
8 | ///
9 | public abstract class MergeActionExistence : MergeAction
10 | {
11 | public MergeActionExistence(GameObject ours, GameObject theirs)
12 | : base(ours, theirs)
13 | {
14 | ObjectDictionaries.AddToSchroedingersObjects(ours ?? theirs, this);
15 | }
16 |
17 | ///
18 | /// Apply whatever version that has the object existing, since it might be needed somewhere.
19 | /// When overriding, call either UseOurs or UseTheirs to make sure to trigger the side effects.
20 | ///
21 | public abstract void EnsureExistence();
22 | }
23 | }
--------------------------------------------------------------------------------
/Editor/Resources/GitMergeBox.psd.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: be9ca0515e031fb4c86b12a6b9ba2410
3 | TextureImporter:
4 | serializedVersion: 2
5 | mipmaps:
6 | mipMapMode: 0
7 | enableMipMap: 0
8 | linearTexture: 1
9 | correctGamma: 0
10 | fadeOut: 0
11 | borderMipMap: 0
12 | mipMapFadeDistanceStart: 1
13 | mipMapFadeDistanceEnd: 3
14 | bumpmap:
15 | convertToNormalMap: 0
16 | externalNormalMap: 0
17 | heightScale: .25
18 | normalMapFilter: 0
19 | isReadable: 0
20 | grayScaleToAlpha: 0
21 | generateCubemap: 0
22 | seamlessCubemap: 0
23 | textureFormat: -1
24 | maxTextureSize: 1024
25 | textureSettings:
26 | filterMode: -1
27 | aniso: 1
28 | mipBias: -1
29 | wrapMode: 1
30 | nPOTScale: 0
31 | lightmap: 0
32 | compressionQuality: 50
33 | spriteMode: 0
34 | spriteExtrude: 1
35 | spriteMeshType: 1
36 | alignment: 0
37 | spritePivot: {x: .5, y: .5}
38 | spriteBorder: {x: 0, y: 0, z: 0, w: 0}
39 | spritePixelsToUnits: 100
40 | alphaIsTransparency: 1
41 | textureType: 2
42 | buildTargetSettings: []
43 | spriteSheet:
44 | sprites: []
45 | spritePackingTag:
46 | userData:
47 |
--------------------------------------------------------------------------------
/Editor/Resources/GitMergeLogo.psd.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: e18ddd74b76685d46a46ca56a3f6380f
3 | TextureImporter:
4 | serializedVersion: 2
5 | mipmaps:
6 | mipMapMode: 0
7 | enableMipMap: 0
8 | linearTexture: 1
9 | correctGamma: 0
10 | fadeOut: 0
11 | borderMipMap: 0
12 | mipMapFadeDistanceStart: 1
13 | mipMapFadeDistanceEnd: 3
14 | bumpmap:
15 | convertToNormalMap: 0
16 | externalNormalMap: 0
17 | heightScale: .25
18 | normalMapFilter: 0
19 | isReadable: 0
20 | grayScaleToAlpha: 0
21 | generateCubemap: 0
22 | seamlessCubemap: 0
23 | textureFormat: -1
24 | maxTextureSize: 1024
25 | textureSettings:
26 | filterMode: -1
27 | aniso: 1
28 | mipBias: -1
29 | wrapMode: 1
30 | nPOTScale: 0
31 | lightmap: 0
32 | compressionQuality: 50
33 | spriteMode: 0
34 | spriteExtrude: 1
35 | spriteMeshType: 1
36 | alignment: 0
37 | spritePivot: {x: .5, y: .5}
38 | spriteBorder: {x: 0, y: 0, z: 0, w: 0}
39 | spritePixelsToUnits: 100
40 | alphaIsTransparency: 1
41 | textureType: 2
42 | buildTargetSettings: []
43 | spriteSheet:
44 | sprites: []
45 | spritePackingTag:
46 | userData:
47 |
--------------------------------------------------------------------------------
/Editor/Resources.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 |
3 | namespace GitMerge
4 | {
5 | public class Resources : ScriptableObject
6 | {
7 | private static Resources _styles;
8 | public static Resources styles
9 | {
10 | get
11 | {
12 | if (!_styles)
13 | {
14 | _styles = UnityEngine.Resources.Load("GitMergeStyles");
15 | }
16 | return _styles;
17 | }
18 | }
19 | private static Texture2D _logo;
20 | public static Texture2D logo
21 | {
22 | get
23 | {
24 | if (!_logo)
25 | {
26 | _logo = UnityEngine.Resources.Load("GitMergeLogo");
27 | }
28 | return _logo;
29 | }
30 | }
31 |
32 | public GUIStyle mergeActions;
33 | public GUIStyle mergeAction;
34 |
35 | public static void DrawLogo()
36 | {
37 | GUI.DrawTexture(new Rect(5, 5, logo.width, logo.height), logo);
38 | GUILayout.Space(logo.height + 15);
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/Editor/VCS/VCSGit.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace GitMerge
3 | {
4 | using UnityEngine;
5 |
6 | public class VCSGit : VCS
7 | {
8 | protected override string GetDefaultPath()
9 | {
10 | if (Application.platform == RuntimePlatform.WindowsEditor)
11 | {
12 | return @"C:\Program Files (x86)\Git\bin\git.exe";
13 | }
14 | return @"/usr/bin/git";
15 | }
16 |
17 | protected override string EditorPrefsKey()
18 | {
19 | return "GitMerge_git";
20 | }
21 |
22 | public override void CheckoutOurs(string path)
23 | {
24 | GetAbsoluteFolderPathAndFilename(path, out var absoluteFolderPath, out var filename);
25 | Execute("checkout --ours \"" + filename + "\"", absoluteFolderPath);
26 | }
27 |
28 | public override void CheckoutTheirs(string path)
29 | {
30 | GetAbsoluteFolderPathAndFilename(path, out var absoluteFolderPath, out var filename);
31 | Execute("checkout --theirs \"" + filename + "\"", absoluteFolderPath);
32 | }
33 |
34 | public override void MarkAsMerged(string path)
35 | {
36 | GetAbsoluteFolderPathAndFilename(path, out var absoluteFolderPath, out var filename);
37 | Execute("add \"" + filename + "\"", absoluteFolderPath);
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/Editor/Utilities/MergeFilterBar.cs:
--------------------------------------------------------------------------------
1 | using GitMerge;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using UnityEditor;
5 | using UnityEditor.AnimatedValues;
6 | using UnityEngine;
7 |
8 | public class MergeFilterBar
9 | {
10 | public MergeFilter filter { get; set; }
11 |
12 | private AnimBool filterAnimAlpha;
13 |
14 | public void Draw()
15 | {
16 | filter.useFilter = GUILayout.Toggle(filter.useFilter, "Filter");
17 | if (filter.useFilter)
18 | {
19 | using (new EditorGUI.IndentLevelScope())
20 | {
21 | filter.isRegex = EditorGUILayout.Toggle("Regex?", filter.isRegex);
22 | if (!filter.isRegex)
23 | {
24 | filter.isCaseSensitive = EditorGUILayout.Toggle("Case Sensitive", filter.isCaseSensitive);
25 | }
26 | filter.expression = EditorGUILayout.TextField("Expression", filter.expression, GUILayout.ExpandWidth(true));
27 |
28 | filter.filterMode = (MergeFilter.FilterMode)EditorGUILayout.EnumPopup("Mode", filter.filterMode, GUILayout.Width(300), GUILayout.ExpandWidth(false));
29 | filter.filterState = (MergeFilter.FilterState)EditorGUILayout.EnumFlagsField("Conflict State", filter.filterState, GUILayout.Width(300), GUILayout.ExpandWidth(false));
30 | }
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Editor/MergeActions/MergeActionDeleteGameObject.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using UnityEditor;
3 |
4 | namespace GitMerge
5 | {
6 | ///
7 | /// The MergeAction that handles a GameObject which exists in "our" version but not "theirs".
8 | ///
9 | public class MergeActionDeleteGameObject : MergeActionExistence
10 | {
11 | private bool oursWasActive;
12 |
13 | public MergeActionDeleteGameObject(GameObject ours, GameObject theirs)
14 | : base(ours, theirs)
15 | {
16 | oursWasActive = ours.activeSelf;
17 |
18 | if (GitMergeWindow.automerge)
19 | {
20 | UseOurs();
21 | }
22 | }
23 |
24 | protected override void ApplyOurs()
25 | {
26 | ours.SetActiveForMerging(true);
27 | ours.SetActive(oursWasActive);
28 | }
29 |
30 | protected override void ApplyTheirs()
31 | {
32 | ours.SetActiveForMerging(false);
33 | SceneView.RepaintAll();
34 | }
35 |
36 | public override void EnsureExistence()
37 | {
38 | UseOurs();
39 | }
40 |
41 | public override void OnGUI()
42 | {
43 | var defaultOptionColor = merged ? Color.gray : Color.white;
44 |
45 | GUI.color = usingOurs ? Color.green : defaultOptionColor;
46 | if (GUILayout.Button("Keep GameObject"))
47 | {
48 | UseOurs();
49 | }
50 | GUI.color = usingTheirs ? Color.green : defaultOptionColor;
51 | if (GUILayout.Button("Delete GameObject"))
52 | {
53 | UseTheirs();
54 | }
55 | }
56 | }
57 | }
--------------------------------------------------------------------------------
/Editor/MergeActions/MergeActionNewGameObject.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using UnityEditor;
3 |
4 | namespace GitMerge
5 | {
6 | ///
7 | /// The MergeAction that handles GameObjects that exist in "their" version but not in "ours".
8 | ///
9 | public class MergeActionNewGameObject : MergeActionExistence
10 | {
11 | public MergeActionNewGameObject(GameObject ours, GameObject theirs)
12 | : base(ours, theirs)
13 | {
14 | if (GitMergeWindow.automerge)
15 | {
16 | UseTheirs();
17 | }
18 | }
19 |
20 | protected override void ApplyOurs()
21 | {
22 | if (ours)
23 | {
24 | ObjectDictionaries.RemoveCopyOf(theirs);
25 | GameObject.DestroyImmediate(ours, true);
26 | }
27 | }
28 |
29 | protected override void ApplyTheirs()
30 | {
31 | if (!ours)
32 | {
33 | ours = ObjectDictionaries.InstantiateFromMerging(theirs);
34 | ObjectDictionaries.SetAsCopy(ours, theirs);
35 | }
36 | }
37 |
38 | public override void EnsureExistence()
39 | {
40 | UseTheirs();
41 | }
42 |
43 | public override void OnGUI()
44 | {
45 | var defaultOptionColor = merged ? Color.gray : Color.white;
46 |
47 | GUI.color = usingOurs ? Color.green : defaultOptionColor;
48 | if (GUILayout.Button("Don't add GameObject"))
49 | {
50 | UseOurs();
51 | }
52 | GUI.color = usingTheirs ? Color.green : defaultOptionColor;
53 | if (GUILayout.Button("Add new GameObject"))
54 | {
55 | UseTheirs();
56 | }
57 | }
58 | }
59 | }
--------------------------------------------------------------------------------
/Editor/Utilities/ObjectID.cs:
--------------------------------------------------------------------------------
1 | // #define DEBUG_IDS
2 |
3 | namespace GitMerge
4 | {
5 | using UnityEngine;
6 | using UnityEditor;
7 |
8 | ///
9 | /// Struct representing a GameObject ID.
10 | /// Similar to GlobalObjectID, but used for robustness against changes to Unity's API.
11 | ///
12 | public struct ObjectID
13 | {
14 | public readonly ulong id;
15 | public readonly ulong prefabId;
16 |
17 | public ObjectID(ulong id, ulong prefabId)
18 | {
19 | this.id = id;
20 | this.prefabId = prefabId;
21 | }
22 |
23 | public override bool Equals(object obj)
24 | {
25 | if (obj == null || GetType() != obj.GetType())
26 | {
27 | return false;
28 | }
29 |
30 | var other = (ObjectID)obj;
31 |
32 | return id == other.id && prefabId == other.prefabId;
33 | }
34 |
35 | public override int GetHashCode()
36 | {
37 | return unchecked(id.GetHashCode() + prefabId.GetHashCode());
38 | }
39 |
40 | public override string ToString()
41 | {
42 | return "[" + id + (prefabId != 0 ? "/" + prefabId : "") + "]";
43 | }
44 |
45 | public static ObjectID GetFor(Object o)
46 | {
47 | var goid = GlobalObjectId.GetGlobalObjectIdSlow(o);
48 | var id = goid.targetObjectId;
49 | var prefabId = goid.targetPrefabId;
50 | return new ObjectID(id, prefabId);
51 | }
52 |
53 | #if DEBUG_IDS
54 | [MenuItem("Window/GitMerge Test ObjectID")]
55 | private static void Test()
56 | {
57 | // Debug.Log(GlobalObjectId.GetGlobalObjectIdSlow(Selection.activeGameObject));
58 | Debug.Log(GetFor(Selection.activeGameObject));
59 | }
60 | #endif
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/Editor/MergeActions/MergeActionNewComponent.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using UnityEditor;
3 |
4 | namespace GitMerge
5 | {
6 | ///
7 | /// The MergeAction that handles Components that exist in "our" version but not in "theirs".
8 | ///
9 | public class MergeActionNewComponent : MergeActionExistence
10 | {
11 | protected Component ourComponent;
12 | protected Component theirComponent;
13 |
14 | public MergeActionNewComponent(GameObject ours, Component theirComponent)
15 | : base(ours, null)
16 | {
17 | this.theirComponent = theirComponent;
18 |
19 | if (GitMergeWindow.automerge)
20 | {
21 | UseOurs();
22 | }
23 | }
24 |
25 | protected override void ApplyOurs()
26 | {
27 | if (ourComponent)
28 | {
29 | ObjectDictionaries.RemoveCopyOf(theirComponent);
30 | Object.DestroyImmediate(ourComponent, true);
31 | }
32 | }
33 |
34 | protected override void ApplyTheirs()
35 | {
36 | if (!ourComponent)
37 | {
38 | ourComponent = ours.AddComponent(theirComponent);
39 | ObjectDictionaries.SetAsCopy(ourComponent, theirComponent);
40 | }
41 | }
42 |
43 | public override void EnsureExistence()
44 | {
45 | UseTheirs();
46 | }
47 |
48 | public override void OnGUI()
49 | {
50 | GUILayout.Label(theirComponent.GetPlainType());
51 |
52 | var defaultOptionColor = merged ? Color.gray : Color.white;
53 |
54 | GUI.color = usingOurs ? Color.green : defaultOptionColor;
55 | if (GUILayout.Button("Don't add Component"))
56 | {
57 | UseOurs();
58 | }
59 | GUI.color = usingTheirs ? Color.green : defaultOptionColor;
60 | if (GUILayout.Button("Add new Component"))
61 | {
62 | UseTheirs();
63 | }
64 | }
65 | }
66 | }
--------------------------------------------------------------------------------
/Editor/MergeActions/MergeActionDeleteComponent.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using UnityEditor;
3 |
4 | namespace GitMerge
5 | {
6 | ///
7 | /// The MergeAction that handles a Component which exists in "their" version but not "ours".
8 | ///
9 | public class MergeActionDeleteComponent : MergeActionExistence
10 | {
11 | protected Component ourComponent;
12 | protected Component copy;
13 |
14 | public MergeActionDeleteComponent(GameObject ours, Component ourComponent)
15 | : base(ours, null)
16 | {
17 | this.ourComponent = ourComponent;
18 |
19 | var go = new GameObject("GitMerge Object");
20 | go.SetActiveForMerging(false);
21 |
22 | copy = go.AddComponent(ourComponent);
23 |
24 | if (GitMergeWindow.automerge)
25 | {
26 | UseOurs();
27 | }
28 | }
29 |
30 | protected override void ApplyOurs()
31 | {
32 | if (ourComponent == null)
33 | {
34 | ourComponent = ours.AddComponent(copy);
35 | ObjectDictionaries.SetAsOurObject(ourComponent);
36 | }
37 | }
38 |
39 | protected override void ApplyTheirs()
40 | {
41 | if (ourComponent != null)
42 | {
43 | ObjectDictionaries.RemoveOurObject(ourComponent);
44 | Object.DestroyImmediate(ourComponent, true);
45 | }
46 | }
47 |
48 | public override void EnsureExistence()
49 | {
50 | UseOurs();
51 | }
52 |
53 | public override void OnGUI()
54 | {
55 | GUILayout.Label(copy.GetPlainType());
56 |
57 | var defaultOptionColor = merged ? Color.gray : Color.white;
58 |
59 | GUI.color = usingOurs ? Color.green : defaultOptionColor;
60 | if (GUILayout.Button("Keep Component"))
61 | {
62 | UseOurs();
63 | }
64 | GUI.color = usingTheirs ? Color.green : defaultOptionColor;
65 | if (GUILayout.Button("Delete Component"))
66 | {
67 | UseTheirs();
68 | }
69 | }
70 | }
71 | }
--------------------------------------------------------------------------------
/Editor/VCS/VCS.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace GitMerge
3 | {
4 | using UnityEngine;
5 | using UnityEditor;
6 | using System.Diagnostics;
7 | using System.ComponentModel;
8 | using System.IO;
9 |
10 | ///
11 | /// This abstract class represents a vcs interface.
12 | /// It manages saving and retrieving the exe path from/to the EditorPrefs
13 | /// and offers a small set of actions using the vcs.
14 | ///
15 | public abstract class VCS
16 | {
17 | protected abstract string GetDefaultPath();
18 | protected abstract string EditorPrefsKey();
19 |
20 | public abstract void CheckoutOurs(string path);
21 | public abstract void CheckoutTheirs(string path);
22 | public abstract void MarkAsMerged(string path);
23 |
24 | public string GetExePath()
25 | {
26 | if (EditorPrefs.HasKey(EditorPrefsKey()))
27 | {
28 | return EditorPrefs.GetString(EditorPrefsKey());
29 | }
30 |
31 | return GetDefaultPath();
32 | }
33 |
34 | public void SetPath(string path)
35 | {
36 | EditorPrefs.SetString(EditorPrefsKey(), path);
37 | }
38 |
39 | ///
40 | /// Executes the VCS as a subprocess.
41 | ///
42 | /// The parameters passed. Like "status" for "git status".
43 | /// Whatever the call returns.
44 | protected string Execute(string args, string workingDirectoryPath)
45 | {
46 | var process = new Process();
47 | var startInfo = new ProcessStartInfo();
48 | startInfo.WindowStyle = ProcessWindowStyle.Hidden;
49 | startInfo.FileName = GetExePath();
50 | startInfo.Arguments = args;
51 | startInfo.UseShellExecute = false;
52 | startInfo.RedirectStandardOutput = true;
53 | startInfo.WorkingDirectory = workingDirectoryPath;
54 | process.StartInfo = startInfo;
55 |
56 | try
57 | {
58 | process.Start();
59 | }
60 | catch (Win32Exception)
61 | {
62 | throw new VCSException();
63 | }
64 |
65 | string output = process.StandardOutput.ReadToEnd();
66 | process.WaitForExit();
67 |
68 | return output;
69 | }
70 |
71 | private static string GetAboluteFolderPath(string relativeFilePath)
72 | {
73 | var projectPath = Application.dataPath;
74 | projectPath = Directory.GetParent(projectPath).FullName;
75 | var fullPath = Path.Combine(projectPath, relativeFilePath);
76 | return Path.GetDirectoryName(fullPath);
77 | }
78 |
79 | protected static void GetAbsoluteFolderPathAndFilename(string relativeFilePath, out string absoluteFolderPath, out string filename)
80 | {
81 | absoluteFolderPath = GetAboluteFolderPath(relativeFilePath);
82 | filename = Path.GetFileName(relativeFilePath);
83 | }
84 | }
85 | }
--------------------------------------------------------------------------------
/Editor/MergeActions/MergeActionParenting.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using UnityEditor;
3 |
4 | namespace GitMerge
5 | {
6 | ///
7 | /// The MergeAction that handles a differing parents for a Transform.
8 | ///
9 | public class MergeActionParenting : MergeAction
10 | {
11 | private Transform transform;
12 | private Transform ourParent;
13 | private Transform theirParent;
14 |
15 | public MergeActionParenting(Transform transform, Transform ourParent, Transform theirParent)
16 | : base(transform.gameObject, null)
17 | {
18 | this.transform = transform;
19 | this.ourParent = ourParent;
20 | this.theirParent = theirParent;
21 | }
22 |
23 | protected override void ApplyOurs()
24 | {
25 | transform.parent = ourParent;
26 | }
27 |
28 | protected override void ApplyTheirs()
29 | {
30 | var ourVersion = ObjectDictionaries.GetOurCounterpartFor(theirParent) as Transform;
31 | if (theirParent && !ourVersion)
32 | {
33 | if (EditorUtility.DisplayDialog("The chosen parent currently does not exist.", "Do you want do add it?", "Yes", "No"))
34 | {
35 | ObjectDictionaries.EnsureExistence(theirParent.gameObject);
36 | ourVersion = ObjectDictionaries.GetOurCounterpartFor(theirParent) as Transform;
37 |
38 | transform.parent = ourVersion;
39 | }
40 | else
41 | {
42 | throw new System.Exception("User Abort.");
43 | }
44 | }
45 | else
46 | {
47 | transform.parent = ourVersion;
48 | }
49 | }
50 |
51 | public override void OnGUI()
52 | {
53 | GUILayout.BeginVertical();
54 | GUILayout.Label("Parent");
55 |
56 | GUILayout.BeginHorizontal();
57 |
58 | GUILayout.Label(ourParent ? ourParent.ToString() : "None", GUILayout.Width(100));
59 |
60 | if (MergeButton(">>>", usingOurs))
61 | {
62 | UseOurs();
63 | }
64 |
65 | var c = GUI.backgroundColor;
66 | GUI.backgroundColor = Color.white;
67 | var newParent = EditorGUILayout.ObjectField(transform.parent, typeof(Transform), true, GUILayout.Width(170)) as Transform;
68 | if (newParent != transform.parent)
69 | {
70 | transform.parent = newParent;
71 | UsedNew();
72 | }
73 | GUI.backgroundColor = c;
74 |
75 | if (MergeButton("<<<", usingTheirs))
76 | {
77 | UseTheirs();
78 | }
79 |
80 | GUILayout.Label(theirParent ? theirParent.ToString() : "None", GUILayout.Width(100));
81 |
82 | GUILayout.EndHorizontal();
83 | GUILayout.EndVertical();
84 | }
85 |
86 | private static bool MergeButton(string text, bool green)
87 | {
88 | if (green)
89 | {
90 | GUI.color = Color.green;
91 | }
92 | bool result = GUILayout.Button(text, GUILayout.ExpandWidth(false));
93 | GUI.color = Color.white;
94 | return result;
95 | }
96 | }
97 | }
--------------------------------------------------------------------------------
/Editor/Utilities/PageView.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using UnityEditor;
5 | using UnityEngine;
6 |
7 | namespace GitMerge.Utilities
8 | {
9 | public class PageView
10 | {
11 | public int PageIndex { get; set; } = 0;
12 | public int NumElementsPerPage { get; set; } = 10;
13 |
14 | private Vector2 scrollPosition;
15 |
16 | ///
17 | /// Draw a scroll view only a limited number of elements displayed.
18 | /// Add tool to change the page to display previous/next range of elements.
19 | ///
20 | /// The total number of elements to draw.
21 | /// Called for each element to draw. The element index to draw is passed as argument.
22 | public void Draw(int numMaxElements, Action callbackElementDraw)
23 | {
24 | GUILayout.BeginVertical(GUILayout.ExpandWidth(true));
25 | {
26 | DrawPageContent(callbackElementDraw, numMaxElements);
27 | DrawPageNavigation(numMaxElements);
28 | }
29 | GUILayout.EndVertical();
30 | }
31 |
32 | private void DrawPageContent(Action callbackElementDraw, int numMaxElements)
33 | {
34 | scrollPosition = GUILayout.BeginScrollView(scrollPosition, false, true);
35 | {
36 | GUILayout.BeginVertical(GUILayout.ExpandWidth(true));
37 |
38 | int lastElementIndex = Mathf.Min((PageIndex + 1) * NumElementsPerPage, numMaxElements);
39 | for (int index = PageIndex * NumElementsPerPage; index < lastElementIndex; ++index)
40 | {
41 | callbackElementDraw(index);
42 | }
43 |
44 | GUILayout.EndVertical();
45 | }
46 | GUILayout.EndScrollView();
47 | }
48 |
49 | private void DrawPageNavigation(int numMaxElements)
50 | {
51 | int numPages = CalculateNumberOfPages(numMaxElements);
52 |
53 | if (numPages == 0)
54 | {
55 | return;
56 | }
57 |
58 | GUILayout.BeginHorizontal();
59 | {
60 | EditorGUILayout.PrefixLabel("Count Per Page");
61 | int newNumElementsPerPage = EditorGUILayout.DelayedIntField(NumElementsPerPage, GUILayout.Width(100));
62 | if (newNumElementsPerPage != NumElementsPerPage)
63 | {
64 | NumElementsPerPage = Mathf.Max(newNumElementsPerPage, 1);
65 | numPages = CalculateNumberOfPages(numMaxElements);
66 | }
67 |
68 | GUILayout.FlexibleSpace();
69 |
70 | EditorGUI.BeginDisabledGroup(PageIndex == 0);
71 | {
72 | if (GUILayout.Button("<"))
73 | {
74 | --PageIndex;
75 | }
76 | }
77 | EditorGUI.EndDisabledGroup();
78 |
79 | int newPageIndex = EditorGUILayout.DelayedIntField(PageIndex + 1, GUILayout.Width(30)) - 1;
80 | PageIndex = Mathf.Clamp(newPageIndex, 0, numPages - 1);
81 |
82 | GUILayout.Label("/" + numPages);
83 |
84 | EditorGUI.BeginDisabledGroup(PageIndex == numPages - 1);
85 | {
86 | if (GUILayout.Button(">"))
87 | {
88 | ++PageIndex;
89 | }
90 | }
91 | EditorGUI.EndDisabledGroup();
92 | }
93 | GUILayout.EndHorizontal();
94 | }
95 |
96 | private int CalculateNumberOfPages(int numMaxElements)
97 | {
98 | int numPages = numMaxElements / NumElementsPerPage;
99 | if (numMaxElements % NumElementsPerPage != 0)
100 | {
101 | ++numPages;
102 | }
103 |
104 | return numPages;
105 | }
106 | }
107 | }
--------------------------------------------------------------------------------
/Editor/Resources/GitMergeStyles.asset:
--------------------------------------------------------------------------------
1 | %YAML 1.1
2 | %TAG !u! tag:unity3d.com,2011:
3 | --- !u!114 &11400000
4 | MonoBehaviour:
5 | m_ObjectHideFlags: 0
6 | m_CorrespondingSourceObject: {fileID: 0}
7 | m_PrefabInstance: {fileID: 0}
8 | m_PrefabAsset: {fileID: 0}
9 | m_GameObject: {fileID: 0}
10 | m_Enabled: 1
11 | m_EditorHideFlags: 0
12 | m_Script: {fileID: 11500000, guid: 67422f4e577bb17409644dcfe6bf75c8, type: 3}
13 | m_Name: GitMergeStyles
14 | m_EditorClassIdentifier:
15 | mergeActions:
16 | m_Name:
17 | m_Normal:
18 | m_Background: {fileID: 2800000, guid: be9ca0515e031fb4c86b12a6b9ba2410, type: 3}
19 | m_ScaledBackgrounds: []
20 | m_TextColor: {r: 0, g: 0, b: 0, a: 1}
21 | m_Hover:
22 | m_Background: {fileID: 0}
23 | m_ScaledBackgrounds: []
24 | m_TextColor: {r: 0, g: 0, b: 0, a: 1}
25 | m_Active:
26 | m_Background: {fileID: 0}
27 | m_ScaledBackgrounds: []
28 | m_TextColor: {r: 0, g: 0, b: 0, a: 1}
29 | m_Focused:
30 | m_Background: {fileID: 0}
31 | m_ScaledBackgrounds: []
32 | m_TextColor: {r: 0, g: 0, b: 0, a: 1}
33 | m_OnNormal:
34 | m_Background: {fileID: 0}
35 | m_ScaledBackgrounds: []
36 | m_TextColor: {r: 0, g: 0, b: 0, a: 1}
37 | m_OnHover:
38 | m_Background: {fileID: 0}
39 | m_ScaledBackgrounds: []
40 | m_TextColor: {r: 0, g: 0, b: 0, a: 1}
41 | m_OnActive:
42 | m_Background: {fileID: 0}
43 | m_ScaledBackgrounds: []
44 | m_TextColor: {r: 0, g: 0, b: 0, a: 1}
45 | m_OnFocused:
46 | m_Background: {fileID: 0}
47 | m_ScaledBackgrounds: []
48 | m_TextColor: {r: 0, g: 0, b: 0, a: 1}
49 | m_Border:
50 | m_Left: 4
51 | m_Right: 4
52 | m_Top: 4
53 | m_Bottom: 4
54 | m_Margin:
55 | m_Left: 2
56 | m_Right: 2
57 | m_Top: 2
58 | m_Bottom: 2
59 | m_Padding:
60 | m_Left: 4
61 | m_Right: 4
62 | m_Top: 4
63 | m_Bottom: 4
64 | m_Overflow:
65 | m_Left: 0
66 | m_Right: 0
67 | m_Top: 0
68 | m_Bottom: 0
69 | m_Font: {fileID: 0}
70 | m_FontSize: 0
71 | m_FontStyle: 0
72 | m_Alignment: 0
73 | m_WordWrap: 0
74 | m_RichText: 1
75 | m_TextClipping: 0
76 | m_ImagePosition: 0
77 | m_ContentOffset: {x: 0, y: 0}
78 | m_FixedWidth: 0
79 | m_FixedHeight: 0
80 | m_StretchWidth: 1
81 | m_StretchHeight: 0
82 | mergeAction:
83 | m_Name:
84 | m_Normal:
85 | m_Background: {fileID: 2800000, guid: be9ca0515e031fb4c86b12a6b9ba2410, type: 3}
86 | m_ScaledBackgrounds: []
87 | m_TextColor: {r: 0, g: 0, b: 0, a: 1}
88 | m_Hover:
89 | m_Background: {fileID: 0}
90 | m_ScaledBackgrounds: []
91 | m_TextColor: {r: 0, g: 0, b: 0, a: 1}
92 | m_Active:
93 | m_Background: {fileID: 0}
94 | m_ScaledBackgrounds: []
95 | m_TextColor: {r: 0, g: 0, b: 0, a: 1}
96 | m_Focused:
97 | m_Background: {fileID: 0}
98 | m_ScaledBackgrounds: []
99 | m_TextColor: {r: 0, g: 0, b: 0, a: 1}
100 | m_OnNormal:
101 | m_Background: {fileID: 0}
102 | m_ScaledBackgrounds: []
103 | m_TextColor: {r: 0, g: 0, b: 0, a: 1}
104 | m_OnHover:
105 | m_Background: {fileID: 0}
106 | m_ScaledBackgrounds: []
107 | m_TextColor: {r: 0, g: 0, b: 0, a: 1}
108 | m_OnActive:
109 | m_Background: {fileID: 0}
110 | m_ScaledBackgrounds: []
111 | m_TextColor: {r: 0, g: 0, b: 0, a: 1}
112 | m_OnFocused:
113 | m_Background: {fileID: 0}
114 | m_ScaledBackgrounds: []
115 | m_TextColor: {r: 0, g: 0, b: 0, a: 1}
116 | m_Border:
117 | m_Left: 4
118 | m_Right: 4
119 | m_Top: 4
120 | m_Bottom: 4
121 | m_Margin:
122 | m_Left: 2
123 | m_Right: 2
124 | m_Top: 2
125 | m_Bottom: 2
126 | m_Padding:
127 | m_Left: 2
128 | m_Right: 2
129 | m_Top: 2
130 | m_Bottom: 4
131 | m_Overflow:
132 | m_Left: 0
133 | m_Right: 0
134 | m_Top: 0
135 | m_Bottom: 0
136 | m_Font: {fileID: 0}
137 | m_FontSize: 0
138 | m_FontStyle: 0
139 | m_Alignment: 0
140 | m_WordWrap: 0
141 | m_RichText: 1
142 | m_TextClipping: 0
143 | m_ImagePosition: 0
144 | m_ContentOffset: {x: 0, y: 0}
145 | m_FixedWidth: 0
146 | m_FixedHeight: 0
147 | m_StretchWidth: 1
148 | m_StretchHeight: 0
149 |
--------------------------------------------------------------------------------
/Editor/Utilities/GameObjectExtensions.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace GitMerge
3 | {
4 | using System.Text;
5 | using UnityEngine;
6 | using UnityEditor;
7 |
8 | public static class GameObjectExtensions
9 | {
10 | ///
11 | /// Adds the copy of a Component to a GameObject.
12 | ///
13 | /// The GameObject that will get the new Component
14 | /// The original component to copy
15 | /// The reference to the newly added Component copy
16 | public static Component AddComponent(this GameObject go, Component original)
17 | {
18 | var newComponent = go.AddComponent(original.GetType());
19 |
20 | var originalProperty = new SerializedObject(original).GetIterator();
21 | var newSerializedObject = new SerializedObject(newComponent);
22 | var newProperty = newSerializedObject.GetIterator();
23 |
24 | if (originalProperty.Next(true))
25 | {
26 | newProperty.Next(true);
27 |
28 | while (originalProperty.NextVisible(true))
29 | {
30 | newProperty.NextVisible(true);
31 | newProperty.SetValue(originalProperty.GetValue());
32 | }
33 | }
34 |
35 | newSerializedObject.ApplyModifiedProperties();
36 |
37 | return newComponent;
38 | }
39 |
40 | ///
41 | /// Activates/deactivates the GameObjct, and hides it when it is disabled.
42 | /// This is used for "their" objects to hide them while merging.
43 | ///
44 | /// The object do enable/disable
45 | /// Enable or disable the object?
46 | public static void SetActiveForMerging(this GameObject go, bool active)
47 | {
48 | go.SetActive(active);
49 | go.hideFlags = active ? HideFlags.None : HideFlags.HideAndDontSave;
50 | }
51 |
52 | ///
53 | /// Ping the GameObject in the hierarchy, select it, and center it in the scene view.
54 | ///
55 | /// The GameObject of interest
56 | public static void Highlight(this GameObject go)
57 | {
58 | // Focussing on the same object twice, zooms in to the coordinate instead of the bounding box.
59 | if (Selection.activeObject == go) {
60 | return;
61 | }
62 |
63 | Selection.activeGameObject = go;
64 | EditorGUIUtility.PingObject(go);
65 |
66 | var view = SceneView.lastActiveSceneView;
67 | if (view)
68 | {
69 | view.FrameSelected();
70 | }
71 | }
72 |
73 | ///
74 | /// Gets the path of this GameObject in the hierarchy.
75 | ///
76 | public static string GetPath(this GameObject gameObject)
77 | {
78 | var t = gameObject.transform;
79 | var sb = new StringBuilder(RemovePostfix(t.name));
80 | while (t.parent != null)
81 | {
82 | t = t.parent;
83 | sb.Insert(0, RemovePostfix(t.name) + "/");
84 | }
85 | return sb.ToString();
86 | }
87 |
88 | ///
89 | /// Returns a child of this GameObject that has the same relative path to this GamObject as
90 | /// the given GameObject has to it's root GameObject.
91 | ///
92 | public static GameObject GetChildWithEqualPath(this GameObject gameObject, GameObject otherGameObject)
93 | {
94 | string fullHierarchyPath = otherGameObject.GetPath();
95 | string relativeHierarchyPath = fullHierarchyPath.Substring(fullHierarchyPath.IndexOf("/", 1) + 1);
96 | Transform result = gameObject.transform.Find(relativeHierarchyPath);
97 | return result != null ? result.gameObject : gameObject; // fallback to root if a GameObject with equal path doesn't exist
98 | }
99 |
100 | private static string RemovePostfix(string name)
101 | {
102 | if (name.EndsWith(MergeManagerBase.THEIR_FILE_POSTFIX))
103 | {
104 | return name.Substring(0, name.Length - MergeManagerBase.THEIR_FILE_POSTFIX.Length);
105 | }
106 |
107 | return name;
108 | }
109 | }
110 | }
--------------------------------------------------------------------------------
/Editor/Utilities/MergeFilter.cs:
--------------------------------------------------------------------------------
1 | using GitMerge;
2 | using System;
3 | using System.Collections;
4 | using System.Collections.Generic;
5 | using System.Text.RegularExpressions;
6 | using UnityEngine;
7 |
8 | namespace GitMerge
9 | {
10 | public class MergeFilter
11 | {
12 | public event Action OnChanged;
13 |
14 | public enum FilterMode
15 | {
16 | Inclusion,
17 | Exclusion
18 | }
19 |
20 | [System.Flags]
21 | public enum FilterState
22 | {
23 | Conflict = 0x01,
24 | Done = 0x02
25 | }
26 |
27 | private bool _useFilter = false;
28 | public bool useFilter
29 | {
30 | get => _useFilter;
31 | set
32 | {
33 | if (_useFilter != value)
34 | {
35 | _useFilter = value;
36 | OnChanged?.Invoke();
37 | }
38 | }
39 | }
40 |
41 | private bool _isRegex = false;
42 | public bool isRegex
43 | {
44 | get => _isRegex;
45 | set
46 | {
47 | if (_isRegex != value)
48 | {
49 | _isRegex = value;
50 | OnChanged?.Invoke();
51 | }
52 | }
53 | }
54 |
55 | private bool _isCaseSensitive = false;
56 | public bool isCaseSensitive
57 | {
58 | get => _isCaseSensitive;
59 | set
60 | {
61 | if (_isCaseSensitive != value)
62 | {
63 | _isCaseSensitive = value;
64 | OnChanged?.Invoke();
65 | }
66 | }
67 | }
68 |
69 | private string _expression = string.Empty;
70 | public string expression
71 | {
72 | get => _expression;
73 | set
74 | {
75 | if (_expression != value)
76 | {
77 | _expression = value;
78 | regex = new Regex(_expression);
79 | OnChanged?.Invoke();
80 | }
81 | }
82 | }
83 |
84 | private FilterMode _filterMode = FilterMode.Inclusion;
85 | public FilterMode filterMode
86 | {
87 | get => _filterMode;
88 | set
89 | {
90 | if (_filterMode != value)
91 | {
92 | _filterMode = value;
93 | OnChanged?.Invoke();
94 | }
95 | }
96 | }
97 |
98 | private FilterState _filterState = (FilterState)(-1);
99 | public FilterState filterState
100 | {
101 | get => _filterState;
102 | set
103 | {
104 | if (_filterState != value)
105 | {
106 | _filterState = value;
107 | OnChanged?.Invoke();
108 | }
109 | }
110 | }
111 |
112 | private Regex regex = new Regex(string.Empty);
113 |
114 | public bool IsPassingFilter(GameObjectMergeActions action)
115 | {
116 | if (!useFilter)
117 | {
118 | return true;
119 | }
120 |
121 | bool isPassingFilter = false;
122 |
123 | string name = action.name;
124 |
125 | if (isRegex)
126 | {
127 | isPassingFilter = regex.IsMatch(name);
128 | }
129 | else
130 | {
131 | if (!isCaseSensitive)
132 | {
133 | name = name.ToLowerInvariant();
134 | isPassingFilter = name.Contains(_expression.ToLowerInvariant());
135 | }
136 | else
137 | {
138 | isPassingFilter = name.Contains(_expression);
139 | }
140 | }
141 |
142 | if (filterMode == FilterMode.Exclusion)
143 | {
144 | isPassingFilter = !isPassingFilter;
145 | }
146 |
147 | bool isPassingFilterState = false;
148 | if ((_filterState & FilterState.Conflict) != 0)
149 | {
150 | isPassingFilterState |= !action.merged;
151 | }
152 |
153 | if ((_filterState & FilterState.Done) != 0)
154 | {
155 | isPassingFilterState |= action.merged;
156 | }
157 | isPassingFilter &= isPassingFilterState;
158 |
159 | return isPassingFilter;
160 | }
161 | }
162 | }
--------------------------------------------------------------------------------
/Editor/MergeManagerBase.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace GitMerge
3 | {
4 | using UnityEngine;
5 | using System.IO;
6 | using System.Collections.Generic;
7 |
8 | public abstract class MergeManagerBase
9 | {
10 | internal const string OUR_FILE_POSTFIX = "--OURS";
11 | internal const string THEIR_FILE_POSTFIX = "--THEIRS";
12 |
13 | protected VCS vcs { private set; get; }
14 | protected GitMergeWindow window { private set; get; }
15 |
16 | internal List allMergeActions;
17 |
18 | protected static string fileName;
19 | protected static string theirFilename;
20 |
21 | public static bool isMergingScene { protected set; get; }
22 | public static bool isMergingPrefab { get { return !isMergingScene; } }
23 |
24 |
25 | public MergeManagerBase(GitMergeWindow window, VCS vcs)
26 | {
27 | this.window = window;
28 | this.vcs = vcs;
29 | allMergeActions = new List();
30 | }
31 |
32 | ///
33 | /// Creates "their" version of the file at the given path,
34 | /// named filename--THEIRS.unity.
35 | ///
36 | /// The path of the file, relative to the project folder.
37 | protected void CheckoutTheirVersionOf(string path)
38 | {
39 | fileName = path;
40 |
41 | string basepath = Path.GetDirectoryName(path);
42 | string sceneName = Path.GetFileNameWithoutExtension(path);
43 | string extension = Path.GetExtension(path);
44 |
45 | string ourFilename = Path.Combine(basepath, sceneName + OUR_FILE_POSTFIX + extension);
46 | theirFilename = Path.Combine(basepath, sceneName + THEIR_FILE_POSTFIX + extension);
47 |
48 | File.Copy(path, ourFilename);
49 | try
50 | {
51 | vcs.CheckoutTheirs(path);
52 | }
53 | catch (VCSException e)
54 | {
55 | File.Delete(ourFilename);
56 | throw e;
57 | }
58 | File.Move(path, theirFilename);
59 | File.Move(ourFilename, path);
60 | }
61 |
62 | ///
63 | /// Finds all specific merge conflicts between two sets of GameObjects,
64 | /// representing "our" scene and "their" scene.
65 | ///
66 | /// The GameObjects of "our" version of the scene.
67 | /// The GameObjects of "their" version of the scene.
68 | protected void BuildAllMergeActions(List ourObjects, List theirObjects)
69 | {
70 | allMergeActions = new List();
71 |
72 | // Map "their" GameObjects to their respective ids
73 | var theirObjectsDict = new Dictionary();
74 | foreach (var theirs in theirObjects)
75 | {
76 | theirObjectsDict.Add(ObjectID.GetFor(theirs), theirs);
77 | }
78 |
79 | foreach (var ours in ourObjects)
80 | {
81 | // Try to find "their" equivalent to "our" GameObjects
82 | var id = ObjectID.GetFor(ours);
83 | GameObject theirs;
84 | theirObjectsDict.TryGetValue(id, out theirs);
85 |
86 | // If theirs is null, mergeActions.hasActions will be false
87 | var mergeActions = new GameObjectMergeActions(ours, theirs);
88 | if (mergeActions.hasActions)
89 | {
90 | allMergeActions.Add(mergeActions);
91 | }
92 | // Remove "their" GameObject from the dict to only keep those new to us
93 | theirObjectsDict.Remove(id);
94 | }
95 |
96 | // Every GameObject left in the dict is a...
97 | foreach (var theirs in theirObjectsDict.Values)
98 | {
99 | // ...new GameObject from them
100 | var mergeActions = new GameObjectMergeActions(null, theirs);
101 | if (mergeActions.hasActions)
102 | {
103 | allMergeActions.Add(mergeActions);
104 | }
105 | }
106 | }
107 |
108 | public abstract void CompleteMerge();
109 |
110 | public virtual void AbortMerge(bool showNotification = true)
111 | {
112 | MergeAction.inMergePhase = false;
113 |
114 | foreach (var actions in allMergeActions)
115 | {
116 | actions.UseOurs();
117 | }
118 | ObjectDictionaries.DestroyTheirObjects();
119 | ObjectDictionaries.Clear();
120 | allMergeActions = null;
121 |
122 | if (showNotification)
123 | {
124 | window.ShowNotification(new GUIContent("Merge aborted."));
125 | }
126 | }
127 | }
128 | }
--------------------------------------------------------------------------------
/Editor/MergeActions/MergeAction.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace GitMerge
3 | {
4 | using UnityEngine;
5 | using UnityEditor;
6 |
7 | ///
8 | /// Each MergeAction represents a single, specific merge conflict.
9 | /// This can be a GameObject added or deleted in one of the versions,
10 | /// a Component added or deleted on a GameObject,
11 | /// or a single property changed on a Component.
12 | ///
13 | public abstract class MergeAction
14 | {
15 | // Don't highlight objects if not in merge phase.
16 | // Prevents highlighting while automerging.
17 | public static bool inMergePhase;
18 |
19 | // A MergeAction is considered "merged" when, at some point,
20 | // "our", "their" or a new version has been applied.
21 | public bool merged { protected set; get; }
22 |
23 | public GameObject ours { protected set; get; }
24 | public GameObject theirs { protected set; get; }
25 |
26 | // Flags that indicate how this MergeAction has been resolved.
27 | protected bool usingOurs;
28 | protected bool usingTheirs;
29 | protected bool usingNew;
30 |
31 | protected bool wasResolvedAutomatically;
32 |
33 |
34 | public MergeAction(GameObject ours, GameObject theirs)
35 | {
36 | this.ours = ours;
37 | this.theirs = theirs;
38 | }
39 |
40 | ///
41 | /// Apply "our" change in the conflict, dismissing "their"s.
42 | ///
43 | public void UseOurs()
44 | {
45 | try
46 | {
47 | ApplyOurs();
48 | }
49 | catch
50 | {
51 | return;
52 | }
53 | merged = true;
54 | usingOurs = true;
55 | usingTheirs = false;
56 | usingNew = false;
57 |
58 | wasResolvedAutomatically = !inMergePhase;
59 |
60 | if (GitMergeWindow.autofocus)
61 | {
62 | HighlightObject();
63 | }
64 |
65 | RefreshPrefabInstance();
66 | }
67 |
68 | ///
69 | /// Apply "their" change in the conflict, dismissing "our"s.
70 | ///
71 | public void UseTheirs()
72 | {
73 | try
74 | {
75 | ApplyTheirs();
76 | }
77 | catch
78 | {
79 | return;
80 | }
81 | merged = true;
82 | usingOurs = false;
83 | usingTheirs = true;
84 | usingNew = false;
85 |
86 | wasResolvedAutomatically = !inMergePhase;
87 |
88 | if (GitMergeWindow.autofocus)
89 | {
90 | HighlightObject();
91 | }
92 |
93 | RefreshPrefabInstance();
94 | }
95 |
96 | ///
97 | /// Mark this to use a new value instead of either of the conflicting ones.
98 | ///
99 | public void UsedNew()
100 | {
101 | merged = true;
102 | usingOurs = false;
103 | usingTheirs = false;
104 | usingNew = true;
105 |
106 | wasResolvedAutomatically = !inMergePhase;
107 |
108 | RefreshPrefabInstance();
109 | }
110 |
111 | ///
112 | /// Refreshes the prefab instance, if there is any.
113 | /// We change the prefab directly, so we have to do this to see the changes in the scene view.
114 | ///
115 | private static void RefreshPrefabInstance()
116 | {
117 | if (MergeManagerBase.isMergingPrefab)
118 | {
119 | PrefabUtility.RevertObjectOverride(MergeManagerPrefab.ourPrefabInstance, InteractionMode.AutomatedAction);
120 | }
121 | }
122 |
123 | // The implementations of these methods conatain the actual merging steps
124 | protected abstract void ApplyOurs();
125 | protected abstract void ApplyTheirs();
126 |
127 | ///
128 | /// Displays the MergeAction.
129 | ///
130 | /// True when the represented conflict has now been merged.
131 | public bool OnGUIMerge()
132 | {
133 | var wasMerged = merged;
134 | if (merged)
135 | {
136 | GUI.backgroundColor = wasResolvedAutomatically ? new Color(.9f, .9f, .3f, 1) : new Color(.2f, .8f, .2f, 1);
137 | }
138 | else
139 | {
140 | GUI.backgroundColor = new Color(1f, .25f, .25f, 1);
141 | }
142 | GUILayout.BeginHorizontal(Resources.styles.mergeAction);
143 | GUI.backgroundColor = Color.white;
144 | OnGUI();
145 | GUI.color = Color.white;
146 | GUILayout.EndHorizontal();
147 | return merged && !wasMerged;
148 | }
149 |
150 | // The actual UI of the MergeAction depends on the actual type
151 | public abstract void OnGUI();
152 |
153 | private void HighlightObject()
154 | {
155 | // Highlight the instance of the prefab, not the prefab itself
156 | // Otherwise, "ours".
157 | var objectToHighlight = MergeManagerBase.isMergingPrefab ? MergeManagerPrefab.ourPrefabInstance.GetChildWithEqualPath(ours) : ours;
158 | if (objectToHighlight && inMergePhase && objectToHighlight.hideFlags == HideFlags.None)
159 | {
160 | objectToHighlight.Highlight();
161 | }
162 | }
163 | }
164 | }
--------------------------------------------------------------------------------
/Editor/MergeManagerScene.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace GitMerge
3 | {
4 | using UnityEngine;
5 | using UnityEditor;
6 | using UnityEngine.SceneManagement;
7 | using UnityEditor.SceneManagement;
8 | using System.Collections.Generic;
9 |
10 | public class MergeManagerScene : MergeManagerBase
11 | {
12 | private const int NUMBER_OF_INITIALIZATION_STEPS = 3;
13 |
14 | private Scene theirScene;
15 |
16 | public MergeManagerScene(GitMergeWindow window, VCS vcs)
17 | : base(window, vcs)
18 | {
19 |
20 | }
21 |
22 | public bool TryInitializeMerge(string path = null)
23 | {
24 | var activeScene = EditorSceneManager.GetActiveScene();
25 |
26 | if (activeScene.isDirty)
27 | {
28 | window.ShowNotification(new GUIContent("Please make sure there are no unsaved changes before attempting to merge."));
29 | return false;
30 | }
31 |
32 | DisplayProgressBar(0, "Checking out scene...");
33 | isMergingScene = true;
34 | var scenePath = path ?? activeScene.path;
35 |
36 | // Overwrite the current scene to prevent the reload/ignore dialog that pops up after the upcoming changes to the file.
37 | // Pressing "reload" on it would invalidate the GameObject references we're about to collect.
38 | EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
39 | Lightmapping.ForceStop();
40 |
41 | vcs.CheckoutOurs(scenePath);
42 | CheckoutTheirVersionOf(scenePath);
43 | AssetDatabase.Refresh();
44 |
45 | DisplayProgressBar(1, "Opening scene...");
46 |
47 | activeScene = EditorSceneManager.OpenScene(scenePath, OpenSceneMode.Single);
48 |
49 | MergeAction.inMergePhase = false;
50 | ObjectDictionaries.Clear();
51 |
52 | List ourObjects;
53 | try
54 | {
55 | DisplayProgressBar(2, "Collecting differences...");
56 | // Find all of "our" objects
57 | ourObjects = GetAllSceneObjects();
58 | ObjectDictionaries.AddToOurObjects(ourObjects);
59 |
60 | // Add "their" objects
61 | theirScene = EditorSceneManager.OpenScene(theirFilename, OpenSceneMode.Additive);
62 |
63 | var addedObjects = GetAllNewSceneObjects(ourObjects);
64 | ObjectDictionaries.AddToTheirObjects(addedObjects);
65 | BuildAllMergeActions(ourObjects, addedObjects);
66 |
67 | MoveGameObjectsToScene(theirScene.GetRootGameObjects(), activeScene);
68 | }
69 | finally
70 | {
71 | EditorSceneManager.UnloadSceneAsync(theirScene);
72 | AssetDatabase.DeleteAsset(theirFilename);
73 |
74 | EditorUtility.ClearProgressBar();
75 | }
76 |
77 | if (allMergeActions.Count == 0)
78 | {
79 | window.ShowNotification(new GUIContent("No conflict found for this scene."));
80 | return false;
81 | }
82 |
83 | MergeAction.inMergePhase = true;
84 | return true;
85 | }
86 |
87 | private static void DisplayProgressBar(int step, string text)
88 | {
89 | var progress = step / (float)NUMBER_OF_INITIALIZATION_STEPS;
90 | EditorUtility.DisplayProgressBar("GitMerge for Unity", text, progress);
91 | }
92 |
93 | private static void MoveGameObjectsToScene(IEnumerable addedObjects, Scene scene)
94 | {
95 | foreach (var obj in addedObjects)
96 | {
97 | EditorSceneManager.MoveGameObjectToScene(obj, scene);
98 | }
99 | }
100 |
101 | private static List GetAllSceneObjects()
102 | {
103 | var objects = (GameObject[])Object.FindObjectsOfType(typeof(GameObject));
104 | return new List(objects);
105 | }
106 |
107 | ///
108 | /// Finds all GameObjects in the scene, minus the ones passed.
109 | ///
110 | private static List GetAllNewSceneObjects(List oldObjects)
111 | {
112 | var all = GetAllSceneObjects();
113 |
114 | foreach (var obj in oldObjects)
115 | {
116 | all.Remove(obj);
117 | }
118 |
119 | return all;
120 | }
121 |
122 | ///
123 | /// Completes the merge process after solving all conflicts.
124 | /// Cleans up the scene by deleting "their" GameObjects, clears merge related data structures,
125 | /// executes git add scene_name.
126 | ///
127 | public override void CompleteMerge()
128 | {
129 | MergeAction.inMergePhase = false;
130 |
131 | ObjectDictionaries.DestroyTheirObjects();
132 | ObjectDictionaries.Clear();
133 | EditorSceneManager.SaveScene(EditorSceneManager.GetActiveScene());
134 |
135 | allMergeActions = null;
136 |
137 | vcs.MarkAsMerged(fileName);
138 |
139 | // Directly committing here might not be that smart, since there might be more conflicts
140 |
141 | window.ShowNotification(new GUIContent("Scene successfully merged."));
142 | }
143 |
144 | ///
145 | /// Aborts merge by using "our" version in all conflicts.
146 | /// Cleans up merge related data.
147 | ///
148 | public override void AbortMerge(bool showNotification = true)
149 | {
150 | base.AbortMerge(showNotification);
151 |
152 | EditorSceneManager.CloseScene(theirScene, true);
153 |
154 | EditorSceneManager.SaveScene(EditorSceneManager.GetActiveScene());
155 | }
156 | }
157 | }
--------------------------------------------------------------------------------
/Editor/MergeManagerPrefab.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace GitMerge
3 | {
4 | using UnityEngine;
5 | using UnityEditor;
6 | using System.Collections.Generic;
7 | using UnityEditor.SceneManagement;
8 |
9 | public class MergeManagerPrefab : MergeManagerBase
10 | {
11 | public static GameObject ourPrefab { private set; get; }
12 | private static GameObject theirPrefab;
13 | public static GameObject ourPrefabInstance { private set; get; }
14 | private static string previouslyOpenedScenePath;
15 |
16 |
17 | public MergeManagerPrefab(GitMergeWindow window, VCS vcs)
18 | : base(window, vcs)
19 | {
20 |
21 | }
22 |
23 | public bool TryInitializeMerge(string prefabPath)
24 | {
25 | if (!EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo())
26 | {
27 | return false;
28 | }
29 |
30 | isMergingScene = false;
31 | MergeAction.inMergePhase = false;
32 |
33 | ObjectDictionaries.Clear();
34 |
35 | vcs.CheckoutOurs(prefabPath);
36 | CheckoutTheirVersionOf(prefabPath);
37 | AssetDatabase.Refresh();
38 |
39 | ourPrefab = AssetDatabase.LoadAssetAtPath(prefabPath);
40 |
41 | if (ourPrefab == null)
42 | {
43 | DeleteTheirPrefabAndLoadPreviousScene();
44 | return false;
45 | }
46 |
47 | // Open a new Scene that will only display the prefab.
48 | previouslyOpenedScenePath = EditorSceneManager.GetActiveScene().path;
49 | EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
50 | Lightmapping.ForceStop();
51 |
52 | // Instantiate our object in order to view it while merging.
53 | ourPrefabInstance = PrefabUtility.InstantiatePrefab(ourPrefab) as GameObject;
54 |
55 | // UI Elements need a Canvas to be displayed correctly:
56 | if (ourPrefabInstance.GetComponentInChildren() != null) {
57 | GameObject defaultCanvas = new GameObject("Canvas");
58 | defaultCanvas.AddComponent