diff --git a/app/views/protected_branches/shared/_create_protected_branch.html.haml b/app/views/protected_branches/shared/_create_protected_branch.html.haml index bb1d56dcc619e6ef47c7f09952a5968192dbdd6c..48c3752e8263792e6a02c3eff54b780402320037 100644 --- a/app/views/protected_branches/shared/_create_protected_branch.html.haml +++ b/app/views/protected_branches/shared/_create_protected_branch.html.haml @@ -39,7 +39,7 @@ = render Pajamas::ToggleComponent.new(classes: 'js-force-push-toggle', label: s_("ProtectedBranch|Allowed to force push"), label_position: :hidden) do - - force_push_docs_url = help_page_url('topics/git/git_rebase', anchor: 'force-push') + - force_push_docs_url = help_page_url('topics/git/git_rebase', anchor: 'force-pushing') - force_push_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: force_push_docs_url } = (s_("ProtectedBranch|Allow all users with push access to %{tag_start}force push%{tag_end}.") % { tag_start: force_push_link_start, tag_end: '</a>' }).html_safe = render_if_exists 'protected_branches/ee/code_owner_approval_form', f: f, protected_branch_entity: protected_branch_entity diff --git a/doc/gitlab-basics/start-using-git.md b/doc/gitlab-basics/start-using-git.md index 473986bc4daec63741437a615a98e905e3d07b86..de7b727fd183dcdb699492c4fb55b0bc5b52fa6a 100644 --- a/doc/gitlab-basics/start-using-git.md +++ b/doc/gitlab-basics/start-using-git.md @@ -369,7 +369,7 @@ git push origin main ``` Sometimes Git does not allow you to push to a repository. Instead, -you must [force an update](../topics/git/git_rebase.md#force-push). +you must [force an update](../topics/git/git_rebase.md#force-pushing). ### Delete all changes in the branch diff --git a/doc/topics/git/git_rebase.md b/doc/topics/git/git_rebase.md index 05773ec7e92ef8de59a17e104cea52cb249fd915..e4dce8bbf5753326e75d172cf53b0ff6b6817dc1 100644 --- a/doc/topics/git/git_rebase.md +++ b/doc/topics/git/git_rebase.md @@ -7,95 +7,107 @@ description: "Introduction to Git rebase and force push, methods to resolve merg # Git rebase and force push **(FREE ALL)** -This guide helps you to get started with rebases, force pushes, and fixing -[merge conflicts](../../user/project/merge_requests/conflicts.md) locally. -Before you attempt a force push or a rebase, make sure you are familiar with -[Git through the command line](../../gitlab-basics/start-using-git.md). +In Git, a rebase updates your branch with the contents of another branch. +A rebase confirms that changes in your branch don't conflict with +changes in the target branch. -WARNING: -`git rebase` rewrites the commit history. It **can be harmful** to do it in -shared branches. It can cause complex and hard to resolve -[merge conflicts](../../user/project/merge_requests/conflicts.md). In -these cases, instead of rebasing your branch against the default branch, -consider pulling it instead (`git pull origin master`). Pulling has similar -effects with less risk compromising the work of your contributors. +If you have a [merge conflict](../../user/project/merge_requests/conflicts.md), +you can rebase to fix it. -In Git, a rebase updates your feature branch with the contents of another branch. -This step is important for Git-based development strategies. Use a rebase to confirm -that your branch's changes don't conflict with any changes added to your target branch -_after_ you created your feature branch. +## What happens during rebase When you rebase: -1. Git imports all the commits submitted to your target branch _after_ you initially created - your feature branch from it. -1. Git stacks the commits you have in your feature branch on top of all +1. Git imports all the commits submitted to your target branch after you initially created + your branch from it. +1. Git stacks the commits you have in your branch on top of all the commits it imported from that branch: - +  While most rebases are performed against `main`, you can rebase against any other branch, such as `release-15-3`. You can also specify a different remote repository (such as `upstream`) instead of `origin`. -## Back up a branch before rebase +WARNING: +`git rebase` rewrites the commit history. It **can be harmful** to do it in +shared branches. It can cause complex and hard to resolve +merge conflicts. Instead of rebasing your branch against the default branch, +consider pulling it instead (`git pull origin master`). Pulling has similar +effects with less risk of compromising others' work. -To back up a branch before taking any destructive action, like a rebase or force push: +## Rebase by using Git -1. Open your feature branch in the terminal: `git checkout my-feature` -1. Create a backup branch: `git branch my-feature-backup` - Any changes added to `my-feature` after this point are lost - if you restore from the backup branch. +When you use Git to rebase, each commit is applied to your branch. +When merge conflicts occur, you are prompted to address them. -Your branch is backed up, and you can try a rebase or a force push. -If anything goes wrong, restore your branch from its backup: +If you want more advanced options for your commits, +do [an interactive rebase](#rebase-interactively-by-using-git). -1. Make sure you're in the correct branch (`my-feature`): `git checkout my-feature` -1. Reset it against `my-feature-backup`: `git reset --hard my-feature-backup` +Prerequisites: -## Rebase a branch +- You must have permission to force push to branches. -[Rebases](https://git-scm.com/docs/git-rebase) are very common operations in -Git, and have these options: +To use Git to rebase your branch against the target branch: -- **Regular rebases.** This type of rebase can be done through the - [command line](#regular-rebase) and [the GitLab UI](#from-the-gitlab-ui). -- [**Interactive rebases**](#interactive-rebase) give more flexibility by - enabling you to specify how to handle each commit. Interactive rebases - must be done on the command line. +1. Open a terminal and change to your project. +1. Ensure you have the latest contents of the target branch. + In this example, the target branch is `main`: -Any user who rebases a branch is treated as having added commits to that branch. -If a project is configured to -[**prevent approvals by users who add commits**](../../user/project/merge_requests/approvals/settings.md#prevent-approvals-by-users-who-add-commits), -a user who rebases a branch cannot also approve its merge request. + ```shell + git fetch origin main + ``` -### Regular rebase +1. Check out your branch: -Standard rebases replay the previous commits on a branch without changes, stopping -only if merge conflicts occur. + ```shell + git checkout my-branch + ``` -Prerequisites: +1. Optional. Create a backup of your branch: -- You must have permission to force push branches. + ```shell + git branch my-branch-backup + ``` -To update your branch `my-feature` with recent changes from your -[default branch](../../user/project/repository/branches/default.md) (here, using `main`): + Changes added to `my-branch` after this point are lost + if you restore from the backup branch. -1. Fetch the latest changes from `main`: `git fetch origin main` -1. Check out your feature branch: `git checkout my-feature` -1. Rebase it against `main`: `git rebase origin/main` -1. [Force push](#force-push) to your branch. +1. Rebase against the main branch: -If there are merge conflicts, Git prompts you to fix them before continuing the rebase. + ```shell + git rebase origin/main + ``` -### From the GitLab UI +1. If merge conflicts exist: + 1. Fix the conflicts in your editor. -The `/rebase` [quick action](../../user/project/quick_actions.md#issues-merge-requests-and-epics) -rebases your feature branch directly from its merge request if all of these -conditions are met: + 1. Add the files: -- No merge conflicts exist for your feature branch. -- You have the **Developer** role for the source project. This role grants you + ```shell + git add . + ``` + + 1. Continue the rebase: + + ```shell + git rebase --continue + ``` + +1. Force push your changes to the target branch, while protecting others' commits: + + ```shell + git push origin my-branch --force-with-lease + ``` + +## Rebase from the UI + +You can rebase a merge request from the GitLab UI. + +Prerequisites: + +- No merge conflicts must exist. +- You must have at least the **Developer** role for the source project. This role grants you permission to push to the source branch for the source project. - If the merge request is in a fork, the fork must allow commits [from members of the upstream project](../../user/project/merge_requests/allow_collaboration.md). @@ -106,91 +118,112 @@ To rebase from the UI: 1. Type `/rebase` in a comment. 1. Select **Comment**. -GitLab schedules a rebase of the feature branch against the default branch and +GitLab schedules a rebase of the branch against the default branch and executes it as soon as possible. -### Interactive rebase - -Use an interactive rebase (the `--interactive` flag, or `-i`) to simultaneously -update a branch while you modify how its commits are handled. -For example, to edit the last five commits in your branch (`HEAD~5`), run: - -```shell -git rebase -i HEAD~5 -``` - -Git opens the last five commits in your terminal text editor, oldest commit first. -Each commit shows the action to take on it, the SHA, and the commit title: - -```shell -pick 111111111111 Second round of structural revisions -pick 222222222222 Update inbound link to this changed page -pick 333333333333 Shifts from H4 to H3 -pick 444444444444 Adds revisions from editorial -pick 555555555555 Revisions continue to build the concept part out - -# Rebase 111111111111..222222222222 onto zzzzzzzzzzzz (5 commands) -# -# Commands: -# p, pick <commit> = use commit -# r, reword <commit> = use commit, but edit the commit message -# e, edit <commit> = use commit, but stop for amending -# s, squash <commit> = use commit, but meld into previous commit -# f, fixup [-C | -c] <commit> = like "squash" but keep only the previous -``` - -After the list of commits, a commented-out section shows some common actions you -can take on a commit: - -- **Pick** a commit to use it with no changes. The default option. -- **Reword** a commit message. -- **Edit** a commit to use it, but pause the rebase to amend (add changes to) it. -- **Squash** multiple commits together to simplify the commit history - of your feature branch. - -Replace the keyword `pick` according to -the operation you want to perform in each commit. To do so, edit -the commits in your terminal's text editor. - -For example, with [Vim](https://www.vim.org/) as the text editor in -a macOS Zsh shell, you can `squash` or `fixup` (combine) all of the commits together: - -NOTE: -The steps for editing through the command line can be slightly -different depending on your operating system and the shell you use. - -1. Press <kbd>i</kbd> on your keyboard to switch to Vim's editing mode. -1. Use your keyboard arrows to edit the **second** commit keyword - from `pick` to `squash` or `fixup` (or `s` or `f`). Do the same to the remaining commits. - Leave the first commit **unchanged** (`pick`) as we want to squash - all other commits into it. -1. Press <kbd>Escape</kbd> to leave the editing mode. -1. Type `:wq` to "write" (save) and "quit". +## Rebase interactively by using Git + +Use an interactive rebase when you want to specify how to handle each commit. +You must do an interactive rebase from the command line. + +Prerequisites: + +- [Vim](https://www.vim.org/) must be your text editor to follow these instructions. + +To rebase interactively: + +1. Open a terminal and change to your project. +1. Ensure you have the latest contents of the target branch. + In this example, the target branch is `main`: + + ```shell + git fetch origin main + ``` + +1. Check out your branch: + + ```shell + git checkout my-branch + ``` + +1. Optional. Create a backup of your branch: + + ```shell + git branch my-branch-backup + ``` + + Changes added to `my-branch` after this point are lost + if you restore from the backup branch. + +1. In the GitLab UI, in your merge request, confirm how many commits + you want to rebase by viewing the **Commits** tab. + +1. Open these commits. For example, to edit the last five commits in your branch (`HEAD~5`), type: + + ```shell + git rebase -i HEAD~5 + ``` + + Git opens the last five commits in your terminal text editor, oldest commit first. + Each commit shows the action to take on it, the SHA, and the commit title: + + ```shell + pick 111111111111 Second round of structural revisions + pick 222222222222 Update inbound link to this changed page + pick 333333333333 Shifts from H4 to H3 + pick 444444444444 Adds revisions from editorial + pick 555555555555 Revisions continue to build the concept part out + + # Rebase 111111111111..222222222222 onto zzzzzzzzzzzz (5 commands) + # + # Commands: + # p, pick <commit> = use commit + # r, reword <commit> = use commit, but edit the commit message + # e, edit <commit> = use commit, but stop for amending + # s, squash <commit> = use commit, but meld into previous commit + # f, fixup [-C | -c] <commit> = like "squash" but keep only the previous + ``` + +1. Switch to Vim's edit mode by pressing <kbd>i</kbd>. +1. Move to the second commit in the list by using your keyboard arrows. +1. Change the word `pick` to `squash` or `fixup` (or `s` or `f`). +1. Do the same for the remaining commits. Leave the first commit as `pick`. +1. End edit mode, save, and quit: + + - Press <kbd>ESC</kbd>. + - Type `:wq`. + 1. When squashing, Git outputs the commit message so you have a chance to edit it: + - All lines starting with `#` are ignored and not included in the commit - message. Everything else is included. - - To leave it as it is, type `:wq`. To edit the commit message: switch to the - editing mode, edit the commit message, and save it as you just did. -1. If you haven't pushed your commits to the remote branch before rebasing, - push your changes without a force push. If you had pushed these commits already, - [force push](#force-push) instead. + message. Everything else is included. + - To leave it as-is, type `:wq`. To edit the commit message, switch to + edit mode, edit the commit message, and save. + +1. Commit to the target branch. -#### Configure squash options for a project + - If you didn't push your commits to the target branch before rebasing, + push your changes without a force push: -Keeping the default branch commit history clean doesn't require you to -manually squash all your commits on each merge request. GitLab provides -[squash and merge](../../user/project/merge_requests/squash_and_merge.md#configure-squash-options-for-a-project), -options at a project level. + ```shell + git push origin my-branch + ``` -## Force push + - If you pushed these commits already, use a force push: + + ```shell + git push origin my-branch --force-with-lease + ``` + +## Force pushing Complex operations in Git require you to force an update to the remote branch. Operations like squashing commits, resetting a branch, or rebasing a branch rewrite the history of your branch. Git requires a forced update to help safeguard against these more destructive changes from happening accidentally. -Force pushing is not recommended on shared branches, as you risk destroying the -changes of others. +Force pushing is not recommended on shared branches, because you risk destroying +others' changes. If the branch you want to force push is [protected](../../user/project/protected_branches.md), you can't force push to it unless you either: @@ -201,27 +234,32 @@ you can't force push to it unless you either: Then you can force push and protect it again. -### `--force-with-lease` flag +## Restore your backed up branch + +Your branch is backed up, and you can try a rebase or a force push. +If anything goes wrong, restore your branch from its backup: + +1. Make sure you're in the correct branch: -The [`--force-with-lease`](https://git-scm.com/docs/git-push#Documentation/git-push.txt---force-with-leaseltrefnamegt) -flag force pushes. Because it preserves any new commits added to the remote -branch by other people, it is safer than `--force`: + ```shell + git checkout my-branch + ``` -```shell -git push --force-with-lease origin my-feature -``` +1. Reset your branch against the backup: -### `--force` flag + ```shell + git reset --hard my-branch-backup + ``` -The `--force` flag forces pushes, but does not preserve any new commits added to -the remote branch by other people. To use this method, pass the flag `--force` or `-f` -to the `push` command: +## Approving after rebase -```shell -git push --force origin my-feature -``` +If you rebase a branch, you've added commits. +If your project is configured to +[prevent approvals by users who add commits](../../user/project/merge_requests/approvals/settings.md#prevent-approvals-by-users-who-add-commits), +you can't approve a merge request if you have rebased it. ## Related topics - [Numerous undo possibilities in Git](numerous_undo_possibilities_in_git/index.md#undo-staged-local-changes-without-modifying-history) - [Git documentation for branches and rebases](https://git-scm.com/book/en/v2/Git-Branching-Rebasing) +- [Project squash and merge settings](../../user/project/merge_requests/squash_and_merge.md#configure-squash-options-for-a-project) diff --git a/doc/user/project/merge_requests/conflicts.md b/doc/user/project/merge_requests/conflicts.md index 0ebf1c8ed9e1a3c835abaaf6f4e171423171996b..e4640b4d63521b666b5833d6f2fbfad828b9f2f0 100644 --- a/doc/user/project/merge_requests/conflicts.md +++ b/doc/user/project/merge_requests/conflicts.md @@ -105,7 +105,7 @@ most control over each change: git switch my-feature-branch ``` -1. [Rebase your branch](../../../topics/git/git_rebase.md#regular-rebase) against the +1. [Rebase your branch](../../../topics/git/git_rebase.md#rebase-by-using-git) against the target branch (here, `main`) so Git prompts you with the conflicts: ```shell @@ -150,7 +150,7 @@ most control over each change: running `git rebase`. After you run `git rebase --continue`, you cannot abort the rebase. -1. [Force-push](../../../topics/git/git_rebase.md#force-push) the changes to your +1. [Force-push](../../../topics/git/git_rebase.md#force-pushing) the changes to your remote branch. ## Merge commit strategy diff --git a/doc/user/project/merge_requests/methods/index.md b/doc/user/project/merge_requests/methods/index.md index 8acf380c6f62a0f1a3f236e29d55b3898ad2d9ea..9ecb3f8ae622949db20a37db4842059f5fb134a1 100644 --- a/doc/user/project/merge_requests/methods/index.md +++ b/doc/user/project/merge_requests/methods/index.md @@ -198,7 +198,7 @@ In these merge methods, you can merge only when your source branch is up-to-date If a fast-forward merge is not possible but a conflict-free rebase is possible, GitLab provides: -- The [`/rebase` quick action](../../../../topics/git/git_rebase.md#from-the-gitlab-ui). +- The [`/rebase` quick action](../../../../topics/git/git_rebase.md#rebase-from-the-ui). - The option to select **Rebase** in the user interface. You must rebase the source branch locally before a fast-forward merge if both diff --git a/doc/user/project/protected_branches.md b/doc/user/project/protected_branches.md index a77babb6cd6e88e1f7011d4a85b8dbb07aa28176..0525729ef581819989eba8a4e34acddb771a8ddc 100644 --- a/doc/user/project/protected_branches.md +++ b/doc/user/project/protected_branches.md @@ -267,7 +267,7 @@ Deploy keys are not available in the **Allowed to merge** dropdown list. > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/15611) in GitLab 13.10 [with a flag](../../administration/feature_flags.md) named `allow_force_push_to_protected_branches`. Disabled by default. > - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/323431) in GitLab 14.0. Feature flag `allow_force_push_to_protected_branches` removed. -You can allow [force pushes](../../topics/git/git_rebase.md#force-push) to +You can allow [force pushes](../../topics/git/git_rebase.md#force-pushing) to protected branches. To protect a new branch and enable force push: diff --git a/doc/user/project/settings/import_export_troubleshooting.md b/doc/user/project/settings/import_export_troubleshooting.md index 79401a7734ada535863cd01949ffc88107202b01..aa1317608fbc739139755b402a09eef26fe14e42 100644 --- a/doc/user/project/settings/import_export_troubleshooting.md +++ b/doc/user/project/settings/import_export_troubleshooting.md @@ -86,7 +86,7 @@ reduce the repository size for another import attempt: 1. To reduce the repository size, work on this `smaller-tmp-main` branch: [identify and remove large files](../repository/reducing_the_repo_size_using_git.md) - or [interactively rebase and fixup](../../../topics/git/git_rebase.md#interactive-rebase) + or [interactively rebase and fixup](../../../topics/git/git_rebase.md#rebase-interactively-by-using-git) to reduce the number of commits. ```shell