From a158bebe03b366b6463af181b9ee6f6c2b3850a3 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Fri, 7 May 2021 06:10:43 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .../pipelines/components/graph_shared/api.js | 5 + .../namespace/package_settings/update.rb | 10 + .../types/namespace/package_settings_type.rb | 2 + app/models/namespace/package_setting.rb | 4 +- app/models/packages.rb | 2 + app/models/repository.rb | 8 +- .../package_settings/update_service.rb | 5 +- .../generic/create_package_file_service.rb | 8 + app/views/shared/snippets/_snippet.html.haml | 4 +- .../293755-generic-dupe-settings.yml | 5 + .../327414-agent-proxy-request-count.yml | 5 + ..._settings_to_namespace_package_settings.rb | 11 + ...tings_generic_duplicate_exception_regex.rb | 15 + db/schema_migrations/20210429192653 | 1 + db/schema_migrations/20210429193106 | 1 + db/structure.sql | 3 + doc/api/graphql/reference/index.md | 4 + doc/ci/yaml/README.md | 16 +- doc/development/internal_api.md | 3 +- doc/development/usage_ping/dictionary.md | 12 + .../index.md | 267 +++++++----------- lib/api/generic_packages.rb | 2 + lib/api/internal/kubernetes.rb | 16 +- .../kubernetes_agent_counter.rb | 24 +- qa/qa/page/dashboard/snippet/index.rb | 22 ++ qa/qa/resource/snippet.rb | 2 +- .../snippet/snippet_index_page_spec.rb | 82 ++++++ spec/factories/namespace_package_settings.rb | 3 + .../graph_shared/links_layer_spec.js | 14 +- .../namespace/package_settings/update_spec.rb | 12 +- .../kubernetes_agent_counter_spec.rb | 60 +++- spec/lib/gitlab/usage_data_spec.rb | 1 + spec/models/namespace/package_setting_spec.rb | 21 +- spec/models/repository_spec.rb | 63 ++++- .../namespace/package_settings/update_spec.rb | 12 +- spec/requests/api/internal/kubernetes_spec.rb | 12 +- .../package_settings/update_service_spec.rb | 11 +- .../create_package_file_service_spec.rb | 42 ++- ...espace_package_settings_shared_examples.rb | 4 + 39 files changed, 552 insertions(+), 242 deletions(-) create mode 100644 changelogs/unreleased/293755-generic-dupe-settings.yml create mode 100644 changelogs/unreleased/327414-agent-proxy-request-count.yml create mode 100644 db/migrate/20210429192653_add_generic_package_duplicate_settings_to_namespace_package_settings.rb create mode 100644 db/migrate/20210429193106_add_text_limit_to_namespace_package_settings_generic_duplicate_exception_regex.rb create mode 100644 db/schema_migrations/20210429192653 create mode 100644 db/schema_migrations/20210429193106 create mode 100644 qa/qa/specs/features/browser_ui/3_create/snippet/snippet_index_page_spec.rb diff --git a/app/assets/javascripts/pipelines/components/graph_shared/api.js b/app/assets/javascripts/pipelines/components/graph_shared/api.js index 49cd04d11e9..0fe7d9ffda3 100644 --- a/app/assets/javascripts/pipelines/components/graph_shared/api.js +++ b/app/assets/javascripts/pipelines/components/graph_shared/api.js @@ -2,6 +2,11 @@ import axios from '~/lib/utils/axios_utils'; import { reportToSentry } from '../../utils'; export const reportPerformance = (path, stats) => { + // FIXME: https://gitlab.com/gitlab-org/gitlab/-/issues/330245 + if (!path) { + return; + } + axios.post(path, stats).catch((err) => { reportToSentry('links_inner_perf', `error: ${err}`); }); diff --git a/app/graphql/mutations/namespace/package_settings/update.rb b/app/graphql/mutations/namespace/package_settings/update.rb index ca21c3418fc..75c80cfbd3e 100644 --- a/app/graphql/mutations/namespace/package_settings/update.rb +++ b/app/graphql/mutations/namespace/package_settings/update.rb @@ -25,6 +25,16 @@ module Mutations required: false, description: copy_field_description(Types::Namespace::PackageSettingsType, :maven_duplicate_exception_regex) + argument :generic_duplicates_allowed, + GraphQL::BOOLEAN_TYPE, + required: false, + description: copy_field_description(Types::Namespace::PackageSettingsType, :generic_duplicates_allowed) + + argument :generic_duplicate_exception_regex, + Types::UntrustedRegexp, + required: false, + description: copy_field_description(Types::Namespace::PackageSettingsType, :generic_duplicate_exception_regex) + field :package_settings, Types::Namespace::PackageSettingsType, null: true, diff --git a/app/graphql/types/namespace/package_settings_type.rb b/app/graphql/types/namespace/package_settings_type.rb index 0720a1cfb4b..af091515979 100644 --- a/app/graphql/types/namespace/package_settings_type.rb +++ b/app/graphql/types/namespace/package_settings_type.rb @@ -10,5 +10,7 @@ module Types field :maven_duplicates_allowed, GraphQL::BOOLEAN_TYPE, null: false, description: 'Indicates whether duplicate Maven packages are allowed for this namespace.' field :maven_duplicate_exception_regex, Types::UntrustedRegexp, null: true, description: 'When maven_duplicates_allowed is false, you can publish duplicate packages with names that match this regex. Otherwise, this setting has no effect.' + field :generic_duplicates_allowed, GraphQL::BOOLEAN_TYPE, null: false, description: 'Indicates whether duplicate generic packages are allowed for this namespace.' + field :generic_duplicate_exception_regex, Types::UntrustedRegexp, null: true, description: 'When generic_duplicates_allowed is false, you can publish duplicate packages with names that match this regex. Otherwise, this setting has no effect.' end end diff --git a/app/models/namespace/package_setting.rb b/app/models/namespace/package_setting.rb index ce0b736e9a5..881b2f3acb3 100644 --- a/app/models/namespace/package_setting.rb +++ b/app/models/namespace/package_setting.rb @@ -6,13 +6,15 @@ class Namespace::PackageSetting < ApplicationRecord PackageSettingNotImplemented = Class.new(StandardError) - PACKAGES_WITH_SETTINGS = %w[maven].freeze + PACKAGES_WITH_SETTINGS = %w[maven generic].freeze belongs_to :namespace, inverse_of: :package_setting_relation validates :namespace, presence: true validates :maven_duplicates_allowed, inclusion: { in: [true, false] } validates :maven_duplicate_exception_regex, untrusted_regexp: true, length: { maximum: 255 } + validates :generic_duplicates_allowed, inclusion: { in: [true, false] } + validates :generic_duplicate_exception_regex, untrusted_regexp: true, length: { maximum: 255 } class << self def duplicates_allowed?(package) diff --git a/app/models/packages.rb b/app/models/packages.rb index e14c9290093..19490d23ce4 100644 --- a/app/models/packages.rb +++ b/app/models/packages.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true module Packages + DuplicatePackageError = Class.new(StandardError) + def self.table_name_prefix 'packages_' end diff --git a/app/models/repository.rb b/app/models/repository.rb index 9d2e514f377..9411cbc35fc 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -995,7 +995,13 @@ class Repository def search_files_by_wildcard_path(path, ref = 'HEAD') # We need to use RE2 to match Gitaly's regexp engine - regexp_string = RE2::Regexp.escape(path).gsub('\*', '.*?') + regexp_string = RE2::Regexp.escape(path) + + anything = '.*?' + anything_but_not_slash = '([^\/])*?' + regexp_string.gsub!('\*\*', anything) + regexp_string.gsub!('\*', anything_but_not_slash) + raw_repository.search_files_by_regexp("^#{regexp_string}$", ref) end diff --git a/app/services/namespaces/package_settings/update_service.rb b/app/services/namespaces/package_settings/update_service.rb index 0964963647a..cbadbe5c907 100644 --- a/app/services/namespaces/package_settings/update_service.rb +++ b/app/services/namespaces/package_settings/update_service.rb @@ -5,7 +5,10 @@ module Namespaces class UpdateService < BaseContainerService include Gitlab::Utils::StrongMemoize - ALLOWED_ATTRIBUTES = %i[maven_duplicates_allowed maven_duplicate_exception_regex].freeze + ALLOWED_ATTRIBUTES = %i[maven_duplicates_allowed + maven_duplicate_exception_regex + generic_duplicates_allowed + generic_duplicate_exception_regex].freeze def execute return ServiceResponse.error(message: 'Access Denied', http_status: 403) unless allowed? diff --git a/app/services/packages/generic/create_package_file_service.rb b/app/services/packages/generic/create_package_file_service.rb index 1451a022a39..42a191fb415 100644 --- a/app/services/packages/generic/create_package_file_service.rb +++ b/app/services/packages/generic/create_package_file_service.rb @@ -23,6 +23,10 @@ module Packages .new(project, current_user, package_params) .execute + unless Namespace::PackageSetting.duplicates_allowed?(package) + raise ::Packages::DuplicatePackageError if target_file_is_duplicate?(package) + end + package.update_column(:status, params[:status]) if params[:status] && params[:status] != package.status package.build_infos.safe_find_or_create_by!(pipeline: params[:build].pipeline) if params[:build].present? @@ -40,6 +44,10 @@ module Packages ::Packages::CreatePackageFileService.new(package, file_params).execute end + + def target_file_is_duplicate?(package) + package.package_files.with_file_name(params[:file_name]).exists? + end end end end diff --git a/app/views/shared/snippets/_snippet.html.haml b/app/views/shared/snippets/_snippet.html.haml index 52cf0248f21..4e373dda013 100644 --- a/app/views/shared/snippets/_snippet.html.haml +++ b/app/views/shared/snippets/_snippet.html.haml @@ -8,7 +8,7 @@ = link_to gitlab_snippet_path(snippet) do = snippet.title - %ul.controls + %ul.controls{ data: { qa_selector: 'snippet_file_count_content', qa_snippet_files: snippet.statistics&.file_count } } %li = snippet_file_count(snippet) %li @@ -16,7 +16,7 @@ = sprite_icon('comments', css_class: 'gl-vertical-align-text-bottom') = notes_count %li - %span.sr-only + %span.sr-only{ data: { qa_selector: 'snippet_visibility_content', qa_snippet_visibility: visibility_level_label(snippet.visibility_level) } } = visibility_level_label(snippet.visibility_level) = visibility_level_icon(snippet.visibility_level) diff --git a/changelogs/unreleased/293755-generic-dupe-settings.yml b/changelogs/unreleased/293755-generic-dupe-settings.yml new file mode 100644 index 00000000000..fd2e5a8d1d8 --- /dev/null +++ b/changelogs/unreleased/293755-generic-dupe-settings.yml @@ -0,0 +1,5 @@ +--- +title: Add setting to allow or disallow duplicates for generic packages +merge_request: 60664 +author: +type: added diff --git a/changelogs/unreleased/327414-agent-proxy-request-count.yml b/changelogs/unreleased/327414-agent-proxy-request-count.yml new file mode 100644 index 00000000000..1f3bf7027b6 --- /dev/null +++ b/changelogs/unreleased/327414-agent-proxy-request-count.yml @@ -0,0 +1,5 @@ +--- +title: Add kubernetes_agent_proxy_request to usage ping +merge_request: 60978 +author: +type: changed diff --git a/db/migrate/20210429192653_add_generic_package_duplicate_settings_to_namespace_package_settings.rb b/db/migrate/20210429192653_add_generic_package_duplicate_settings_to_namespace_package_settings.rb new file mode 100644 index 00000000000..8c328eb52fc --- /dev/null +++ b/db/migrate/20210429192653_add_generic_package_duplicate_settings_to_namespace_package_settings.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class AddGenericPackageDuplicateSettingsToNamespacePackageSettings < ActiveRecord::Migration[6.0] + # rubocop:disable Migration/AddLimitToTextColumns + # limit is added in 20210429193106_add_text_limit_to_namespace_package_settings_generic_duplicate_exception_regex + def change + add_column :namespace_package_settings, :generic_duplicates_allowed, :boolean, null: false, default: true + add_column :namespace_package_settings, :generic_duplicate_exception_regex, :text, null: false, default: '' + end + # rubocop:enable Migration/AddLimitToTextColumns +end diff --git a/db/migrate/20210429193106_add_text_limit_to_namespace_package_settings_generic_duplicate_exception_regex.rb b/db/migrate/20210429193106_add_text_limit_to_namespace_package_settings_generic_duplicate_exception_regex.rb new file mode 100644 index 00000000000..5d02ad3e2f5 --- /dev/null +++ b/db/migrate/20210429193106_add_text_limit_to_namespace_package_settings_generic_duplicate_exception_regex.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +class AddTextLimitToNamespacePackageSettingsGenericDuplicateExceptionRegex < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + disable_ddl_transaction! + + def up + add_text_limit :namespace_package_settings, :generic_duplicate_exception_regex, 255 + end + + def down + remove_text_limit :namespace_package_settings, :generic_duplicate_exception_regex + end +end diff --git a/db/schema_migrations/20210429192653 b/db/schema_migrations/20210429192653 new file mode 100644 index 00000000000..5e380380d72 --- /dev/null +++ b/db/schema_migrations/20210429192653 @@ -0,0 +1 @@ +c2b5ad6786e1c71ccff391b03fcd0635dfd42d69484443291a692cef9f3ffda5 \ No newline at end of file diff --git a/db/schema_migrations/20210429193106 b/db/schema_migrations/20210429193106 new file mode 100644 index 00000000000..49f1838a585 --- /dev/null +++ b/db/schema_migrations/20210429193106 @@ -0,0 +1 @@ +e0898e4e439cde4e3b84808e7505490fe956cf17922f5c779b3384997d36cafd \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 5bf73b4955a..ce42f7362ca 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -14798,6 +14798,9 @@ CREATE TABLE namespace_package_settings ( namespace_id bigint NOT NULL, maven_duplicates_allowed boolean DEFAULT true NOT NULL, maven_duplicate_exception_regex text DEFAULT ''::text NOT NULL, + generic_duplicates_allowed boolean DEFAULT true NOT NULL, + generic_duplicate_exception_regex text DEFAULT ''::text NOT NULL, + CONSTRAINT check_31340211b1 CHECK ((char_length(generic_duplicate_exception_regex) <= 255)), CONSTRAINT check_d63274b2b6 CHECK ((char_length(maven_duplicate_exception_regex) <= 255)) ); diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index be5de5c86ac..28f91c7139e 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -3911,6 +3911,8 @@ Input type: `UpdateNamespacePackageSettingsInput` | Name | Type | Description | | ---- | ---- | ----------- | | `clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | +| `genericDuplicateExceptionRegex` | [`UntrustedRegexp`](#untrustedregexp) | When generic_duplicates_allowed is false, you can publish duplicate packages with names that match this regex. Otherwise, this setting has no effect. | +| `genericDuplicatesAllowed` | [`Boolean`](#boolean) | Indicates whether duplicate generic packages are allowed for this namespace. | | `mavenDuplicateExceptionRegex` | [`UntrustedRegexp`](#untrustedregexp) | When maven_duplicates_allowed is false, you can publish duplicate packages with names that match this regex. Otherwise, this setting has no effect. | | `mavenDuplicatesAllowed` | [`Boolean`](#boolean) | Indicates whether duplicate Maven packages are allowed for this namespace. | | `namespacePath` | [`ID!`](#id) | The namespace path where the namespace package setting is located. | @@ -10488,6 +10490,8 @@ Namespace-level Package Registry settings. | Name | Type | Description | | ---- | ---- | ----------- | +| `genericDuplicateExceptionRegex` | [`UntrustedRegexp`](#untrustedregexp) | When generic_duplicates_allowed is false, you can publish duplicate packages with names that match this regex. Otherwise, this setting has no effect. | +| `genericDuplicatesAllowed` | [`Boolean!`](#boolean) | Indicates whether duplicate generic packages are allowed for this namespace. | | `mavenDuplicateExceptionRegex` | [`UntrustedRegexp`](#untrustedregexp) | When maven_duplicates_allowed is false, you can publish duplicate packages with names that match this regex. Otherwise, this setting has no effect. | | `mavenDuplicatesAllowed` | [`Boolean!`](#boolean) | Indicates whether duplicate Maven packages are allowed for this namespace. | diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index f815bfbc5a9..23cdce8187b 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -487,7 +487,7 @@ Use local includes instead of symbolic links. > - It's not recommended for production use. > - To use it in GitLab self-managed instances, ask a GitLab administrator to enable it. **(CORE ONLY)** -You can use wildcard paths (`*`) with `include:local`. +You can use wildcard paths (`*` and `**`) with `include:local`. Example: @@ -495,7 +495,19 @@ Example: include: 'configs/*.yml' ``` -When the pipeline runs, it adds all `.yml` files in the `configs` folder into the pipeline configuration. +When the pipeline runs, GitLab: + +- Adds all `.yml` files in the `configs` directory into the pipeline configuration. +- Does not add `.yml` files in subfolders of the `configs` directory. To allow this, + add the following configuration: + + ```yaml + # This matches all `.yml` files in `configs` and any subfolder in it. + include: 'configs/**.yml' + + # This matches all `.yml` files only in subfolders of `configs`. + include: 'configs/**/*.yml' + ``` The wildcard file paths feature is under development and not ready for production use. It is deployed behind a feature flag that is **disabled by default**. diff --git a/doc/development/internal_api.md b/doc/development/internal_api.md index 7cf740d16a0..57dd1c0a65b 100644 --- a/doc/development/internal_api.md +++ b/doc/development/internal_api.md @@ -453,7 +453,8 @@ metric counters. | Attribute | Type | Required | Description | |:----------|:-------|:---------|:------------| -| `gitops_sync_count` | integer| yes | The number to increase the `gitops_sync_count` counter by | +| `gitops_sync_count` | integer| no | The number to increase the `gitops_sync_count` counter by | +| `k8s_api_proxy_request_count` | integer| no | The number to increase the `k8s_api_proxy_request_count` counter by | ```plaintext POST /internal/kubernetes/usage_metrics diff --git a/doc/development/usage_ping/dictionary.md b/doc/development/usage_ping/dictionary.md index 8c60a768b46..80816bf583a 100644 --- a/doc/development/usage_ping/dictionary.md +++ b/doc/development/usage_ping/dictionary.md @@ -2902,6 +2902,18 @@ Status: `data_available` Tiers: `premium`, `ultimate` +### `counts.kubernetes_agent_k8s_api_proxy_request` + +Count of Kubernetes API proxy requests + +[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_all/20210505015532_kubernetes_agent_k8s_api_proxy_request.yml) + +Group: `group::configure` + +Status: `implemented` + +Tiers: `premium`, `ultimate` + ### `counts.kubernetes_agents` Count of Kubernetes agents diff --git a/doc/topics/git/numerous_undo_possibilities_in_git/index.md b/doc/topics/git/numerous_undo_possibilities_in_git/index.md index eb1c0a597f3..2426fa2f7cb 100644 --- a/doc/topics/git/numerous_undo_possibilities_in_git/index.md +++ b/doc/topics/git/numerous_undo_possibilities_in_git/index.md @@ -5,139 +5,134 @@ info: To determine the technical writer assigned to the Stage/Group associated w type: howto --- -# Numerous undo possibilities in Git **(FREE)** +# Undo possibilities in Git **(FREE)** -This tutorial shows you different ways of undoing your work in Git. -We assume you have a basic working knowledge of Git. Check the GitLab -[Git documentation](../index.md) for reference. +[Nothing in Git is deleted](https://git-scm.com/book/en/v2/Git-Internals-Maintenance-and-Data-Recovery), +so when you work in Git, you can undo your work. -We only provide some general information about the commands to get you started. -For more advanced examples, refer to the [Git book](https://git-scm.com/book/en/v2). +All version control systems have options for undoing work. However, +because of the de-centralized nature of Git, these options are multiplied. +The actions you take are based on the +[stage of development](https://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository) +you are in. -A few different techniques exist to undo your changes, based on the stage -of the change in your current development. Remember that -[nothing in Git is really deleted](https://git-scm.com/book/en/v2/Git-Internals-Maintenance-and-Data-Recovery). -Until Git cleans detached commits - commits that cannot be accessed by branch or tag - -you can view them with `git reflog` command, and access them with direct commit ID. -Read more about [redoing the undo](#redoing-the-undo) in the section below. +For more information about working with Git and GitLab: -> For more information about working with Git and GitLab: -> -> -  Learn why [North Western Mutual chose GitLab](https://youtu.be/kPNMyxKRRoM) for their Enterprise source code management. -> - Learn how to [get started with Git](https://about.gitlab.com/resources/whitepaper-moving-to-git/). +-  Learn why [North Western Mutual chose GitLab](https://youtu.be/kPNMyxKRRoM) for their enterprise source code management. +- Learn how to [get started with Git](https://about.gitlab.com/resources/whitepaper-moving-to-git/). +- For more advanced examples, refer to the [Git book](https://git-scm.com/book/en/v2). -## Introduction +## When you can undo changes -This guide is organized depending on the [stage of development](https://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository): +In the standard Git workflow: -- Where do you want to undo your changes from? -- Were they shared with other developers? +1. You create or edit a file. It starts in the unstaged state. If it's new, it is not yet tracked by Git. +1. You add the file to your local repository (`git add`), which puts the file into the staged state. +1. You commit the file to your local repository (`git commit`). +1. You can then share the file with other developers, by committing to a remote repository (`git push`). -Because Git tracks changes, a created or edited file is in the unstaged state -(if created it is untracked by Git). After you add it to a repository (`git add`) you put -a file into the **staged** state, which is then committed (`git commit`) to your -local repository. After that, file can be shared with other developers (`git push`). -This tutorial covers: +You can undo changes at any point in this workflow: -- [Undo local changes](#undo-local-changes) which were not pushed to a remote repository: - - - Before you commit, in both unstaged and staged state. - - After you committed. - -- Undo changes after they are pushed to a remote repository: - - - [Without history modification](#undo-remote-changes-without-changing-history) (preferred way). - - [With history modification](#undo-remote-changes-with-modifying-history) (requires +- [When you're working locally](#undo-local-changes) and haven't yet pushed to a remote repository. +- When you have already pushed to a remote repository and you want to: + - [Keep the history intact](#undo-remote-changes-without-changing-history) (preferred). + - [Change the history](#undo-remote-changes-with-modifying-history) (requires coordination with team and force pushes). - - [Use cases when modifying history is generally acceptable](#where-modifying-history-is-generally-acceptable). - - [How to modify history](#how-modifying-history-is-done). - - [How to remove sensitive information from repository](#deleting-sensitive-information-from-commits). - -### Branching strategy - -[Git](https://git-scm.com/) is a de-centralized version control system. Beside regular -versioning of the whole repository, it has possibilities to exchange changes -with other repositories. - -To avoid chaos with -[multiple sources of truth](https://git-scm.com/about/distributed), various -development workflows have to be followed. It depends on your internal -workflow how certain changes or commits can be undone or changed. - -[GitLab Flow](https://about.gitlab.com/topics/version-control/what-is-gitlab-flow/) provides a good -balance between developers clashing with each other while -developing the same feature and cooperating seamlessly. However, it does not enable -joined development of the same feature by multiple developers by default. - -When multiple developers develop the same feature on the same branch, clashing -with every synchronization is unavoidable. However, a proper or chosen Git Workflow -prevents lost or out-of-sync data when the feature is complete. - -You can also -read through this blog post on [Git Tips & Tricks](https://about.gitlab.com/blog/2016/12/08/git-tips-and-tricks/) -to learn how to do things in Git. ## Undo local changes -Until you push your changes to any remote repository, they only affect you. -That broadens your options on how to handle undoing them. Still, local changes -can be on various stages and each stage has a different approach on how to tackle them. +Until you push your changes to a remote repository, changes +you make in Git are only in your local development environment. -### Unstaged local changes (before you commit) +### Undo unstaged local changes before you commit -When a change is made, but not added to the staged tree, Git -proposes a solution to discard changes to the file. +When you make a change, but have not yet staged it, you can undo your work. -Suppose you edited a file to change the content using your favorite editor: +1. Confirm that the file is unstaged (that you did not use `git add `) by running `git status`: -```shell -vim -``` + ```shell + $ git status + On branch main + Your branch is up-to-date with 'origin/main'. + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) -Because you did not `git add ` to staging, it should be under unstaged files (or -untracked if file was created). You can confirm that with: + modified: + no changes added to commit (use "git add" and/or "git commit -a") + ``` -```shell -$ git status -On branch master -Your branch is up-to-date with 'origin/master'. -Changes not staged for commit: - (use "git add ..." to update what will be committed) - (use "git checkout -- ..." to discard changes in working directory) +1. Choose an option and undo your changes: - modified: -no changes added to commit (use "git add" and/or "git commit -a") -``` + - To overwrite local changes: -At this point there are 3 options to undo the local changes you have: + ```shell + git checkout -- + ``` -- Discard all local changes, but save them for possible re-use [later](#quickly-save-local-changes): + - To save local changes so you can [re-use them later](#quickly-save-local-changes): - ```shell - git stash - ``` + ```shell + git stash + ``` -- Discarding local changes (permanently) to a file: + - To discard local changes to all files, permanently: - ```shell - git checkout -- - ``` + ```shell + git reset --hard + ``` -- Discard all local changes to all files permanently: +### Undo staged local changes before you commit - ```shell - git reset --hard - ``` +If you added a file to staging, you can undo it. -Before executing `git reset --hard`, keep in mind that there is also a way to -just temporary store the changes without committing them using `git stash`. -This command resets the changes to all files, but it also saves them in case -you would like to apply them at some later time. You can read more about it in -[section below](#quickly-save-local-changes). +1. Confirm that the file is staged (that you used `git add `) by running `git status`: + + ```shell + $ git status + On branch main + Your branch is up-to-date with 'origin/main'. + Changes to be committed: + (use "git restore --staged ..." to unstage) + + new file: + ``` + +1. Choose an option and undo your changes: + + - To unstage the file but keep your changes: + + ```shell + git restore --staged + ``` + + - To unstage everything but keep your changes: + + ```shell + git reset + ``` + + - To unstage the file to current commit (HEAD): + + ```shell + git reset HEAD + ``` + + - To discard all local changes, but save them for [later](#quickly-save-local-changes): + + ```shell + git stash + ``` + + - To discard everything permanently: + + ```shell + git reset --hard + ``` ### Quickly save local changes -You are working on a feature when a boss drops by with an urgent task. Because your +You are working on a feature when someone drops by with an urgent task. Because your feature is not complete, but you need to swap to another branch, you can use `git stash` to: @@ -159,60 +154,7 @@ additional options like: - `git stash pop`, which redoes previously stashed changes and removes them from stashed list - `git stash apply`, which redoes previously stashed changes, but keeps them on stashed list -### Staged local changes (before you commit) - -If you add some files to staging, but you want to remove them from the -current commit while retaining those changes, move them outside -of the staging tree. You can also discard all changes with -`git reset --hard` or think about `git stash` [as described earlier.](#quickly-save-local-changes) - -Lets start the example by editing a file with your favorite editor to change the -content and add it to staging: - -```shell -vim -git add -``` - -The file is now added to staging as confirmed by `git status` command: - -```shell -$ git status -On branch master -Your branch is up-to-date with 'origin/master'. -Changes to be committed: - (use "git reset HEAD ..." to unstage) - - new file: -``` - -Now you have 4 options to undo your changes: - -- Unstage the file to current commit (HEAD): - - ```shell - git reset HEAD - ``` - -- Unstage everything - retain changes: - - ```shell - git reset - ``` - -- Discard all local changes, but save them for [later](#quickly-save-local-changes): - - ```shell - git stash - ``` - -- Discard everything permanently: - - ```shell - git reset --hard - ``` - -## Committed local changes +## Undo committed local changes After you commit, your changes are recorded by the version control system. Because you haven't pushed to your remote repository yet, your changes are @@ -289,6 +231,9 @@ these options to remove all or part of it from our repository: ### With history modification +You can rewrite history in Git, but you should avoid it, because it can cause problems +when multiple developers are contributing to the same codebase. + There is one command for history modification and that is `git rebase`. Command provides interactive mode (`-i` flag) which enables you to: @@ -335,7 +280,7 @@ In case you want to modify something introduced in commit `B`. You can find some more examples in the section explaining [how to modify history](#how-modifying-history-is-done). -### Redoing the Undo +### Redoing the undo Sometimes you realize that the changes you undid were useful and you want them back. Well because of first paragraph you are in luck. Command `git reflog` @@ -501,14 +446,6 @@ feature set as `git filter-branch` does, but focus on specific use cases. Refer [Reduce repository size](../../../user/project/repository/reducing_the_repo_size_using_git.md) page to know more about purging files from repository history & GitLab storage. -## Conclusion - -Various options exist for undoing your work with any version control system, but -because of the de-centralized nature of Git, these options are multiplied (or limited) -depending on the stage of your process. Git also enables rewriting history, but that -should be avoided as it might cause problems when multiple developers are -contributing to the same codebase. -