Repository: devtron-labs/devtron
Pull request #2663 (2022-11-21 06:48:15)

docs: devtron readme - credentials update

# Description

- docs - The PR contains Documentation ONLY changes. 
- README. md file update: Credentials updated for Devtron version v0.6.0 higher and lesser than v0.6.0 versions






Patch:
diff --git a/README.md b/README.md
index 9ea1a6907..47106247c 100644
--- a/README.md
+++ b/README.md
@@ -47,11 +47,11 @@ Devtron deeply integrates with products across the lifecycle of microservices,i.
 [Devtron](#install-devtron) helps you deploy, observe, manage & debug existing Helm apps in all your clusters.
 
 
-## Devtron Demo environment
+## Devtron Demo Environment
 
 Please log in the <a href="https://preview.devtron.ai/dashboard/" rel="nofollow">Demo environment</a> using github credentials. Please note the user is granted view access.
 
-## Devtron features
+## Devtron Features
 
 <details><summary><b>Application-level Resource grouping for easier Debugging</b></summary>
 <br>
@@ -77,7 +77,7 @@ Please log in the <a href="https://preview.devtron.ai/dashboard/" rel="nofollow"
 
 Devtron is designed to be modular, and its functionality can be easily extended with the help of integrations.
 
-### CI/CD integration
+### CI/CD Integration
 
 [Devtron CI/CD with GitOps](#install-devtron-with-cicd-integration) integration is used to automate the builds and deployments and enables the software development teams to focus on meeting the business requirements, code quality, and security.
 
@@ -85,7 +85,7 @@ Devtron is designed to be modular, and its functionality can be easily extended
 * Supports pre-CI and post-CI integrations for code quality monitoring.
 * Seamlessly integrates with Clair for image vulnerability scanning.
 * Supports different deployment strategies: Blue/Green, Rolling, Canary, and Recreate.
-* Implements GitOps to manage the state of Kubernetes applications,
+* Implements GitOps to manage the state of Kubernetes applications.
 * Integrates with ArgoCD for continuous deployment.
 * Checks logs, events, and manifests or exec inside containers for debugging.
 * Provides deployment metrics like; deployment frequency, lead time, change failure rate, and mean-time recovery.
@@ -99,7 +99,7 @@ Devtron is designed to be modular, and its functionality can be easily extended
 
 Before you begin, you must create a [Kubernetes cluster](https://kubernetes.io/docs/tutorials/kubernetes-basics/create-cluster/) (preferably K8s 1.16 or higher) and install [Helm](https://helm.sh/docs/intro/install/).
 
-### 1. Install Devtron with CI/CD integration
+### 1. Install Devtron with CI/CD Integration
 
 Run the following command to install the latest version of Devtron along with the CI/CD module:
 
@@ -122,15 +122,22 @@ kubectl get svc -n devtroncd devtron-service -o jsonpath='{.status.loadBalancer.
 **Credentials**:
 
 **UserName**:  `admin` <br>
-**Password**:   Run the following command to get the admin password
+**Password**:   Run the following command to get the admin password for Devtron version v0.6.0 and higher
+
+```bash
+kubectl -n devtroncd get secret devtron-secret -o jsonpath='{.data.ADMIN_PASSWORD}' | base64 -d
+```
+
+For Devtron version less than v0.6.0, run the following command to get the admin password:
 
 ```bash
 kubectl -n devtroncd get secret devtron-secret -o jsonpath='{.data.ACD_PASSWORD}' | base64 -d
 ```
 
+
 Please refer to the document for more information on how to [access the Devtron Dashboard](./docs/setup/install/install-devtron-with-cicd.md/#access-devtron-dashboard).
 
-#### Installation status
+#### Installation Status
 
 The above install command for CI/CD integration starts Devtron-operator, which takes about 20 minutes to spin up all of the Devtron microservices one by one. You can check the status of the installation with the following command:
 
diff --git a/Wire.go b/Wire.go
index cc56998f8..5c580c30b 100644
--- a/Wire.go
+++ b/Wire.go
@@ -686,6 +686,20 @@ func InitializeApp() (*App, error) {
 		wire.Bind(new(repository3.PrePostCdScriptHistoryRepository), new(*repository3.PrePostCdScriptHistoryRepositoryImpl)),
 		repository3.NewPipelineStrategyHistoryRepositoryImpl,
 		wire.Bind(new(repository3.PipelineStrategyHistoryRepository), new(*repository3.PipelineStrategyHistoryRepositoryImpl)),
+		repository3.NewGitMaterialHistoryRepositoyImpl,
+		wire.Bind(new(repository3.GitMaterialHistoryRepository), new(*repository3.GitMaterialHistoryRepositoryImpl)),
+
+		history3.NewCiTemplateHistoryServiceImpl,
+		wire.Bind(new(history3.CiTemplateHistoryService), new(*history3.CiTemplateHistoryServiceImpl)),
+
+		repository3.NewCiTemplateHistoryRepositoryImpl,
+		wire.Bind(new(repository3.CiTemplateHistoryRepository), new(*repository3.CiTemplateHistoryRepositoryImpl)),
+
+		history3.NewCiPipelineHistoryServiceImpl,
+		wire.Bind(new(history3.CiPipelineHistoryService), new(*history3.CiPipelineHistoryServiceImpl)),
+
+		repository3.NewCiPipelineHistoryRepositoryImpl,
+		wire.Bind(new(repository3.CiPipelineHistoryRepository), new(*repository3.CiPipelineHistoryRepositoryImpl)),
 
 		history3.NewPrePostCdScriptHistoryServiceImpl,
 		wire.Bind(new(history3.PrePostCdScriptHistoryService), new(*history3.PrePostCdScriptHistoryServiceImpl)),
@@ -697,6 +711,8 @@ func InitializeApp() (*App, error) {
 		wire.Bind(new(history3.ConfigMapHistoryService), new(*history3.ConfigMapHistoryServiceImpl)),
 		history3.NewPipelineStrategyHistoryServiceImpl,
 		wire.Bind(new(history3.PipelineStrategyHistoryService), new(*history3.PipelineStrategyHistoryServiceImpl)),
+		history3.NewGitMaterialHistoryServiceImpl,
+		wire.Bind(new(history3.GitMaterialHistoryService), new(*history3.GitMaterialHistoryServiceImpl)),
 
 		history3.NewDeployedConfigurationHistoryServiceImpl,
 		wire.Bind(new(history3.DeployedConfigurationHistoryService), new(*history3.DeployedConfigurationHistoryServiceImpl)),
diff --git a/docs/README.md b/docs/README.md
index 445dde07b..870895020 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -100,4 +100,4 @@ We at Devtron take security and our users' trust very seriously. If you believe
  
 ## License
  
-Devtron is available under the [Apache License, Version 2.0](../LICENSE).
+Devtron is available under the [Apache License, Version 2.0](https://github.com/devtron-labs/devtron/blob/main/LICENSE).
diff --git a/docs/user-guide/global-configurations/docker-registries.md b/docs/user-guide/global-configurations/docker-registries.md
index 564dabf09..4f71cb7b0 100644
--- a/docs/user-guide/global-configurations/docker-registries.md
+++ b/docs/user-guide/global-configurations/docker-registries.md
@@ -1,43 +1,52 @@
 # Container Registries
 
-Container registries are used to store images built by the CI Pipeline. Here you can configure the container registry you want to use for storing images.
+Container registries are used for storing images built by the CI Pipeline. You can configure the container registry using any container registry provider of your choice. It allows you to build, deploy and manage your container images with easy-to-use UI. 
 
-When configuring an application, you can choose which registry and repository it should use in the App Configuration > [Docker Build Config](../creating-application/deployment-template.md) section.
+When configuring an application, you can choose the specific container registry and repository in the App Configuration > [Build Configuration](user-guide/creating-application/docker-build-configuration.md) section.
 
-## Add Container Registry configuration:
+Provide the information in the following fields to configure the container registry from App Configuration > [Build Configuration](user-guide/creating-application/docker-build-configuration.md) section.
 
-Go to the `Container Registry` section of `Global Configuration`. Click on `Add container registry`.
+| Fields | Description |
+| --- | --- |
+| **Container Registry** | Select the container registry from the drop-down list. |
+| **Container Repository** | Enter the name of the container repository. |
 
-You will see below the input fields to configure the container registry.
 
-* Name
-* Registry type
-  * ecr
-    * AWS region
-    * Access key ID
-    * Secret access key
-  * docker hub
-    * Username
-    * Password
-  * Others
-    * Username
-    * password
-* Registry URL
-* Set as default
+## Add Container Registry:
 
-![](../../user-guide/global-configurations/images/Container_Registry.jpg)
+To add container registry, go to the `Container Registry` section of `Global Configurations`. Click **Add Container Registry**.
 
-### Name
+| Fields | Description |
+| --- | --- |
+| **Name** | Provide a name to your registry, this name will be shown to you in Build Configuration in the drop-down list. |
+| **Registry Type** | Select the registry type from the drop-down list. E.g., Docker. |
+| **Registry URL** | Provide the URL of your registry. |
+| **Set as default registry** | Enable this field to set as default registry hub for your images. |
 
-Provide a name to your registry, this name will be shown to you in Docker Build Config as a drop-down.
+* For each **Registry Type**, the credential input fields are different. Please see the table below to know the required credential inputs as per the selected registry type.
 
-### Registry type
+| Registry Type | Credentials |
+| --- | --- |
+| **ECR** | Select one of the authentication types:<ul><li>**EC2 IAM Role**</li></ul> <ul><li>**User Auth**<ul><li>`Access key ID`: </li></ul><ul><li>`Secret access key`</li></ul></li></ul>|
+| **Docker** | <ul><li>`Username`</li></ul> <ul><li>`Password/Token (Recommended:Token)`</li></ul> |
+| **Azure**  | <ul><li>`Username/Registry Name`</li></ul> <ul><li>`Password`</li></ul>  |
+| **Artifact Registry (GCP)**  | <ul><li>`Username`</li></ul> <ul><li>`Service Account JSON File*`</li></ul>  |
+| **GCR**  | <ul><li>`Username`</li></ul> <ul><li>`Service Account JSON File*`</li></ul>  |
+| **Quay**  | <ul><li>`Username`</li></ul> <ul><li>`Token`</li></ul>  |
+| **Other**  | <ul><li>`Username`</li></ul> <ul><li>`Password/Token`</li></ul>  |
 
-Here you can select the type of the Registry. We are supporting three types- `docker hub`, `ecr` and `others`. You can select any one of them from the drop-down. By default, this value is `ecr`. If you select ecr then you have to provide some information like- `AWS region, Access Key`, and `Secret Key`. If you select docker hub then you have to provide `Username` and `Password`. And if you select others then you have to provide the `Username` and `Password`.
+  
+![](https://devtron-public-asset.s3.us-east-2.amazonaws.com/images/global-configurations/container-registries/add-container-registry.jpg)
 
-### Registry URL
 
-Select any type of Registry from the drop-down, you have to provide the URL of your registry. Create your registry and provide the URL of that registry in the URL box.
+Please read each `registry type` in detail for you to help in choosing the right container registry for your application development needs.
+
+* [Registry Type: ECR](#registry-type-ecr)
+* [Registry Type: Docker](#registry-type-docker)
+* [Registry Type: Google Container Registry (GCR)](#registry-type-google-container-registry-gcr)
+* [Registry Type: Artifact Registry (GCP)](#registry-type-artifact-registry-gcp)
+* [Registry Type: Others](#registry-type-others)
+
 
 ### Registry Type: ECR
 
@@ -53,71 +62,152 @@ Before you begin, create an [IAM user](https://docs.aws.amazon.com/AmazonECR/lat
 | **Name** | User-defined name for the registry in Devtron |
 | **Registry Type** | Select **ECR** |
 | **Registry URL** | This is the URL of your private registry in AWS. <br></br> For example, the URL format is: `https://xxxxxxxxxxxx.dkr.ecr.<region>.amazonaws.com`. <br></br>`xxxxxxxxxxxx` is your 12-digit AWS account Id. |
-| **Authentication Type** | <br></br> * **EC2 IAM role**: Authenticate with workernode IAM role. <br></br> * **User Auth**: Authenticate with an authorization token <br></br>  - **Access key ID**: Your AWS access key <br></br>  - **Secret access key**: Your AWS secret access key ID |
+| **Authentication Type** | <br></br> * **EC2 IAM role**: Authenticate with workernode IAM role. <br></br> * **User Auth**: Authenticate with an authorization token <br></br>  - **Access key ID**: Your AWS access key. <br></br>  - **Secret access key**: Your AWS secret access key ID. |
 
 ![ECR Role-based authentication](https://devtron-public-asset.s3.us-east-2.amazonaws.com/Container-registeries/ECR-IAM-auth-role-based.png)
 
 ![ECR Key-based authentication](https://devtron-public-asset.s3.us-east-2.amazonaws.com/Container-registeries/ECR_user-auth-key-based.png)
 
-To set this `ECR` as the default registry hub for your images, select **[x] Set as default registry**.
+To set the `ECR` as the default registry hub for your images, enable the field **[x] Set as default registry** and then click **Save**.
 
-Select **Save**.
+To use the ECR container image, go to the **Applications** page and select your application, and then select **App Configuration > [Build Configuration](./../creating-application/docker-build-configuration.md)**.
 
-To use the ECR container image, go to the **Applications** page and select your application, and then select **App Configuration > [Docker Build Config](./../creating-application/docker-build-configuration.md)**.
+### Registry Type: Docker 
 
-### Registry Type- Docker Hub 
-
-You have to provide the below information if you select the registry type as Docker Hub.
+You have to provide below information if you select the registry type as `Docker`.
 
 * **Username**
 
-Give the username of the docker hub account you used for creating your registry in.
+Provide the username of the docker hub account you used for creating your registry.
 
 * **Password**
 
-Give the password/[token](https://docs.docker.com/docker-hub/access-tokens/) corresponding to your docker hub account.
+Provide the password/[Token](https://docs.docker.com/docker-hub/access-tokens/) corresponding to your docker hub account. 
+It is recommended to use `Token` for security purpose.
 
 ![](../../user-guide/global-configurations/images/Container_Registry_DockerHub.jpg)
 
-### Registry Type Others:
+### Registry Type: Google Container Registry (GCR) 
+
+You have to provide below information if you select the registry type as `GCR`.
+JSON key file authentication method can be used to authenticate with username and service account JSON file. Please follow [link](https://cloud.google.com/container-registry/docs/advanced-authentication#json-key) for getting username and service account JSON file for this registry. Please remove all the white spaces from json key and wrap it in single quote while putting in the `Service Account JSON File` field.  
+ 
+![](../../user-guide/global-configurations/images/Container_Registry_gcr.jpg)
 
-You have to provide the below information if you select the registry type as others.
+### Registry Type: Artifact Registry (GCP) 
 
-* **Username**
+You have to provide below information if you select the registry type as `Artifact Registry (GCP)`.
+JSON key file authentication method can be used to authenticate with username and service account JSON file. Please follow [link](https://cloud.google.com/artifact-registry/docs/docker/authentication#json-key) for getting username and service account JSON file for this registry. Please remove all the white spaces from json key and wrap it in single quote while putting in `Service Account JSON File` field.
 
-Give the username of your account, where you have created your registry in.
 
-* **Password**
+### Registry Type: Azure
+Service principal authentication method can be used to authenticate with username and password. Please follow [link](https://docs.microsoft.com/en-us/azure/container-registry/container-registry-auth-service-principal) for getting username and password for this registry.
 
-Give the password corresponding to the username of your registry.
 
-![](../../user-guide/global-configurations/images/Container_Registry_others.jpg)
+### Registry Type: Others
 
-### Set as default:
+You have to provide below information if you select the registry type as `Others`.
 
-If you enable the `Set as default` option, then this registry name will be set as default in the `Container Registry` section inside the `Docker build config` page. This is optional. You can keep it disabled.
+* **Username**
 
-### Advance Registry Url connection options:
+Provide the username of your account, where you have created your registry in.
 
-* If you enable the `Allow Only Secure Connection` option, then this registry allows only secure connections.
+* **Password/Token**
 
-* If you enable the `Allow Secure Connection With CA Certificate` option, then you have to upload/provide private CA certificate (ca.crt).
+Provide the Password/Token corresponding to the username of your registry.
 
-* If the container registry is insecure (for eg : SSL certificate is expired), then you enable the `Allow Insecure Connection` option.
+### Set as default registry:
 
-Now click on `Save` to save the configuration of the `Container registry`.
+If you enable the `Set as default registry` option, then the registry name will be set as default in the `Container Registry` section on the App Configuration >`Build Configuration` page. This field is optional. You can keep it disabled.
 
-### Note:
+### Advance Registry URL Connection Options:
 
+* If you enable the `Allow Only Secure Connection` option, then this registry allows only secure connections.
+* If you enable the `Allow Secure Connection With CA Certificate` option, then you have to upload/provide private CA certificate (ca.crt).
+* If the container registry is insecure (for eg : SSL certificate is expired), then you enable the `Allow Insecure Connection` option.
+
+#### Note:
 You can use any registry which can be authenticated using `docker login -u <username> -p <password> <registry-url>`. However these registries might provide a more secured way for authentication, which we will support later.
-Some popular registries which can be used using username and password mechanism:
 
-* **Google Container Registry (GCR)** : JSON key file authentication method can be used to authenticate with username and password. Please follow [link](https://cloud.google.com/container-registry/docs/advanced-authentication#json-key) for getting username and password for this registry. Please remove all the white spaces from json key and wrap it in single quote while putting in password field.  
 
-![](../../user-guide/global-configurations/images/Container_Registry_gcr.jpg)
+## Pull an Image from a Private Registry
+
+You can create a Pod that uses a `Secret` to pull an image from a private container image registry or repository. There are many private registries in use. This task uses [Docker Hub](https://www.docker.com/products/docker-hub) as an example registry.
+
+Super admin users can decide if they want to auto-inject registry credentials or use a secret to pull an image for deployment to environments on specific clusters.
+
+To manage the access of registry credentials, click **Manage**.
+
+There are two options to manage the access of registry credentials:
+
+| Fields | Description |
+| --- | --- |
+| **Do not inject credentials to clusters** | Select the clusters for which you do not want to inject credentials. |
+| **Auto-inject credentials to clusters** | Select the clusters for which you want to inject credentials. |
+
+You can choose one of the two options for defining credentials:
+
+* [User Registry Credentials](https://docs.devtron.ai/v/v0.6/getting-started/global-configurations/docker-registries#user-registry-credentials)
+* [Specify Image Pull Secret](https://docs.devtron.ai/v/v0.6/getting-started/global-configurations/docker-registries#specify-image-pull-secret) 
+
+### Use Registry Credentials
+
+If you select **Use Registry Credentials**, the clusters will be auto-injected with the registry credentials of your registry type. As an example: If you select `Docker` as Registry Type and `docker.io` as Registry URL, the registry credentials of the clusters will be the `username` and `password` which you define.
+Click **Save**.
+
+![](https://devtron-public-asset.s3.us-east-2.amazonaws.com/images/global-configurations/container-registries/use-registry-credentials.jpg)
+
+
+### Specify Image Pull Secret
+
+You can create a Secret by providing credentials on the command line.
+
+![](https://devtron-public-asset.s3.us-east-2.amazonaws.com/images/global-configurations/container-registries/specify-image-pull-secret-latest.png)
+
+Create this Secret, naming it `regcred`:
+
+```bash
+kubectl create -n <namespace> secret docker-registry regcred --docker-server=<your-registry-server> --docker-username=<your-name> --docker-password=<your-pword> --docker-email=<your-email>
+```
+
+where:
+* <namespace> is your virtual cluster. E.g., devtron-demo
+* <your-registry-server> is your Private Docker Registry FQDN. Use https://index.docker.io/v1/ for DockerHub.
+* <your-name> is your Docker username.
+* <your-pword> is your Docker password.
+* <your-email> is your Docker email.
+
+You have successfully set your Docker credentials in the cluster as a Secret called `regcred`.
+
+**Note**: Typing secrets on the command line may store them in your shell history unprotected, and those secrets might also be visible to other users on your PC during the time when kubectl is running.
+
+Enter the `Secret` name in the field and click **Save**.
+
+
+## How to resolve if Deployment Status shows Failed or Degraded
+
+If the deployment status shows `Failed` or `Degraded`, then the cluster is not able to pull container image from the private registry. In that case, the status of pod shows `ImagePullBackOff`.
+
+The failure of deployment can be one of the following reasons:
+
+* Provided credentials may not have permission to pull container image from registry.
+* Provided credentials may be invalid.
+
+You can resolve the `ImagePullBackOff` issue by clicking **How to resolve?** which will take you to the **App Details** page.
+
+![](https://devtron-public-asset.s3.us-east-2.amazonaws.com/images/global-configurations/container-registries/how-to-resolve-latest1.png)
+
+
+To provide the auto-inject credentials to the specific clusters for pulling the image from the private repository, click **Manage Access** which will take you to the **Container Registries** page. 
+
+![](https://devtron-public-asset.s3.us-east-2.amazonaws.com/images/global-configurations/container-registries/manage-access-latest.jpg)
+
+1. On the **Container Registries** page, select the docker registry and click **Manage**.
+2. In the **Auto-inject credentials to clusters**, click **Confirm to edit** to select the specific cluster or all clusters for which you want to auto-inject the credentials to and click **Save**.
+3. Redeploy the application after allowing the access.
+
+![](https://devtron-public-asset.s3.us-east-2.amazonaws.com/images/global-configurations/container-registries/auto-inject-to-clusters.jpg)
 
-* **Google Artifact Registry (GAR)** : JSON key file authentication method can be used to authenticate with username and password. Please follow [link](https://cloud.google.com/artifact-registry/docs/docker/authentication#json-key) for getting username and password for this registry. Please remove all the white spaces from json key and wrap it in single quote while putting in password field.
-* **Azure Container Registry (ACR)** : Service principal authentication method can be used to authenticate with username and password. Please follow [link](https://docs.microsoft.com/en-us/azure/container-registry/container-registry-auth-service-principal) for getting username and password for this registry.
 
 ## Integrating With External Container Registry
 
@@ -135,3 +225,17 @@ secrets:
 ```     
 
 The `name` that you provide in values.yaml ie. `regcred` is name of the secret that will be used as `imagePullSecrets` to pull the image from docker hub to deploy. To know how `imagePullSecrets` will be used in the deployment-template, please follow the [documentation](https://docs.devtron.ai/devtron/user-guide/creating-application/deployment-template/rollout-deployment#imagepullsecrets).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/internal/sql/repository/pipelineConfig/CiPipelineRepository.go b/internal/sql/repository/pipelineConfig/CiPipelineRepository.go
index c64e4bdba..bb48427bb 100644
--- a/internal/sql/repository/pipelineConfig/CiPipelineRepository.go
+++ b/internal/sql/repository/pipelineConfig/CiPipelineRepository.go
@@ -168,7 +168,7 @@ func (impl CiPipelineRepositoryImpl) MarkCiPipelineScriptsInactiveByCiPipelineId
 func (impl CiPipelineRepositoryImpl) FindByAppId(appId int) (pipelines []*CiPipeline, err error) {
 	err = impl.dbConnection.Model(&pipelines).
 		Column("ci_pipeline.*", "CiPipelineMaterials", "ExternalCiPipeline", "CiPipelineMaterials.GitMaterial").
-		Where("app_id =?", appId).
+		Where("ci_pipeline.app_id =?", appId).
 		Where("deleted =? ", false).
 		Select()
 	return pipelines, err
diff --git a/pkg/bean/app.go b/pkg/bean/app.go
index f2f524464..f0fa76cae 100644
--- a/pkg/bean/app.go
+++ b/pkg/bean/app.go
@@ -267,6 +267,10 @@ type CiConfigRequest struct {
 	BeforeDockerBuild []*Task                 `json:"beforeDockerBuild,omitempty" validate:"dive"`
 	AfterDockerBuild  []*Task                 `json:"afterDockerBuild,omitempty" validate:"dive"`
 	ScanEnabled       bool                    `json:"scanEnabled,notnull"`
+	CreatedOn         time.Time          `sql:"created_on,type:timestamptz"`
+	CreatedBy         int32              `sql:"created_by,type:integer"`
+	UpdatedOn         time.Time          `sql:"updated_on,type:timestamptz"`
+	UpdatedBy         int32              `sql:"updated_by,type:integer"`
 }
 
 type TestExecutorImageProperties struct {
diff --git a/pkg/pipeline/CiHandler.go b/pkg/pipeline/CiHandler.go
index 5e84fb787..98aea5696 100644
--- a/pkg/pipeline/CiHandler.go
+++ b/pkg/pipeline/CiHandler.go
@@ -267,10 +267,6 @@ func (impl *CiHandlerImpl) FetchMaterialsByPipelineId(pipelineId int) ([]CiPipel
 
 	ciMaterialHistoryMap := make(map[*pipelineConfig.CiPipelineMaterial]*gitSensor.MaterialChangeResp)
 	for _, m := range ciMaterials {
-		// git material should be active in this case
-		if m == nil || m.GitMaterial == nil || !m.GitMaterial.Active {
-			continue
-		}
 		changesRequest := &gitSensor.FetchScmChangesRequest{
 			PipelineMaterialId: m.Id,
 		}
@@ -1083,11 +1079,6 @@ func (impl *CiHandlerImpl) FetchMaterialInfoByArtifactId(ciArtifactId int) (*Git
 			var history []*gitSensor.GitCommit
 			_gitTrigger := workflow.GitTriggers[m.Id]
 
-			// ignore git trigger which have commit and webhook both data nil
-			if len(_gitTrigger.Commit) == 0 && _gitTrigger.WebhookData.Id == 0 {
-				continue
-			}
-
 			_gitCommit := &gitSensor.GitCommit{
 				Message: _gitTrigger.Message,
 				Author:  _gitTrigger.Author,
diff --git a/pkg/pipeline/CiService.go b/pkg/pipeline/CiService.go
index 9ec123894..0e86f1ef3 100644
--- a/pkg/pipeline/CiService.go
+++ b/pkg/pipeline/CiService.go
@@ -296,10 +296,6 @@ func (impl *CiServiceImpl) buildWfRequestForCiPipeline(pipeline *pipelineConfig.
 	var ciProjectDetails []CiProjectDetails
 	commitHashes := trigger.CommitHashes
 	for _, ciMaterial := range ciMaterials {
-		// ignore those materials which have inactive git material
-		if ciMaterial == nil || ciMaterial.GitMaterial == nil || !ciMaterial.GitMaterial.Active {
-			continue
-		}
 		commitHashForPipelineId := commitHashes[ciMaterial.Id]
 		ciProjectDetail := CiProjectDetails{
 			GitRepository:   ciMaterial.GitMaterial.Url,
diff --git a/pkg/pipeline/DbPipelineOrchestrator.go b/pkg/pipeline/DbPipelineOrchestrator.go
index 2b5c2f831..e053f387d 100644
--- a/pkg/pipeline/DbPipelineOrchestrator.go
+++ b/pkg/pipeline/DbPipelineOrchestrator.go
@@ -61,9 +61,9 @@ type DbPipelineOrchestrator interface {
 	CreateCiConf(createRequest *bean.CiConfigRequest, templateId int) (*bean.CiConfigRequest, error)
 	CreateCDPipelines(pipelineRequest *bean.CDPipelineConfigObject, appId int, userId int32, tx *pg.Tx) (pipelineId int, err error)
 	UpdateCDPipeline(pipelineRequest *bean.CDPipelineConfigObject, userId int32, tx *pg.Tx) (err error)
-	DeleteCiPipeline(pipeline *pipelineConfig.CiPipeline, userId int32, tx *pg.Tx) error
+	DeleteCiPipeline(pipeline *pipelineConfig.CiPipeline, request *bean.CiPatchRequest, tx *pg.Tx) error
 	DeleteCdPipeline(pipelineId int, tx *pg.Tx) error
-	PatchMaterialValue(createRequest *bean.CiPipeline, userId int32) (*bean.CiPipeline, error)
+	PatchMaterialValue(createRequest *bean.CiPipeline, userId int32, oldPipeline *pipelineConfig.CiPipeline) (*bean.CiPipeline, error)
 	PipelineExists(name string) (bool, error)
 	GetCdPipelinesForApp(appId int) (cdPipelines *bean.CdPipelines, err error)
 	GetCdPipelinesForAppAndEnv(appId int, envId int) (cdPipelines *bean.CdPipelines, err error)
@@ -92,7 +92,10 @@ type DbPipelineOrchestratorImpl struct {
 	prePostCiScriptHistoryService history3.PrePostCiScriptHistoryService
 	pipelineStageService          PipelineStageService
 	//ciTemplateOverrideRepository  pipelineConfig.CiTemplateOverrideRepository
-	ciTemplateService CiTemplateService
+	ciTemplateService            CiTemplateService
+	ciTemplateOverrideRepository pipelineConfig.CiTemplateOverrideRepository
+	gitMaterialHistoryService    history3.GitMaterialHistoryService
+	ciPipelineHistoryService     history3.CiPipelineHistoryService
 }
 
 func NewDbPipelineOrchestrator(
@@ -112,7 +115,9 @@ func NewDbPipelineOrchestrator(
 	prePostCdScriptHistoryService history3.PrePostCdScriptHistoryService,
 	prePostCiScriptHistoryService history3.PrePostCiScriptHistoryService,
 	pipelineStageService PipelineStageService,
-	ciTemplateOverrideRepository pipelineConfig.CiTemplateOverrideRepository, ciTemplateService CiTemplateService) *DbPipelineOrchestratorImpl {
+	ciTemplateOverrideRepository pipelineConfig.CiTemplateOverrideRepository,
+	gitMaterialHistoryService history3.GitMaterialHistoryService,
+	ciPipelineHistoryService history3.CiPipelineHistoryService, ciTemplateService CiTemplateService) *DbPipelineOrchestratorImpl {
 	return &DbPipelineOrchestratorImpl{
 		appRepository:                 pipelineGroupRepository,
 		logger:                        logger,
@@ -131,20 +136,23 @@ func NewDbPipelineOrchestrator(
 		prePostCdScriptHistoryService: prePostCdScriptHistoryService,
 		prePostCiScriptHistoryService: prePostCiScriptHistoryService,
 		pipelineStageService:          pipelineStageService,
-		//ciTemplateOverrideRepository:  ciTemplateOverrideRepository,
-		ciTemplateService: ciTemplateService,
+		ciTemplateOverrideRepository:  ciTemplateOverrideRepository,
+		gitMaterialHistoryService:     gitMaterialHistoryService,
+		ciPipelineHistoryService:      ciPipelineHistoryService,
+		ciTemplateService:             ciTemplateService,
 	}
 }
 
 const BEFORE_DOCKER_BUILD string = "BEFORE_DOCKER_BUILD"
 const AFTER_DOCKER_BUILD string = "AFTER_DOCKER_BUILD"
 
-func (impl DbPipelineOrchestratorImpl) PatchMaterialValue(createRequest *bean.CiPipeline, userId int32) (*bean.CiPipeline, error) {
+func (impl DbPipelineOrchestratorImpl) PatchMaterialValue(createRequest *bean.CiPipeline, userId int32, oldPipeline *pipelineConfig.CiPipeline) (*bean.CiPipeline, error) {
 	argByte, err := json.Marshal(createRequest.DockerArgs)
 	if err != nil {
 		impl.logger.Error(err)
 		return nil, err
 	}
+
 	dbConnection := impl.pipelineRepository.GetConnection()
 	tx, err := dbConnection.Begin()
 	if err != nil {
@@ -166,6 +174,15 @@ func (impl DbPipelineOrchestratorImpl) PatchMaterialValue(createRequest *bean.Ci
 		IsDockerConfigOverridden: createRequest.IsDockerConfigOverridden,
 		AuditLog:                 sql.AuditLog{UpdatedBy: userId, UpdatedOn: time.Now()},
 	}
+
+	createOnTimeMap := make(map[int]time.Time)
+	createByMap := make(map[int]int32)
+
+	for _, oldMaterial := range oldPipeline.CiPipelineMaterials {
+		createOnTimeMap[oldMaterial.GitMaterialId] = oldMaterial.CreatedOn
+		createByMap[oldMaterial.GitMaterialId] = oldMaterial.CreatedBy
+	}
+
 	err = impl.ciPipelineRepository.Update(ciPipelineObject, tx)
 	if err != nil {
 		return nil, err
@@ -217,6 +234,8 @@ func (impl DbPipelineOrchestratorImpl) PatchMaterialValue(createRequest *bean.Ci
 			materialsAdd = append(materialsAdd, pipelineMaterial)
 		} else {
 			materialsUpdate = append(materialsUpdate, pipelineMaterial)
+			pipelineMaterial.CreatedOn = createOnTimeMap[material.GitMaterialId]
+			pipelineMaterial.CreatedBy = createByMap[material.GitMaterialId]
 		}
 	}
 	regexMaterial, err := impl.ciPipelineMaterialRepository.GetRegexByPipelineId(createRequest.Id)
@@ -313,6 +332,7 @@ func (impl DbPipelineOrchestratorImpl) PatchMaterialValue(createRequest *bean.Ci
 				UpdatedBy: userId,
 			},
 		}
+
 		savedTemplateOverride := savedTemplateOverrideBean.CiTemplateOverride
 		if savedTemplateOverride != nil && savedTemplateOverride.Id > 0 {
 			ciBuildConfigBean.Id = savedTemplateOverride.CiBuildConfigId
@@ -328,6 +348,13 @@ func (impl DbPipelineOrchestratorImpl) PatchMaterialValue(createRequest *bean.Ci
 			if err != nil {
 				return nil, err
 			}
+
+			err = impl.ciPipelineHistoryService.SaveHistory(ciPipelineObject, materials, ciTemplateBean, repository4.TRIGGER_UPDATE)
+
+			if err != nil {
+				impl.logger.Errorw("error in saving history of ci pipeline material")
+			}
+
 		} else {
 			ciTemplateBean := &bean2.CiTemplateBean{
 				CiTemplateOverride: templateOverrideReq,
@@ -338,8 +365,28 @@ func (impl DbPipelineOrchestratorImpl) PatchMaterialValue(createRequest *bean.Ci
 			if err != nil {
 				return nil, err
 			}
+
+			err = impl.ciPipelineHistoryService.SaveHistory(ciPipelineObject, materials, ciTemplateBean, repository4.TRIGGER_UPDATE)
+
+			if err != nil {
+				impl.logger.Errorw("error in saving history of ci pipeline material")
+			}
+
+		}
+	} else {
+
+		ciTemplateBean := &bean2.CiTemplateBean{
+			CiTemplateOverride: &pipelineConfig.CiTemplateOverride{},
+			CiBuildConfig:      nil,
+			UserId:             userId,
+		}
+		err = impl.ciPipelineHistoryService.SaveHistory(ciPipelineObject, materials, ciTemplateBean, repository4.TRIGGER_UPDATE)
+
+		if err != nil {
+			impl.logger.Errorw("error in saving history of ci pipeline material")
 		}
 	}
+
 	if len(childrenCiPipelineIds) > 0 {
 
 		ciPipelineMaterials, err := impl.ciPipelineMaterialRepository.FindByCiPipelineIdsIn(childrenCiPipelineIds)
@@ -380,11 +427,17 @@ func (impl DbPipelineOrchestratorImpl) PatchMaterialValue(createRequest *bean.Ci
 	return createRequest, nil
 }
 
-func (impl DbPipelineOrchestratorImpl) DeleteCiPipeline(pipeline *pipelineConfig.CiPipeline, userId int32, tx *pg.Tx) error {
+func (impl DbPipelineOrchestratorImpl) DeleteCiPipeline(pipeline *pipelineConfig.CiPipeline, request *bean.CiPatchRequest, tx *pg.Tx) error {
+
+	userId := request.UserId
+
 	p := &pipelineConfig.CiPipeline{
-		Id:       pipeline.Id,
-		Deleted:  true,
-		AuditLog: sql.AuditLog{UpdatedBy: userId, UpdatedOn: time.Now()},
+		Id:                       pipeline.Id,
+		Deleted:                  true,
+		ScanEnabled:              pipeline.ScanEnabled,
+		IsManual:                 pipeline.IsManual,
+		IsDockerConfigOverridden: pipeline.IsDockerConfigOverridden,
+		AuditLog:                 sql.AuditLog{UpdatedBy: userId, UpdatedOn: time.Now()},
 	}
 	err := impl.ciPipelineRepository.Update(p, tx)
 	if err != nil {
@@ -419,6 +472,51 @@ func (impl DbPipelineOrchestratorImpl) DeleteCiPipeline(pipeline *pipelineConfig
 		}
 	}
 	err = impl.ciPipelineMaterialRepository.Update(tx, materials...)
+
+	if !request.CiPipeline.IsDockerConfigOverridden {
+
+		CiTemplateBean := bean2.CiTemplateBean{
+			CiTemplate:         nil,
+			CiTemplateOverride: &pipelineConfig.CiTemplateOverride{},
+			CiBuildConfig:      request.CiPipeline.DockerConfigOverride.CiBuildConfig,
+			UserId:             userId,
+		}
+
+		err := impl.ciPipelineHistoryService.SaveHistory(p, materials, &CiTemplateBean, repository4.TRIGGER_DELETE)
+
+		if err != nil {
+			impl.logger.Errorw("error in saving delete history for ci pipeline material and ci template overridden")
+		}
+
+	} else {
+		CiTemplateBean := bean2.CiTemplateBean{
+			CiTemplate: nil,
+			CiTemplateOverride: &pipelineConfig.CiTemplateOverride{
+				CiPipelineId:     request.CiPipeline.Id,
+				DockerRegistryId: request.CiPipeline.DockerConfigOverride.DockerRegistry,
+				DockerRepository: request.CiPipeline.DockerConfigOverride.DockerRepository,
+				//DockerfilePath:   ciPipeline.DockerConfigOverride.DockerBuildConfig.DockerfilePath,
+				GitMaterialId: request.CiPipeline.DockerConfigOverride.CiBuildConfig.GitMaterialId,
+				Active:        false,
+				AuditLog: sql.AuditLog{
+					CreatedBy: userId,
+					CreatedOn: time.Now(),
+					UpdatedBy: userId,
+					UpdatedOn: time.Now(),
+				},
+			},
+			CiBuildConfig: request.CiPipeline.DockerConfigOverride.CiBuildConfig,
+			UserId:        userId,
+		}
+
+		err := impl.ciPipelineHistoryService.SaveHistory(p, materials, &CiTemplateBean, repository4.TRIGGER_DELETE)
+
+		if err != nil {
+			impl.logger.Errorw("error in saving delete history for ci pipeline material and ci template overridden")
+		}
+
+	}
+
 	return err
 }
 
@@ -560,7 +658,29 @@ func (impl DbPipelineOrchestratorImpl) CreateCiConf(createRequest *bean.CiConfig
 			if err != nil {
 				return nil, err
 			}
+
+			err = impl.ciPipelineHistoryService.SaveHistory(ciPipelineObject, pipelineMaterials, ciTemplateBean, repository4.TRIGGER_ADD)
+
+			if err != nil {
+				impl.logger.Errorw("error in saving history for ci pipeline")
+			}
+
+		} else {
+
+			ciTemplateBean := &bean2.CiTemplateBean{
+				CiTemplateOverride: &pipelineConfig.CiTemplateOverride{},
+				CiBuildConfig:      nil,
+				UserId:             createRequest.UserId,
+			}
+
+			err = impl.ciPipelineHistoryService.SaveHistory(ciPipelineObject, pipelineMaterials, ciTemplateBean, repository4.TRIGGER_ADD)
+
+			if err != nil {
+				impl.logger.Errorw("error in saving history for ci pipeline")
+			}
+
 		}
+
 		//creating ci stages after tx commit due to FK constraints
 		if ciPipeline.PreBuildStage != nil && len(ciPipeline.PreBuildStage.Steps) > 0 {
 			//creating pre stage
@@ -781,11 +901,14 @@ func (impl DbPipelineOrchestratorImpl) DeleteApp(appId int, userId int32) error
 		materials[i].UpdatedBy = userId
 	}
 	err = impl.materialRepository.Update(materials)
+
 	if err != nil {
 		impl.logger.Errorw("could not delete materials ", "err", err)
 		return err
 	}
 
+	err = impl.gitMaterialHistoryService.CreateDeleteMaterialHistory(materials)
+
 	impl.logger.Debug("deleting materials in git_sensor")
 	for _, m := range materials {
 		err = impl.updateRepositoryToGitSensor(m)
@@ -1029,10 +1152,14 @@ func (impl DbPipelineOrchestratorImpl) updateMaterial(updateMaterialDTO *bean.Up
 	currentMaterial.AuditLog = sql.AuditLog{UpdatedBy: updateMaterialDTO.UserId, CreatedBy: currentMaterial.CreatedBy, UpdatedOn: time.Now(), CreatedOn: currentMaterial.CreatedOn}
 
 	err = impl.materialRepository.UpdateMaterial(currentMaterial)
+
 	if err != nil {
 		impl.logger.Errorw("error in updating material", "material", currentMaterial, "err", err)
 		return nil, err
 	}
+
+	err = impl.gitMaterialHistoryService.CreateMaterialHistory(currentMaterial)
+
 	return currentMaterial, nil
 }
 
@@ -1050,10 +1177,14 @@ func (impl DbPipelineOrchestratorImpl) createMaterial(inputMaterial *bean.GitMat
 		AuditLog:        sql.AuditLog{UpdatedBy: userId, CreatedBy: userId, UpdatedOn: time.Now(), CreatedOn: time.Now()},
 	}
 	err := impl.materialRepository.SaveMaterial(material)
+
 	if err != nil {
 		impl.logger.Errorw("error in saving material", "material", material, "err", err)
 		return nil, err
 	}
+
+	err = impl.gitMaterialHistoryService.CreateMaterialHistory(material)
+
 	return material, err
 }
 
diff --git a/pkg/pipeline/PipelineBuilder.go b/pkg/pipeline/PipelineBuilder.go
index c003f814a..b56bb11eb 100644
--- a/pkg/pipeline/PipelineBuilder.go
+++ b/pkg/pipeline/PipelineBuilder.go
@@ -156,8 +156,12 @@ type PipelineBuilderImpl struct {
 	ciPipelineMaterialRepository     pipelineConfig.CiPipelineMaterialRepository
 	//ciTemplateOverrideRepository     pipelineConfig.CiTemplateOverrideRepository
 	//ciBuildConfigService CiBuildConfigService
-	ciTemplateService CiTemplateService
-	userService       user.UserService
+	ciTemplateService            CiTemplateService
+	userService                  user.UserService
+	ciTemplateOverrideRepository pipelineConfig.CiTemplateOverrideRepository
+	gitMaterialHistoryService    history.GitMaterialHistoryService
+	CiTemplateHistoryService     history.CiTemplateHistoryService
+	CiPipelineHistoryService     history.CiPipelineHistoryService
 }
 
 func NewPipelineBuilderImpl(logger *zap.SugaredLogger,
@@ -196,7 +200,11 @@ func NewPipelineBuilderImpl(logger *zap.SugaredLogger,
 	deploymentGroupRepository repository.DeploymentGroupRepository,
 	ciPipelineMaterialRepository pipelineConfig.CiPipelineMaterialRepository,
 	userService user.UserService,
-	ciTemplateOverrideRepository pipelineConfig.CiTemplateOverrideRepository, ciTemplateService CiTemplateService) *PipelineBuilderImpl {
+	ciTemplateService CiTemplateService,
+	ciTemplateOverrideRepository pipelineConfig.CiTemplateOverrideRepository,
+	gitMaterialHistoryService history.GitMaterialHistoryService,
+	CiTemplateHistoryService history.CiTemplateHistoryService,
+	CiPipelineHistoryService history.CiPipelineHistoryService) *PipelineBuilderImpl {
 	return &PipelineBuilderImpl{
 		logger:                        logger,
 		dbPipelineOrchestrator:        dbPipelineOrchestrator,
@@ -240,7 +248,11 @@ func NewPipelineBuilderImpl(logger *zap.SugaredLogger,
 		ciTemplateService:                ciTemplateService,
 		//ciTemplateOverrideRepository:     ciTemplateOverrideRepository,
 		//ciBuildConfigService: ciBuildConfigService,
-		userService: userService,
+		userService:                  userService,
+		ciTemplateOverrideRepository: ciTemplateOverrideRepository,
+		gitMaterialHistoryService:    gitMaterialHistoryService,
+		CiTemplateHistoryService:     CiTemplateHistoryService,
+		CiPipelineHistoryService:     CiPipelineHistoryService,
 	}
 }
 
@@ -311,11 +323,15 @@ func (impl PipelineBuilderImpl) DeleteMaterial(request *bean.UpdateMaterialDTO)
 	}
 	existingMaterial.UpdatedOn = time.Now()
 	existingMaterial.UpdatedBy = request.UserId
+
 	err = impl.materialRepo.MarkMaterialDeleted(existingMaterial)
+
 	if err != nil {
 		impl.logger.Errorw("error in deleting git material", "gitMaterial", existingMaterial)
 		return err
 	}
+	err = impl.gitMaterialHistoryService.MarkMaterialDeletedAndCreateHistory(existingMaterial)
+
 	return nil
 }
 
@@ -429,6 +445,10 @@ func (impl PipelineBuilderImpl) getCiTemplateVariables(appId int) (ciConfig *bea
 		Version:        template.Version,
 		CiTemplateName: template.TemplateName,
 		Materials:      materials,
+		UpdatedOn:      template.UpdatedOn,
+		UpdatedBy:      template.UpdatedBy,
+		CreatedBy:      template.CreatedBy,
+		CreatedOn:      template.CreatedOn,
 	}
 	return ciConfig, err
 }
@@ -542,10 +562,6 @@ func (impl PipelineBuilderImpl) GetCiPipeline(appId int) (ciConfig *bean.CiConfi
 			}
 		}
 		for _, material := range pipeline.CiPipelineMaterials {
-			// ignore those materials which have inactive git material
-			if material == nil || material.GitMaterial == nil || !material.GitMaterial.Active {
-				continue
-			}
 			ciMaterial := &bean.CiMaterial{
 				Id:              material.Id,
 				CheckoutPath:    material.CheckoutPath,
@@ -679,6 +695,7 @@ func (impl PipelineBuilderImpl) UpdateCiTemplate(updateRequest *bean.CiConfigReq
 		GitMaterialId: ciBuildConfig.GitMaterialId,
 		//Args:              string(argByte),
 		//TargetPlatform:    originalCiConf.DockerBuildConfig.TargetPlatform,
+		AppId:             originalCiConf.AppId,
 		BeforeDockerBuild: string(beforeByte),
 		AfterDockerBuild:  string(afterByte),
 		Version:           originalCiConf.Version,
@@ -686,6 +703,12 @@ func (impl PipelineBuilderImpl) UpdateCiTemplate(updateRequest *bean.CiConfigReq
 		DockerRepository:  originalCiConf.DockerRepository,
 		DockerRegistryId:  originalCiConf.DockerRegistry,
 		Active:            true,
+		AuditLog: sql.AuditLog{
+			CreatedOn: originalCiConf.CreatedOn,
+			CreatedBy: originalCiConf.CreatedBy,
+			UpdatedOn: time.Now(),
+			UpdatedBy: originalCiConf.UpdatedBy,
+		},
 	}
 
 	ciBuildConfig.Id = originalCiBuildConfig.Id
@@ -698,7 +721,15 @@ func (impl PipelineBuilderImpl) UpdateCiTemplate(updateRequest *bean.CiConfigReq
 	if err != nil {
 		return nil, err
 	}
+
 	originalCiConf.CiBuildConfig = ciBuildConfig
+
+	err = impl.CiTemplateHistoryService.SaveHistory(ciTemplateBean, "update")
+
+	if err != nil {
+		impl.logger.Errorw("error in saving update history for ci template", "error", err)
+	}
+
 	return originalCiConf, nil
 }
 
@@ -784,6 +815,13 @@ func (impl PipelineBuilderImpl) CreateCiPipeline(createRequest *bean.CiConfigReq
 	}
 
 	//-- template config end
+
+	err = impl.CiTemplateHistoryService.SaveHistory(ciTemplateBean, "add")
+
+	if err != nil {
+		impl.logger.Errorw("error in saving audit logs of ci Template", "error", err)
+	}
+
 	createRequest.Id = ciTemplate.Id
 	createRequest.CiTemplateName = ciTemplate.TemplateName
 	if len(createRequest.CiPipelines) > 0 {
@@ -1029,7 +1067,7 @@ func (impl PipelineBuilderImpl) DeleteCiPipeline(request *bean.CiPatchRequest) (
 	// Rollback tx on error.
 	defer tx.Rollback()
 
-	err = impl.dbPipelineOrchestrator.DeleteCiPipeline(pipeline, request.UserId, tx)
+	err = impl.dbPipelineOrchestrator.DeleteCiPipeline(pipeline, request, tx)
 	if err != nil {
 		impl.logger.Errorw("error in deleting pipeline db")
 		return nil, err
@@ -1093,7 +1131,7 @@ func (impl PipelineBuilderImpl) patchCiPipelineUpdateSource(baseCiConfig *bean.C
 		return nil, fmt.Errorf("update of plugin scm material not supported")
 	} else {
 		modifiedCiPipeline.ScanEnabled = baseCiConfig.ScanEnabled
-		modifiedCiPipeline, err = impl.dbPipelineOrchestrator.PatchMaterialValue(modifiedCiPipeline, baseCiConfig.UserId)
+		modifiedCiPipeline, err = impl.dbPipelineOrchestrator.PatchMaterialValue(modifiedCiPipeline, baseCiConfig.UserId, pipeline)
 		if err != nil {
 			return nil, err
 		}
@@ -2450,9 +2488,6 @@ func (impl PipelineBuilderImpl) GetCiPipelineById(pipelineId int) (ciPipeline *b
 		}
 	}
 	for _, material := range pipeline.CiPipelineMaterials {
-		if material == nil || material.GitMaterial == nil || !material.GitMaterial.Active {
-			continue
-		}
 		ciMaterial := &bean.CiMaterial{
 			Id:              material.Id,
 			CheckoutPath:    material.CheckoutPath,
diff --git a/pkg/pipeline/history/CiPipelineHistoryService.go b/pkg/pipeline/history/CiPipelineHistoryService.go
new file mode 100644
index 000000000..3811e5895
--- /dev/null
+++ b/pkg/pipeline/history/CiPipelineHistoryService.go
@@ -0,0 +1,97 @@
+package history
+
+import (
+	"encoding/json"
+	"github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig"
+	"github.com/devtron-labs/devtron/pkg/pipeline/bean"
+	"github.com/devtron-labs/devtron/pkg/pipeline/history/repository"
+	"github.com/devtron-labs/devtron/pkg/sql"
+	"go.uber.org/zap"
+	"time"
+)
+
+type CiPipelineHistoryService interface {
+	SaveHistory(pipeline *pipelineConfig.CiPipeline, CiPipelineMaterial []*pipelineConfig.CiPipelineMaterial, ciTemplateBean *bean.CiTemplateBean, Trigger string) error
+}
+
+type CiPipelineHistoryServiceImpl struct {
+	CiPipelineHistoryRepository repository.CiPipelineHistoryRepository
+	logger                      *zap.SugaredLogger
+}
+
+func NewCiPipelineHistoryServiceImpl(CiPipelineHistoryRepository repository.CiPipelineHistoryRepository,
+	logger *zap.SugaredLogger) *CiPipelineHistoryServiceImpl {
+	return &CiPipelineHistoryServiceImpl{
+		CiPipelineHistoryRepository: CiPipelineHistoryRepository,
+		logger:                      logger,
+	}
+}
+
+func (impl *CiPipelineHistoryServiceImpl) SaveHistory(pipeline *pipelineConfig.CiPipeline, CiPipelineMaterial []*pipelineConfig.CiPipelineMaterial, CiTemplateBean *bean.CiTemplateBean, Trigger string) error {
+
+	CiPipelineMaterialJson, _ := json.Marshal(CiPipelineMaterial)
+
+	var CiPipelineHistory repository.CiPipelineHistory
+	var CiTemplateOverride repository.CiPipelineTemplateOverrideHistoryDTO
+
+	IsDockerConfigOverriden := pipeline.IsDockerConfigOverridden
+
+	if IsDockerConfigOverriden {
+		ciTemplateId := 0
+		ciTemplateOverrideId := 0
+
+		CiBuildConfigDbEntity, _ := bean.ConvertBuildConfigBeanToDbEntity(ciTemplateId, ciTemplateOverrideId, CiTemplateBean.CiBuildConfig, CiTemplateBean.UserId)
+
+		CiTemplateOverride = repository.CiPipelineTemplateOverrideHistoryDTO{
+			DockerRegistryId:      CiTemplateBean.CiTemplateOverride.DockerRegistryId,
+			DockerRepository:      CiTemplateBean.CiTemplateOverride.DockerRepository,
+			DockerfilePath:        CiTemplateBean.CiTemplateOverride.DockerfilePath,
+			Active:                CiTemplateBean.CiTemplateOverride.Active,
+			CiBuildConfigId:       CiBuildConfigDbEntity.Id,
+			BuildMetaDataType:     CiBuildConfigDbEntity.Type,
+			BuildMetadata:         CiBuildConfigDbEntity.BuildMetadata,
+			AuditLog:              CiTemplateBean.CiTemplateOverride.AuditLog,
+			IsCiTemplateOverriden: true,
+		}
+
+	} else {
+
+		CiTemplateOverride = repository.CiPipelineTemplateOverrideHistoryDTO{
+			DockerRegistryId:  "",
+			DockerRepository:  "",
+			DockerfilePath:    "",
+			Active:            false,
+			CiBuildConfigId:   0,
+			BuildMetaDataType: "",
+			BuildMetadata:     "",
+			AuditLog: sql.AuditLog{
+				CreatedOn: time.Now(),
+				CreatedBy: CiTemplateBean.UserId,
+				UpdatedOn: time.Now(),
+				UpdatedBy: CiTemplateBean.UserId,
+			},
+			IsCiTemplateOverriden: false,
+		}
+
+	}
+	CiTemplateOverrideJson, _ := json.Marshal(CiTemplateOverride)
+
+	CiPipelineHistory = repository.CiPipelineHistory{
+		CiPipelineId:              pipeline.Id,
+		CiTemplateOverrideHistory: string(CiTemplateOverrideJson),
+		CiPipelineMaterialHistory: string(CiPipelineMaterialJson),
+		Trigger:                   Trigger,
+		ScanEnabled:               pipeline.ScanEnabled,
+		Manual:                    pipeline.IsManual,
+	}
+
+	err := impl.CiPipelineHistoryRepository.Save(&CiPipelineHistory)
+
+	if err != nil {
+		impl.logger.Errorw("error in saving history of ci pipeline")
+		return err
+	}
+
+	return nil
+
+}
diff --git a/pkg/pipeline/history/GitMaterialHistoryService.go b/pkg/pipeline/history/GitMaterialHistoryService.go
new file mode 100644
index 000000000..c40fcfeef
--- /dev/null
+++ b/pkg/pipeline/history/GitMaterialHistoryService.go
@@ -0,0 +1,101 @@
+package history
+
+import (
+	"github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig"
+	"github.com/devtron-labs/devtron/pkg/pipeline/history/repository"
+	"github.com/devtron-labs/devtron/pkg/sql"
+	"go.uber.org/zap"
+)
+
+type GitMaterialHistoryService interface {
+	CreateMaterialHistory(inputMaterial *pipelineConfig.GitMaterial) error
+	CreateDeleteMaterialHistory(materials []*pipelineConfig.GitMaterial) error
+	MarkMaterialDeletedAndCreateHistory(material *pipelineConfig.GitMaterial) error
+}
+
+type GitMaterialHistoryServiceImpl struct {
+	gitMaterialHistoryRepository repository.GitMaterialHistoryRepository
+	logger                       *zap.SugaredLogger
+}
+
+func NewGitMaterialHistoryServiceImpl(gitMaterialHistoryRepository repository.GitMaterialHistoryRepository,
+	logger *zap.SugaredLogger) *GitMaterialHistoryServiceImpl {
+
+	return &GitMaterialHistoryServiceImpl{
+		gitMaterialHistoryRepository: gitMaterialHistoryRepository,
+		logger:                       logger,
+	}
+}
+
+func (impl GitMaterialHistoryServiceImpl) CreateMaterialHistory(inputMaterial *pipelineConfig.GitMaterial) error {
+
+	material := &repository.GitMaterialHistory{
+		GitMaterialId:   inputMaterial.Id,
+		Url:             inputMaterial.Url,
+		AppId:           inputMaterial.AppId,
+		Name:            inputMaterial.Name,
+		GitProviderId:   inputMaterial.GitProviderId,
+		Active:          inputMaterial.Active,
+		CheckoutPath:    inputMaterial.CheckoutPath,
+		FetchSubmodules: inputMaterial.FetchSubmodules,
+		AuditLog:        sql.AuditLog{UpdatedBy: inputMaterial.UpdatedBy, CreatedBy: inputMaterial.CreatedBy, UpdatedOn: inputMaterial.UpdatedOn, CreatedOn: inputMaterial.CreatedOn},
+	}
+
+	err := impl.gitMaterialHistoryRepository.SaveGitMaterialHistory(material)
+
+	if err != nil {
+		impl.logger.Errorw("error in saving create/update history for git repository")
+	}
+
+	return nil
+
+}
+
+func (impl GitMaterialHistoryServiceImpl) CreateDeleteMaterialHistory(materials []*pipelineConfig.GitMaterial) error {
+
+	materialsHistory := []*repository.GitMaterialHistory{}
+
+	for _, material := range materials {
+
+		materialHistory := repository.GitMaterialHistory{
+			GitMaterialId:   material.Id,
+			AppId:           material.AppId,
+			GitProviderId:   material.GitProviderId,
+			Active:          material.Active,
+			Url:             material.Url,
+			Name:            material.Name,
+			CheckoutPath:    material.CheckoutPath,
+			FetchSubmodules: material.FetchSubmodules,
+			AuditLog: sql.AuditLog{
+				CreatedOn: material.CreatedOn,
+				CreatedBy: material.CreatedBy,
+				UpdatedOn: material.UpdatedOn,
+				UpdatedBy: material.UpdatedBy,
+			},
+		}
+		materialsHistory = append(materialsHistory, &materialHistory)
+	}
+
+	err := impl.gitMaterialHistoryRepository.SaveDeleteMaterialHistory(materialsHistory)
+
+	if err != nil {
+		impl.logger.Errorw("Error in saving delete history for git material Repository")
+	}
+
+	return nil
+
+}
+
+func (impl GitMaterialHistoryServiceImpl) MarkMaterialDeletedAndCreateHistory(material *pipelineConfig.GitMaterial) error {
+
+	material.Active = false
+
+	err := impl.CreateMaterialHistory(material)
+
+	if err != nil {
+		impl.logger.Errorw("error in saving delete history for git material repository")
+	}
+
+	return nil
+
+}
diff --git a/pkg/pipeline/history/ciTemplateHistoryService.go b/pkg/pipeline/history/ciTemplateHistoryService.go
new file mode 100644
index 000000000..44d3704e1
--- /dev/null
+++ b/pkg/pipeline/history/ciTemplateHistoryService.go
@@ -0,0 +1,71 @@
+package history
+
+import (
+	"github.com/devtron-labs/devtron/pkg/pipeline/bean"
+	"github.com/devtron-labs/devtron/pkg/pipeline/history/repository"
+	"github.com/devtron-labs/devtron/pkg/sql"
+	"go.uber.org/zap"
+)
+
+type CiTemplateHistoryService interface {
+	SaveHistory(material *bean.CiTemplateBean, trigger string) error
+}
+
+type CiTemplateHistoryServiceImpl struct {
+	CiTemplateHistoryRepository repository.CiTemplateHistoryRepository
+	logger                      *zap.SugaredLogger
+}
+
+func NewCiTemplateHistoryServiceImpl(CiTemplateHistoryRepository repository.CiTemplateHistoryRepository,
+	logger *zap.SugaredLogger) *CiTemplateHistoryServiceImpl {
+
+	return &CiTemplateHistoryServiceImpl{
+		CiTemplateHistoryRepository: CiTemplateHistoryRepository,
+		logger:                      logger,
+	}
+}
+
+func (impl CiTemplateHistoryServiceImpl) SaveHistory(ciTemplateBean *bean.CiTemplateBean, trigger string) error {
+
+	ciTemplate := ciTemplateBean.CiTemplate
+	ciBuildConfig := ciTemplateBean.CiBuildConfig
+
+	ciTemplateId := 0
+	ciTemplateOverrideId := 0
+
+	ciBuildConfigDbEntity, err := bean.ConvertBuildConfigBeanToDbEntity(ciTemplateId, ciTemplateOverrideId, ciBuildConfig, ciTemplateBean.UserId)
+
+	materialHistory := &repository.CiTemplateHistory{
+		CiTemplateId:       ciTemplate.Id,
+		AppId:              ciTemplate.AppId,
+		DockerRegistryId:   ciTemplate.DockerRegistryId,
+		DockerRepository:   ciTemplate.DockerRepository,
+		DockerfilePath:     ciTemplate.DockerfilePath, //in
+		Args:               ciTemplate.Args,
+		TargetPlatform:     ciTemplate.TargetPlatform,
+		BeforeDockerBuild:  ciTemplate.BeforeDockerBuild,
+		AfterDockerBuild:   ciTemplate.AfterDockerBuild,
+		TemplateName:       ciTemplate.TemplateName,
+		Version:            ciTemplate.Version,
+		Active:             ciTemplate.Active,
+		GitMaterialId:      ciTemplate.GitMaterialId,
+		DockerBuildOptions: ciTemplate.DockerBuildOptions,
+		App:                ciTemplate.App,
+		DockerRegistry:     ciTemplate.DockerRegistry,
+		CiBuildConfigId:    ciBuildConfigDbEntity.Id,
+		BuildMetaDataType:  ciBuildConfigDbEntity.Type,
+		BuildMetadata:      ciBuildConfigDbEntity.BuildMetadata,
+		Trigger:            trigger,
+		AuditLog:           sql.AuditLog{CreatedOn: ciTemplate.CreatedOn, CreatedBy: ciTemplate.CreatedBy, UpdatedBy: ciTemplate.UpdatedBy, UpdatedOn: ciTemplate.UpdatedOn},
+	}
+
+	err = impl.CiTemplateHistoryRepository.Save(materialHistory)
+
+	if err != nil {
+		impl.logger.Errorw("unable to save history for ci template repository", "error", err)
+		return err
+	}
+
+	return nil
+
+}
diff --git a/pkg/pipeline/history/repository/CiPipelineHistoryRepository.go b/pkg/pipeline/history/repository/CiPipelineHistoryRepository.go
new file mode 100644
index 000000000..c9bbea520
--- /dev/null
+++ b/pkg/pipeline/history/repository/CiPipelineHistoryRepository.go
@@ -0,0 +1,102 @@
+package repository
+
+import (
+	"github.com/devtron-labs/devtron/pkg/bean"
+	"github.com/devtron-labs/devtron/pkg/sql"
+	"github.com/go-pg/pg"
+	"go.uber.org/zap"
+)
+
+type CiPipelineTemplateOverrideHistoryDTO struct {
+	DockerRegistryId      string `json:"docker_registry_id"`
+	DockerRepository      string `json:"docker_repository"`
+	DockerfilePath        string `json:"dockerfile_path"`
+	Active                bool   `json:"active,notnull"`
+	CiBuildConfigId       int    `json:"ci_build_config_id"`
+	BuildMetaDataType     string `json:"build_meta_data_type"`
+	BuildMetadata         string `json:"build_metadata"`
+	IsCiTemplateOverriden bool   `json:"is_ci_template_overriden"`
+	sql.AuditLog
+}
+
+type CiPipelineMaterialHistoryDTO struct {
+	tableName     struct{} `json:"ci_pipeline_material"`
+	Id            int      `json:"id"`
+	GitMaterialId int      `json:"git_material_id"` //id stored in db GitMaterial( foreign key)
+	CiPipelineId  int      `json:"ci_pipeline_id"`
+	Path          string   `json:"path"` // defaults to root of git repo
+	//depricated was used in gocd remove this
+	CheckoutPath string          `json:"checkout_path"` //path where code will be checked out for single source `./` default for multiSource configured by user
+	Type         bean.SourceType `json:"type"`
+	Value        string          `json:"value"`
+	ScmId        string          `json:"scm_id"`      //id of gocd object
+	ScmName      string          `json:"scm_name"`    //gocd scm name
+	ScmVersion   string          `json:"scm_version"` //gocd scm version
+	Active       bool            `json:"active,notnull"`
+	Regex        string          `json:"regex"`
+	GitTag       string          `json:"-"`
+	sql.AuditLog
+}
+
+//type CiPipelineMaterialHistoryDTO struct {
+//	PipelineMaterialId string `sql:"ci_material_id"`
+//	GitMaterialId      int    `sql:"git_material_id"` //id stored in db GitMaterial( foreign key)
+//	Path               string `sql:"path"`            // defaults to root of git repo
+//	//depricated was used in gocd remove this
+//	CheckoutPath string          `sql:"checkout_path"` //path where code will be checked out for single source `./` default for multiSource configured by user
+//	Type         bean.SourceType `sql:"type"`
+//	Value        string          `sql:"value"`
+//	ScmId        string          `sql:"scm_id"`      //id of gocd object
+//	ScmName      string          `sql:"scm_name"`    //gocd scm name
+//	ScmVersion   string          `sql:"scm_version"` //gocd scm version
+//	Regex        string          `json:"regex"`
+//	GitTag       string          `sql:"-"`
+//	Active       bool   		 `sql:"active,notnull"`
+//	sql.AuditLog
+//}
+
+type CiPipelineHistory struct {
+	tableName                 struct{} `sql:"ci_pipeline_history" pg:",discard_unknown_columns"`
+	Id                        int      `sql:"id,pk"`
+	CiPipelineId              int      `sql:"ci_pipeline_id"`
+	CiTemplateOverrideHistory string   `sql:"ci_template_override_history"`
+	CiPipelineMaterialHistory string   `sql:"ci_pipeline_material_history"`
+	Trigger                   string   `sql:"trigger"`
+	ScanEnabled               bool     `sql:"scan_enabled,notnull"`
+	Manual                    bool     `sql:"manual,notnull"`
+}
+
+const (
+	TRIGGER_ADD    = "add"
+	TRIGGER_UPDATE = "update"
+	TRIGGER_DELETE = "delete"
+)
+
+type CiPipelineHistoryRepository interface {
+	Save(ciPipelineHistory *CiPipelineHistory) error
+}
+
+type CiPipelineHistoryRepositoryImpl struct {
+	dbConnection *pg.DB
+	logger       *zap.SugaredLogger
+}
+
+func NewCiPipelineHistoryRepositoryImpl(dbConnection *pg.DB, logger *zap.SugaredLogger) *CiPipelineHistoryRepositoryImpl {
+
+	return &CiPipelineHistoryRepositoryImpl{
+		dbConnection: dbConnection,
+		logger:       logger,
+	}
+}
+
+func (impl *CiPipelineHistoryRepositoryImpl) Save(CiPipelineHistory *CiPipelineHistory) error {
+
+	err := impl.dbConnection.Insert(CiPipelineHistory)
+
+	if err != nil {
+		impl.logger.Errorw("error in saving history for ci pipeline")
+		return err
+	}
+
+	return nil
+}
diff --git a/pkg/pipeline/history/repository/GitMaterialHistoryRepository.go b/pkg/pipeline/history/repository/GitMaterialHistoryRepository.go
new file mode 100644
index 000000000..cc3cb22c9
--- /dev/null
+++ b/pkg/pipeline/history/repository/GitMaterialHistoryRepository.go
@@ -0,0 +1,53 @@
+package repository
+
+import (
+	"github.com/devtron-labs/devtron/pkg/sql"
+	"github.com/go-pg/pg"
+)
+
+type GitMaterialHistory struct {
+	tableName       struct{} `sql:"git_material_history" pg:",discard_unknown_columns"`
+	Id              int      `sql:"id,pk"`
+	GitMaterialId   int      `sql:"git_material_id"`
+	AppId           int      `sql:"app_id,notnull"`
+	GitProviderId   int      `sql:"git_provider_id,notnull"`
+	Active          bool     `sql:"active,notnull"`
+	Url             string   `sql:"url,omitempty"`
+	Name            string   `sql:"name, omitempty"`
+	CheckoutPath    string   `sql:"checkout_path, omitempty"`
+	FetchSubmodules bool     `sql:"fetch_submodules,notnull"`
+	sql.AuditLog
+}
+
+type GitMaterialHistoryRepository interface {
+	SaveGitMaterialHistory(material *GitMaterialHistory) error
+	SaveDeleteMaterialHistory(materials []*GitMaterialHistory) error
+}
+
+type GitMaterialHistoryRepositoryImpl struct {
+	dbConnection *pg.DB
+}
+
+func NewGitMaterialHistoryRepositoyImpl(dbConnection *pg.DB) *GitMaterialHistoryRepositoryImpl {
+	return &GitMaterialHistoryRepositoryImpl{
+		dbConnection: dbConnection,
+	}
+}
+
+func (repo GitMaterialHistoryRepositoryImpl) SaveGitMaterialHistory(material *GitMaterialHistory) error {
+	return repo.dbConnection.Insert(material)
+}
+
+func (repo GitMaterialHistoryRepositoryImpl) SaveDeleteMaterialHistory(materials []*GitMaterialHistory) error {
+
+	err := repo.dbConnection.RunInTransaction(func(tx *pg.Tx) error {
+		for _, material := range materials {
+			_, err := tx.Model(material).WherePK().Insert()
+			if err != nil {
+				return err
+			}
+		}
+		return nil
+	})
+	return err
+}
diff --git a/pkg/pipeline/history/repository/ciTemplateHistoryRepository.go b/pkg/pipeline/history/repository/ciTemplateHistoryRepository.go
new file mode 100644
index 000000000..07f53b367
--- /dev/null
+++ b/pkg/pipeline/history/repository/ciTemplateHistoryRepository.go
@@ -0,0 +1,64 @@
+package repository
+
+import (
+	"github.com/devtron-labs/devtron/internal/sql/repository/app"
+	repository2 "github.com/devtron-labs/devtron/internal/sql/repository/dockerRegistry"
+	"github.com/devtron-labs/devtron/pkg/sql"
+	"github.com/go-pg/pg"
+	"go.uber.org/zap"
+)
+
+type CiTemplateHistory struct {
+	tableName          struct{} `sql:"ci_template_history" pg:",discard_unknown_columns"`
+	Id                 int      `sql:"id,pk"`
+	CiTemplateId       int      `sql:"ci_template_id"`
+	AppId              int      `sql:"app_id"`             //foreign key of app
+	DockerRegistryId   string   `sql:"docker_registry_id"` //foreign key of registry
+	DockerRepository   string   `sql:"docker_repository"`
+	DockerfilePath     string   `sql:"dockerfile_path"`
+	Args               string   `sql:"args"` //json string format of map[string]string
+	TargetPlatform     string   `sql:"target_platform,notnull"`
+	BeforeDockerBuild  string   `sql:"before_docker_build"` //json string  format of []*Task
+	AfterDockerBuild   string   `sql:"after_docker_build"`  //json string  format of []*Task
+	TemplateName       string   `sql:"template_name"`
+	Version            string   `sql:"version"` //gocd etage
+	Active             bool     `sql:"active,notnull"`
+	GitMaterialId      int      `sql:"git_material_id"`
+	DockerBuildOptions string   `sql:"docker_build_options"` //json string format of map[string]string
+	CiBuildConfigId    int      `sql:"ci_build_config_id"`
+	BuildMetaDataType  string   `sql:"build_meta_data_type"`
+	BuildMetadata      string   `sql:"build_metadata"`
+	Trigger            string   `sql:"trigger"`
+	sql.AuditLog
+	App            *app.App
+	DockerRegistry *repository2.DockerArtifactStore
+}
+
+type CiTemplateHistoryRepository interface {
+	Save(material *CiTemplateHistory) error
+}
+
+type CiTemplateHistoryRepositoryImpl struct {
+	dbConnection *pg.DB
+	logger       *zap.SugaredLogger
+}
+
+func NewCiTemplateHistoryRepositoryImpl(dbConnection *pg.DB, logger *zap.SugaredLogger) *CiTemplateHistoryRepositoryImpl {
+	return &CiTemplateHistoryRepositoryImpl{
+		dbConnection: dbConnection,
+		logger:       logger,
+	}
+}
+
+func (impl CiTemplateHistoryRepositoryImpl) Save(material *CiTemplateHistory) error {
+
+	err := impl.dbConnection.Insert(material)
+
+	if err != nil {
+		impl.logger.Errorw("error in saving history for ci template history")
+		return err
+	}
+
+	return nil
+
+}
diff --git a/pkg/pipeline/history/repository/mocks/CiPipelineHistoryRepository.go b/pkg/pipeline/history/repository/mocks/CiPipelineHistoryRepository.go
new file mode 100644
index 000000000..3bd9880cc
--- /dev/null
+++ b/pkg/pipeline/history/repository/mocks/CiPipelineHistoryRepository.go
@@ -0,0 +1,42 @@
+// Code generated by mockery v2.14.0. DO NOT EDIT.
+
+package mocks
+
+import (
+	repository "github.com/devtron-labs/devtron/pkg/pipeline/history/repository"
+	mock "github.com/stretchr/testify/mock"
+)
+
+// CiPipelineHistoryRepository is an autogenerated mock type for the CiPipelineHistoryRepository type
+type CiPipelineHistoryRepository struct {
+	mock.Mock
+}
+
+// Save provides a mock function with given fields: ciPipelineHistory
+func (_m *CiPipelineHistoryRepository) Save(ciPipelineHistory *repository.CiPipelineHistory) error {
+	ret := _m.Called(ciPipelineHistory)
+
+	var r0 error
+	if rf, ok := ret.Get(0).(func(*repository.CiPipelineHistory) error); ok {
+		r0 = rf(ciPipelineHistory)
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+type mockConstructorTestingTNewCiPipelineHistoryRepository interface {
+	mock.TestingT
+	Cleanup(func())
+}
+
+// NewCiPipelineHistoryRepository creates a new instance of CiPipelineHistoryRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+func NewCiPipelineHistoryRepository(t mockConstructorTestingTNewCiPipelineHistoryRepository) *CiPipelineHistoryRepository {
+	mock := &CiPipelineHistoryRepository{}
+	mock.Mock.Test(t)
+
+	t.Cleanup(func() { mock.AssertExpectations(t) })
+
+	return mock
+}
diff --git a/pkg/pipeline/history/repository/mocks/CiTemplateHistoryRepository.go b/pkg/pipeline/history/repository/mocks/CiTemplateHistoryRepository.go
new file mode 100644
index 000000000..709c0ea37
--- /dev/null
+++ b/pkg/pipeline/history/repository/mocks/CiTemplateHistoryRepository.go
@@ -0,0 +1,42 @@
+// Code generated by mockery v2.14.0. DO NOT EDIT.
+
+package mocks
+
+import (
+	repository "github.com/devtron-labs/devtron/pkg/pipeline/history/repository"
+	mock "github.com/stretchr/testify/mock"
+)
+
+// CiTemplateHistoryRepository is an autogenerated mock type for the CiTemplateHistoryRepository type
+type CiTemplateHistoryRepository struct {
+	mock.Mock
+}
+
+// Save provides a mock function with given fields: material
+func (_m *CiTemplateHistoryRepository) Save(material *repository.CiTemplateHistory) error {
+	ret := _m.Called(material)
+
+	var r0 error
+	if rf, ok := ret.Get(0).(func(*repository.CiTemplateHistory) error); ok {
+		r0 = rf(material)
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+type mockConstructorTestingTNewCiTemplateHistoryRepository interface {
+	mock.TestingT
+	Cleanup(func())
+}
+
+// NewCiTemplateHistoryRepository creates a new instance of CiTemplateHistoryRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+func NewCiTemplateHistoryRepository(t mockConstructorTestingTNewCiTemplateHistoryRepository) *CiTemplateHistoryRepository {
+	mock := &CiTemplateHistoryRepository{}
+	mock.Mock.Test(t)
+
+	t.Cleanup(func() { mock.AssertExpectations(t) })
+
+	return mock
+}
diff --git a/pkg/pipeline/history/repository/mocks/GitMaterialHistoryRepository.go b/pkg/pipeline/history/repository/mocks/GitMaterialHistoryRepository.go
new file mode 100644
index 000000000..63eee2264
--- /dev/null
+++ b/pkg/pipeline/history/repository/mocks/GitMaterialHistoryRepository.go
@@ -0,0 +1,56 @@
+// Code generated by mockery v2.14.0. DO NOT EDIT.
+
+package mocks
+
+import (
+	repository "github.com/devtron-labs/devtron/pkg/pipeline/history/repository"
+	mock "github.com/stretchr/testify/mock"
+)
+
+// GitMaterialHistoryRepository is an autogenerated mock type for the GitMaterialHistoryRepository type
+type GitMaterialHistoryRepository struct {
+	mock.Mock
+}
+
+// SaveDeleteMaterialHistory provides a mock function with given fields: materials
+func (_m *GitMaterialHistoryRepository) SaveDeleteMaterialHistory(materials []*repository.GitMaterialHistory) error {
+	ret := _m.Called(materials)
+
+	var r0 error
+	if rf, ok := ret.Get(0).(func([]*repository.GitMaterialHistory) error); ok {
+		r0 = rf(materials)
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+// SaveGitMaterialHistory provides a mock function with given fields: material
+func (_m *GitMaterialHistoryRepository) SaveGitMaterialHistory(material *repository.GitMaterialHistory) error {
+	ret := _m.Called(material)
+
+	var r0 error
+	if rf, ok := ret.Get(0).(func(*repository.GitMaterialHistory) error); ok {
+		r0 = rf(material)
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+type mockConstructorTestingTNewGitMaterialHistoryRepository interface {
+	mock.TestingT
+	Cleanup(func())
+}
+
+// NewGitMaterialHistoryRepository creates a new instance of GitMaterialHistoryRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+func NewGitMaterialHistoryRepository(t mockConstructorTestingTNewGitMaterialHistoryRepository) *GitMaterialHistoryRepository {
+	mock := &GitMaterialHistoryRepository{}
+	mock.Mock.Test(t)
+
+	t.Cleanup(func() { mock.AssertExpectations(t) })
+
+	return mock
+}
diff --git a/scripts/sql/95_create_ci_build_history.down.sql b/scripts/sql/95_create_ci_build_history.down.sql
new file mode 100644
index 000000000..423cc3d18
--- /dev/null
+++ b/scripts/sql/95_create_ci_build_history.down.sql
@@ -0,0 +1,3 @@
+DROP TABLE IF EXISTS "public"."git_material_history";
+DROP TABLE IF EXISTS "public"."ci_template_history";
+DROP TABLE IF EXISTS "public"."ci_pipeline_history";
\ No newline at end of file
diff --git a/scripts/sql/95_create_ci_build_history.up.sql b/scripts/sql/95_create_ci_build_history.up.sql
new file mode 100644
index 000000000..687ba9278
--- /dev/null
+++ b/scripts/sql/95_create_ci_build_history.up.sql
@@ -0,0 +1,86 @@
+CREATE SEQUENCE IF NOT EXISTS id_seq_git_material_history;
+
+
+CREATE TABLE public.git_material_history (
+     "id" integer  NOT NULL DEFAULT nextval('id_seq_git_material_history'::regclass),
+     "app_id" integer,
+     "git_provider_id" integer,
+     "git_material_id" integer,
+     "active" boolean NOT NULL,
+     "name" character varying(250),
+     "url" character varying(250),
+     "created_on" timestamp with time zone NOT NULL,
+     "created_by" integer NOT NULL,
+     "updated_on" timestamp with time zone NOT NULL,
+     "updated_by" integer NOT NULL,
+     "checkout_path" character varying(250),
+     "fetch_submodules" boolean NOT NULL,
+     PRIMARY KEY ("id"),
+     CONSTRAINT git_material_history_git_material_id_fkey
+         FOREIGN KEY(git_material_id)
+             REFERENCES public.git_material(id)
+);
+
+ALTER TABLE public.git_material_history OWNER TO postgres;
+
+
+CREATE SEQUENCE IF NOT EXISTS id_seq_ci_template_history;
+
+CREATE TABLE public.ci_template_history (
+    id integer NOT NULL DEFAULT nextval('id_seq_ci_template_history'::regclass),
+    ci_template_id integer,
+    app_id integer,
+    docker_registry_id character varying(250),
+    docker_repository character varying(250),
+    dockerfile_path character varying(250),
+    args text,
+    before_docker_build text,
+    after_docker_build text,
+    template_name character varying(250),
+    version character varying(250),
+    target_platform VARCHAR(1000) NOT NULL DEFAULT '',
+    docker_build_options text,
+    active boolean,
+    created_on timestamp with time zone NOT NULL,
+    created_by integer NOT NULL,
+    updated_on timestamp with time zone NOT NULL,
+    updated_by integer NOT NULL,
+    git_material_id integer,
+    ci_build_config_id   integer,
+    build_meta_data_type  varchar(100),
+    build_metadata       text,
+    trigger character varying(100),
+    PRIMARY KEY ("id"),
+    CONSTRAINT ci_template_history_ci_template_id_fkey
+        FOREIGN KEY (ci_template_id)
+            REFERENCES public.ci_template(id),
+    CONSTRAINT ci_template_history_docker_registry_id_fkey
+        FOREIGN KEY(docker_registry_id)
+            REFERENCES public.docker_artifact_store(id),
+    CONSTRAINT ci_template_history_app_id_fkey
+        FOREIGN KEY(app_id)
+            REFERENCES public.app(id),
+    CONSTRAINT ci_template_git_material_history_id_fkey
+        FOREIGN KEY(git_material_id)
+            REFERENCES public.git_material(id)
+);
+
+
+ALTER TABLE public.ci_template OWNER TO postgres;
+
+CREATE SEQUENCE IF NOT EXISTS id_seq_ci_pipeline_history;
+
+CREATE TABLE public.ci_pipeline_history(
+   id integer NOT NULL default nextval('id_seq_ci_pipeline_history'::regclass),
+   ci_pipeline_id integer,
+   ci_template_override_history text,
+   ci_pipeline_material_history text,
+   scan_enabled boolean,
+   manual boolean,
+   trigger character varying(100),
+   PRIMARY KEY ("id"),
+   CONSTRAINT ci_pipeline_history_ci_pipeline_id_fk
+       FOREIGN KEY (ci_pipeline_id)
+           REFERENCES public.ci_pipeline(id)
+);
+
diff --git a/wire_gen.go b/wire_gen.go
index 77226b7d5..cc207508a 100644
--- a/wire_gen.go
+++ b/wire_gen.go
@@ -1,7 +1,8 @@
 // Code generated by Wire. DO NOT EDIT.
 
 //go:generate go run github.com/google/wire/cmd/wire
-//+build !wireinject
+//go:build !wireinject
+// +build !wireinject
 
 package main
 
@@ -354,17 +355,23 @@ func InitializeApp() (*App, error) {
 	globalPluginRepositoryImpl := repository9.NewGlobalPluginRepository(sugaredLogger, db)
 	pipelineStageServiceImpl := pipeline.NewPipelineStageService(sugaredLogger, pipelineStageRepositoryImpl, globalPluginRepositoryImpl)
 	ciTemplateOverrideRepositoryImpl := pipelineConfig.NewCiTemplateOverrideRepositoryImpl(db, sugaredLogger)
+	gitMaterialHistoryRepositoryImpl := repository6.NewGitMaterialHistoryRepositoyImpl(db)
+	gitMaterialHistoryServiceImpl := history.NewGitMaterialHistoryServiceImpl(gitMaterialHistoryRepositoryImpl, sugaredLogger)
+	ciPipelineHistoryRepositoryImpl := repository6.NewCiPipelineHistoryRepositoryImpl(db, sugaredLogger)
+	ciPipelineHistoryServiceImpl := history.NewCiPipelineHistoryServiceImpl(ciPipelineHistoryRepositoryImpl, sugaredLogger)
 	ciBuildConfigRepositoryImpl := pipelineConfig.NewCiBuildConfigRepositoryImpl(db, sugaredLogger)
 	ciBuildConfigServiceImpl := pipeline.NewCiBuildConfigServiceImpl(sugaredLogger, ciBuildConfigRepositoryImpl)
 	ciTemplateRepositoryImpl := pipelineConfig.NewCiTemplateRepositoryImpl(db, sugaredLogger)
 	ciTemplateServiceImpl := pipeline.NewCiTemplateServiceImpl(sugaredLogger, ciBuildConfigServiceImpl, ciTemplateRepositoryImpl, ciTemplateOverrideRepositoryImpl)
-	dbPipelineOrchestratorImpl := pipeline.NewDbPipelineOrchestrator(appRepositoryImpl, sugaredLogger, materialRepositoryImpl, pipelineRepositoryImpl, ciPipelineRepositoryImpl, ciPipelineMaterialRepositoryImpl, gitSensorClientImpl, ciConfig, appWorkflowRepositoryImpl, environmentRepositoryImpl, attributesServiceImpl, appListingRepositoryImpl, appCrudOperationServiceImpl, userAuthServiceImpl, prePostCdScriptHistoryServiceImpl, prePostCiScriptHistoryServiceImpl, pipelineStageServiceImpl, ciTemplateOverrideRepositoryImpl, ciTemplateServiceImpl)
+	dbPipelineOrchestratorImpl := pipeline.NewDbPipelineOrchestrator(appRepositoryImpl, sugaredLogger, materialRepositoryImpl, pipelineRepositoryImpl, ciPipelineRepositoryImpl, ciPipelineMaterialRepositoryImpl, gitSensorClientImpl, ciConfig, appWorkflowRepositoryImpl, environmentRepositoryImpl, attributesServiceImpl, appListingRepositoryImpl, appCrudOperationServiceImpl, userAuthServiceImpl, prePostCdScriptHistoryServiceImpl, prePostCiScriptHistoryServiceImpl, pipelineStageServiceImpl, ciTemplateOverrideRepositoryImpl, gitMaterialHistoryServiceImpl, ciPipelineHistoryServiceImpl, ciTemplateServiceImpl)
 	propertiesConfigServiceImpl := pipeline.NewPropertiesConfigServiceImpl(sugaredLogger, envConfigOverrideRepositoryImpl, chartRepositoryImpl, utilMergeUtil, environmentRepositoryImpl, dbPipelineOrchestratorImpl, applicationServiceClientImpl, envLevelAppMetricsRepositoryImpl, appLevelMetricsRepositoryImpl, deploymentTemplateHistoryServiceImpl)
 	ecrConfig, err := pipeline.GetEcrConfig()
 	if err != nil {
 		return nil, err
 	}
-	pipelineBuilderImpl := pipeline.NewPipelineBuilderImpl(sugaredLogger, dbPipelineOrchestratorImpl, dockerArtifactStoreRepositoryImpl, materialRepositoryImpl, appRepositoryImpl, pipelineRepositoryImpl, propertiesConfigServiceImpl, ciTemplateRepositoryImpl, ciPipelineRepositoryImpl, applicationServiceClientImpl, chartRepositoryImpl, ciArtifactRepositoryImpl, ecrConfig, envConfigOverrideRepositoryImpl, environmentRepositoryImpl, pipelineConfigRepositoryImpl, utilMergeUtil, appWorkflowRepositoryImpl, ciConfig, cdWorkflowRepositoryImpl, appServiceImpl, imageScanResultRepositoryImpl, argoK8sClientImpl, gitFactory, attributesServiceImpl, acdAuthConfig, gitOpsConfigRepositoryImpl, pipelineStrategyHistoryServiceImpl, prePostCiScriptHistoryServiceImpl, prePostCdScriptHistoryServiceImpl, deploymentTemplateHistoryServiceImpl, appLevelMetricsRepositoryImpl, pipelineStageServiceImpl, chartRefRepositoryImpl, chartTemplateServiceImpl, chartServiceImpl, helmAppServiceImpl, deploymentGroupRepositoryImpl, ciPipelineMaterialRepositoryImpl, userServiceImpl, ciTemplateOverrideRepositoryImpl, ciTemplateServiceImpl)
+	ciTemplateHistoryRepositoryImpl := repository6.NewCiTemplateHistoryRepositoryImpl(db, sugaredLogger)
+	ciTemplateHistoryServiceImpl := history.NewCiTemplateHistoryServiceImpl(ciTemplateHistoryRepositoryImpl, sugaredLogger)
+	pipelineBuilderImpl := pipeline.NewPipelineBuilderImpl(sugaredLogger, dbPipelineOrchestratorImpl, dockerArtifactStoreRepositoryImpl, materialRepositoryImpl, appRepositoryImpl, pipelineRepositoryImpl, propertiesConfigServiceImpl, ciTemplateRepositoryImpl, ciPipelineRepositoryImpl, applicationServiceClientImpl, chartRepositoryImpl, ciArtifactRepositoryImpl, ecrConfig, envConfigOverrideRepositoryImpl, environmentRepositoryImpl, pipelineConfigRepositoryImpl, utilMergeUtil, appWorkflowRepositoryImpl, ciConfig, cdWorkflowRepositoryImpl, appServiceImpl, imageScanResultRepositoryImpl, argoK8sClientImpl, gitFactory, attributesServiceImpl, acdAuthConfig, gitOpsConfigRepositoryImpl, pipelineStrategyHistoryServiceImpl, prePostCiScriptHistoryServiceImpl, prePostCdScriptHistoryServiceImpl, deploymentTemplateHistoryServiceImpl, appLevelMetricsRepositoryImpl, pipelineStageServiceImpl, chartRefRepositoryImpl, chartTemplateServiceImpl, chartServiceImpl, helmAppServiceImpl, deploymentGroupRepositoryImpl, ciPipelineMaterialRepositoryImpl, userServiceImpl, ciTemplateServiceImpl, ciTemplateOverrideRepositoryImpl, gitMaterialHistoryServiceImpl, ciTemplateHistoryServiceImpl, ciPipelineHistoryServiceImpl)
 	dbMigrationServiceImpl := pipeline.NewDbMogrationService(sugaredLogger, dbMigrationConfigRepositoryImpl)
 	globalCMCSRepositoryImpl := repository.NewGlobalCMCSRepositoryImpl(sugaredLogger, db)
 	globalCMCSServiceImpl := pipeline.NewGlobalCMCSServiceImpl(sugaredLogger, globalCMCSRepositoryImpl)


Test patch:
diff --git a/pkg/pipeline/history/CiPipelineHistoryService_test.go b/pkg/pipeline/history/CiPipelineHistoryService_test.go
new file mode 100644
index 000000000..903981515
--- /dev/null
+++ b/pkg/pipeline/history/CiPipelineHistoryService_test.go
@@ -0,0 +1,120 @@
+package history
+
+import (
+	"encoding/json"
+	"github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig"
+	"github.com/devtron-labs/devtron/internal/util"
+	bean2 "github.com/devtron-labs/devtron/pkg/pipeline/bean"
+	"github.com/devtron-labs/devtron/pkg/pipeline/history/repository"
+	"github.com/devtron-labs/devtron/pkg/pipeline/history/repository/mocks"
+	"github.com/devtron-labs/devtron/pkg/sql"
+	"github.com/stretchr/testify/assert"
+	"testing"
+)
+
+func TestCiPipelineHistoryService(t *testing.T) {
+
+	t.Run("SaveHistory", func(t *testing.T) {
+
+		sugaredLogger, err := util.NewSugardLogger()
+		assert.Nil(t, err)
+
+		mockedCiPipelineHistoryRepository := mocks.NewCiPipelineHistoryRepository(t)
+
+		CiPipelineHistoryServiceImpl := NewCiPipelineHistoryServiceImpl(mockedCiPipelineHistoryRepository, sugaredLogger)
+
+		PipelineObject := pipelineConfig.CiPipeline{
+			Id:                       5,
+			AppId:                    2,
+			App:                      nil,
+			CiTemplateId:             3,
+			DockerArgs:               "",
+			Name:                     "",
+			Version:                  "",
+			Active:                   false,
+			Deleted:                  false,
+			IsManual:                 false,
+			IsExternal:               false,
+			ParentCiPipeline:         0,
+			ScanEnabled:              false,
+			IsDockerConfigOverridden: true,
+			AuditLog:                 sql.AuditLog{},
+		}
+
+		PipelineMaterialsObject := []*pipelineConfig.CiPipelineMaterial{&pipelineConfig.CiPipelineMaterial{
+			Id:            0,
+			GitMaterialId: 22,
+			CiPipelineId:  5,
+			Path:          "",
+			CheckoutPath:  "",
+			Type:          "",
+			Value:         "",
+			ScmId:         "",
+			ScmName:       "",
+			ScmVersion:    "",
+			Active:        false,
+			Regex:         "",
+			GitTag:        "",
+			AuditLog:      sql.AuditLog{}},
+		}
+
+		CiTemplateObject := bean2.CiTemplateBean{
+			CiTemplateOverride: &pipelineConfig.CiTemplateOverride{
+				Id:               0,
+				CiPipelineId:     5,
+				DockerRegistryId: "prakash",
+				DockerRepository: "prakash1001/sams-repository-3",
+				DockerfilePath:   "",
+				GitMaterialId:    22,
+				Active:           true,
+				CiBuildConfigId:  20,
+				AuditLog:         sql.AuditLog{},
+				GitMaterial:      nil,
+				DockerRegistry:   nil,
+				CiBuildConfig:    nil,
+			},
+			CiBuildConfig: &bean2.CiBuildConfigBean{
+				Id:                20,
+				GitMaterialId:     22,
+				CiBuildType:       "self-dockerfile-build",
+				DockerBuildConfig: &bean2.DockerBuildConfig{DockerfileContent: ""},
+				BuildPackConfig:   nil,
+			},
+			UserId: 0,
+		}
+
+		MockedCiPipelineMaterialJson, _ := json.Marshal(PipelineMaterialsObject)
+
+		MockedCiTemplateOverrideHistory, _ := json.Marshal(
+			repository.CiPipelineTemplateOverrideHistoryDTO{
+				DockerRegistryId:      "prakash",
+				DockerRepository:      "prakash1001/sams-repository-3",
+				DockerfilePath:        "",
+				Active:                true,
+				CiBuildConfigId:       20,
+				BuildMetaDataType:     "self-dockerfile-build",
+				BuildMetadata:         "{\"dockerfileContent\":\"\"}",
+				IsCiTemplateOverriden: true,
+				AuditLog:              sql.AuditLog{},
+			},
+		)
+
+		mockedCiPipelineHistoryObject := repository.CiPipelineHistory{
+			Id:                        0,
+			CiPipelineId:              5,
+			CiTemplateOverrideHistory: string(MockedCiTemplateOverrideHistory),
+			CiPipelineMaterialHistory: string(MockedCiPipelineMaterialJson),
+			Trigger:                   "update",
+			ScanEnabled:               false,
+			Manual:                    false,
+		}
+
+		mockedCiPipelineHistoryRepository.On("Save", &mockedCiPipelineHistoryObject).Return(nil)
+
+		err = CiPipelineHistoryServiceImpl.SaveHistory(&PipelineObject, PipelineMaterialsObject, &CiTemplateObject, "update")
+
+		assert.Nil(t, err)
+
+	})
+
+}
diff --git a/pkg/pipeline/history/GitMaterialHistoryService_test.go b/pkg/pipeline/history/GitMaterialHistoryService_test.go
new file mode 100644
index 000000000..d0e1fd247
--- /dev/null
+++ b/pkg/pipeline/history/GitMaterialHistoryService_test.go
@@ -0,0 +1,93 @@
+package history
+
+import (
+	"github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig"
+	"github.com/devtron-labs/devtron/internal/util"
+	"github.com/devtron-labs/devtron/pkg/pipeline/history/repository"
+	"github.com/devtron-labs/devtron/pkg/pipeline/history/repository/mocks"
+	"github.com/devtron-labs/devtron/pkg/sql"
+	"github.com/stretchr/testify/assert"
+	"testing"
+)
+
+func TestGitMaterialService(t *testing.T) {
+
+	t.Run("Save", func(t *testing.T) {
+
+		sugaredLogger, err := util.NewSugardLogger()
+		assert.Nil(t, err)
+
+		mockedGitMaterialHistoryRepository := mocks.NewGitMaterialHistoryRepository(t)
+
+		GitHistoryServiceImpl := NewGitMaterialHistoryServiceImpl(mockedGitMaterialHistoryRepository, sugaredLogger)
+
+		GitMaterial := &pipelineConfig.GitMaterial{
+			Id:              1,
+			Url:             "https://github.com/devtron-labs/ci-runner",
+			AppId:           49,
+			Name:            "1-devtron-test",
+			Active:          true,
+			CheckoutPath:    "./",
+			FetchSubmodules: false,
+			AuditLog:        sql.AuditLog{},
+		}
+
+		mockedMaterial := &repository.GitMaterialHistory{
+			GitMaterialId:   1,
+			Url:             "https://github.com/devtron-labs/ci-runner",
+			AppId:           49,
+			Name:            "1-devtron-test",
+			Active:          true,
+			CheckoutPath:    "./",
+			FetchSubmodules: false,
+			AuditLog:        sql.AuditLog{},
+		}
+
+		mockedGitMaterialHistoryRepository.On("SaveGitMaterialHistory", mockedMaterial).Return(nil)
+
+		err = GitHistoryServiceImpl.CreateMaterialHistory(GitMaterial)
+
+		assert.Nil(t, err)
+
+	})
+
+	t.Run("MarkMaterialDelete", func(t *testing.T) {
+
+		sugaredLogger, err := util.NewSugardLogger()
+		assert.Nil(t, err)
+
+		mockedGitMaterialHistoryRepository := mocks.NewGitMaterialHistoryRepository(t)
+
+		GitHistoryServiceImpl := NewGitMaterialHistoryServiceImpl(mockedGitMaterialHistoryRepository, sugaredLogger)
+
+		mockedMaterial := &repository.GitMaterialHistory{
+			GitMaterialId:   1,
+			Url:             "https://github.com/devtron-labs/ci-runner",
+			AppId:           49,
+			Name:            "1-devtron-test",
+			Active:          false,
+			CheckoutPath:    "./",
+			FetchSubmodules: false,
+			AuditLog:        sql.AuditLog{},
+		}
+
+		GitMaterial := &pipelineConfig.GitMaterial{
+			Id:              1,
+			Url:             "https://github.com/devtron-labs/ci-runner",
+			AppId:           49,
+			Name:            "1-devtron-test",
+			Active:          true,
+			CheckoutPath:    "./",
+			FetchSubmodules: false,
+			AuditLog:        sql.AuditLog{},
+		}
+
+		mockedGitMaterialHistoryRepository.On("SaveGitMaterialHistory", mockedMaterial).Return(nil)
+
+		err = GitHistoryServiceImpl.MarkMaterialDeletedAndCreateHistory(GitMaterial)
+
+		assert.Nil(t, err)
+
+	})
+
+}
diff --git a/pkg/pipeline/history/ciTemplateHistoryService_test.go b/pkg/pipeline/history/ciTemplateHistoryService_test.go
new file mode 100644
index 000000000..138402ecd
--- /dev/null
+++ b/pkg/pipeline/history/ciTemplateHistoryService_test.go
@@ -0,0 +1,95 @@
+package history
+
+import (
+	"github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig"
+	"github.com/devtron-labs/devtron/internal/util"
+	bean2 "github.com/devtron-labs/devtron/pkg/pipeline/bean"
+	"github.com/devtron-labs/devtron/pkg/pipeline/history/repository"
+	"github.com/devtron-labs/devtron/pkg/pipeline/history/repository/mocks"
+	"github.com/devtron-labs/devtron/pkg/sql"
+	"github.com/stretchr/testify/assert"
+	"testing"
+)
+
+func TestCiTemplateHistoryService(t *testing.T) {
+
+	t.Run("SaveHistory", func(t *testing.T) {
+
+		sugaredLogger, err := util.NewSugardLogger()
+		assert.Nil(t, err)
+
+		mockedCiTemplateHistoryRepository := mocks.NewCiTemplateHistoryRepository(t)
+
+		CiTemplateHistoryServiceImpl := NewCiTemplateHistoryServiceImpl(mockedCiTemplateHistoryRepository, sugaredLogger)
+
+		mockedCiTemplateHistoryObject := repository.CiTemplateHistory{
+			CiTemplateId:       28,
+			AppId:              38,
+			DockerRegistryId:   "prakash",
+			DockerRepository:   "prakash1001/sams-repository-3",
+			DockerfilePath:     "",
+			Args:               "",
+			TargetPlatform:     "",
+			BeforeDockerBuild:  "",
+			AfterDockerBuild:   "",
+			TemplateName:       "",
+			Version:            "",
+			Active:             true,
+			GitMaterialId:      22,
+			DockerBuildOptions: "",
+			CiBuildConfigId:    20,
+			BuildMetaDataType:  "self-dockerfile-build",
+			BuildMetadata:      "{\"dockerfileContent\":\"\"}",
+			Trigger:            "update",
+			AuditLog:           sql.AuditLog{},
+		}
+		//dockerBuildOptions := map[string]string{}
+		//dockerBuildOptions["dockerfileRelativePath"] = "Dockerfile"
+		//dockerBuildOptions["dockerfileContent"] = ""
+		//dockerBuildOptions["dockerfileRelativePath"] = "Dockerfile"
+
+		ciServiceObject := bean2.CiTemplateBean{
+			CiTemplate: &pipelineConfig.CiTemplate{
+				Id:                 28,
+				AppId:              38,
+				DockerRegistryId:   "prakash",
+				DockerRepository:   "prakash1001/sams-repository-3",
+				DockerfilePath:     "",
+				Args:               "",
+				TargetPlatform:     "",
+				BeforeDockerBuild:  "",
+				AfterDockerBuild:   "",
+				TemplateName:       "",
+				Version:            "",
+				Active:             true,
+				GitMaterialId:      22,
+				DockerBuildOptions: "",
+				CiBuildConfigId:    20,
+				AuditLog:           sql.AuditLog{},
+				App:                nil,
+				DockerRegistry:     nil,
+				GitMaterial:        nil,
+				CiBuildConfig:      nil,
+			},
+			CiTemplateOverride: nil,
+			CiBuildConfig: &bean2.CiBuildConfigBean{
+				Id:                20,
+				GitMaterialId:     22,
+				CiBuildType:       "self-dockerfile-build",
+				DockerBuildConfig: &bean2.DockerBuildConfig{DockerfileContent: ""},
+				BuildPackConfig:   nil,
+			},
+			UserId: 0,
+		}
+
+		mockedCiTemplateHistoryRepository.On("Save", &mockedCiTemplateHistoryObject).Return(
+			nil,
+		)
+
+		err = CiTemplateHistoryServiceImpl.SaveHistory(&ciServiceObject, "update")
+
+		assert.Nil(t, err)
+
+	})
+
+}