Lots of Notes on here: need to sort them out!
https://docs.gitlab.com/ee/user/project/merge_requests/revert_changes.html
https://about.gitlab.com/blog/2019/07/12/guide-to-ci-cd-pipelines/
PUSHING to specific remote branch
fatal: The upstream branch of your current branch does not match
the name of your current branch. To push to the upstream branch
on the remote, use
git push origin HEAD:name-of-remote-branch
The Problem
There are a number of work-flows you can use. The main point is not to break history in a published branch unless you've communicated with everyone who might consume the branch and are willing to do surgery on everyone's clones. It's best not to do that if you can avoid it.
Solutions for Published Branches
Your outlined steps have merit. If you need the dev branch to be stable right away, do it that way. You have a number of tools for Debugging with Git that will help you find the right branch point, and then you can revert all the commits between your last stable commit and HEAD.
Either revert commits one at a time, in reverse order, or use the <first_bad_commit>..<last_bad_commit>
range. Hashes are the simplest way to specify the commit range, but there are other notations. For example, if you've pushed 5 bad commits, you could revert them with:
# Revert a series using ancestor notation. git revert --no-edit dev~5..dev # Revert a series using commit hashes. git revert --no-edit ffffffff..12345678
This will apply reversed patches to your working directory in sequence, working backwards towards your known-good commit. With the –no-edit flag, the changes to your working directory will be automatically committed after each reversed patch is applied.
See man 1 git-revert
for more options, and man 7 gitrevisions
for different ways to specify the commits to be reverted.
Alternatively, you can branch off your HEAD, fix things the way they need to be, and re-merge. Your build will be broken in the meantime, but this may make sense in some situations.
The Danger Zone
Of course, if you're absolutely sure that no one has pulled from the repository since your bad pushes, and if the remote is a bare repository, then you can do a non-fast-forward commit.
git reset --hard <last_good_commit> git push --force
This will leave the reflog intact on your system and the upstream host, but your bad commits will disappear from the directly-accessible history and won't propagate on pulls. Your old changes will hang around until the repositories are pruned, but only Git ninjas will be able to see or recover the commits you made by mistake.
FROM GITLAB – MERGE MANUALLY –
Check out, review, and merge locally
Step 1. Fetch and check out the branch for this merge request
git fetch origin git checkout -b "revert-140bcb6f" "origin/revert-140bcb6f"
Step 2. Review the changes locally
Step 3. Merge the branch and fix any conflicts that come up
git fetch origin git checkout "trenton-ducatti" git merge --no-ff "revert-140bcb6f"
Step 4. Push the result of the merge to GitLab
git push origin "trenton-ducatti"
FAILED:
git revert –continue
git push origin "trenton-ducatti"
Tip: You can also checkout merge requests locally by following these guidelines
This depends a lot on what you mean by "revert".
Temporarily switch to a different commit
If you want to temporarily go back to it, fool around, then come back to where you are, all you have to do is check out the desired commit:
# This will detach your HEAD, that is, leave you with no branch checked out:
git checkout 0d1d7fc32
Or if you want to make commits while you're there, go ahead and make a new branch while you're at it:
git checkout -b old-state 0d1d7fc32
To go back to where you were, just check out the branch you were on again. (If you've made changes, as always when switching branches, you'll have to deal with them as appropriate. You could reset to throw them away; you could stash, checkout, stash pop to take them with you; you could commit them to a branch there if you want a branch there.)
Hard delete unpublished commits
If, on the other hand, you want to really get rid of everything you've done since then, there are two possibilities. One, if you haven't published any of these commits, simply reset:
# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32
# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts, if you've modified things which were
# changed since the commit you reset to.
If you mess up, you've already thrown away your local changes, but you can at least get back to where you were before by resetting again.
Undo published commits with new commits
On the other hand, if you've published the work, you probably don't want to reset the branch, since that's effectively rewriting history. In that case, you could indeed revert the commits. With Git, revert has a very specific meaning: create a commit with the reverse patch to cancel it out. This way you don't rewrite any history.
# This will create three separate revert commits:
git revert a867b4af 25eee4ca 0766c053
# It also takes ranges. This will revert the last two commits:
git revert HEAD~2..HEAD
#Similarly, you can revert a range of commits using commit hashes (non inclusive of first hash):
git revert 0d1d7fc..a867b4a
# Reverting a merge commit
git revert -m 1 <merge_commit_sha>
# To get just one, you could use `rebase -i` to squash them afterwards
# Or, you could do it manually (be sure to do this at top level of the repo)
# get your index and work tree into the desired state, without changing HEAD:
git checkout 0d1d7fc32 .
# Then commit. Be sure and write a good message describing what you just did
git commit
The git-revert
manpage actually covers a lot of this in its description. Another useful link is this git-scm.com section discussing git-revert.
If you decide you didn't want to revert after all, you can revert the revert (as described here) or reset back to before the revert (see the previous section).
You may also find this answer helpful in this case:
How can I move HEAD back to a previous location? (Detached head) & Undo commits
git rebase -i 34c4f95
You can revert individual commits with:
git revert <commit_hash>
This will create a new commit which reverts the changes of the commit you specified. Note that it only reverts that specific commit, and not commits that come after that. If you want to revert a range of commits, you can do it like this:
git revert <oldest_commit_hash>..<latest_commit_hash>
It reverts the commits between and including the specified commits.
To know the hash of the commit(s) you can use git log
Look at the git-revert man page for more information about the git revert
command. Also, look at this answer for more information about reverting commits.
git revert bb2c503c..915004cd
GIT DELETE
Supose you have the following scenario:
* 1bd2200 (HEAD, master) another commit * d258546 bad commit * 0f1efa9 3rd commit * bd8aa13 2nd commit * 34c4f95 1st commit
Where you want to remove d258546 i.e. "bad commit".
You shall try an interactive rebase to remove it: git rebase -i 34c4f95
then your default editor will pop with something like this:
pick bd8aa13 2nd commit pick 0f1efa9 3rd commit pick d258546 bad commit pick 1bd2200 another commit # Rebase 34c4f95..1bd2200 onto 34c4f95 # # Commands: # p, pick = use commit # r, reword = use commit, but edit the commit message # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit # f, fixup = like "squash", but discard this commit's log message # x, exec = run command (the rest of the line) using shell # # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST. # # However, if you remove everything, the rebase will be aborted. # # Note that empty commits are commented out
just remove the line with the commit you want to strip and save+exit the editor:
pick bd8aa13 2nd commit pick 0f1efa9 3rd commit pick 1bd2200 another commit ...
git will proceed to remove this commit from your history leaving something like this (mind the hash change in the commits descendant from the removed commit):
* 34fa994 (HEAD, master) another commit * 0f1efa9 3rd commit * bd8aa13 2nd commit * 34c4f95 1st commit
Now, since I suppose that you already pushed the bad commit to gitlab, you'll need to repush your graph to the repository (but with the -f
option to prevent it from being rejected due to a non fastforwardeable history i.e. git push -f <your remote> <your branch>
)
Please be extra careful and make sure that none coworker is already using the history containing the "bad commit" in their branches.
Alternative option:
Instead of rewrite the history, you may simply create a new commit which negates the changes introduced by your bad commit, to do this just type git revert <your bad commit hash>
. This option is maybe not as clean, but is far more safe (in case you are not fully aware of what are you doing with an interactive rebase).
git branch -u https://git.quantox.tech/Ciric/ns-forge-site.git/trenton-ducatti
TL;DR version: remote-tracking branch origin/master
used to exist, but does not now, so local branch source
is tracking something that does not exist, which is suspicious at best—it means a different Git feature is unable to do anything for you—and Git is warning you about it. You have been getting along just fine without having the "upstream tracking" feature work as intended, so it's up to you whether to change anything.
For another take on upstream settings, see Why do I have to "git push --set-upstream origin "?
This warning is a new thing in Git, appearing first in Git 1.8.5. The release notes contain just one short bullet-item about it:
- "git branch -v -v" (and "git status") did not distinguish among a branch that is not based on any other branch, a branch that is in sync with its upstream branch, and a branch that is configured with an upstream branch that no longer exists.
To describe what it means, you first need to know about "remotes", "remote-tracking branches", and how Git handles "tracking an upstream". (Remote-tracking branches is a terribly flawed term—I've started using remote-tracking names instead, which I think is a slight improvement. Below, though, I'll use "remote-tracking branch" for consistency with Git documentation.)
Each "remote" is simply a name, like origin
or octopress
in this case. Their purpose is to record things like the full URL of the places from which you git fetch
or git pull
updates. When you use git fetch *remote*,
1 Git goes to that remote (using the saved URL) and brings over the appropriate set of updates. It also records the updates, using "remote-tracking branches".
A "remote-tracking branch" (or remote-tracking name) is simply a recording of a branch name as-last-seen on some "remote". Each remote is itself a Git repository, so it has branches. The branches on remote "origin" are recorded in your local repository under remotes/origin/
. The text you showed says that there's a branch named source
on origin
, and branches named 2.1
, linklog
, and so on on octopress
.
(A "normal" or "local" branch, of course, is just a branch-name that you have created in your own repository.)
Last, you can set up a (local) branch to "track" a "remote-tracking branch". Once local branch L
is set to track remote-tracking branch R
, Git will call R
its "upstream" and tell you whether you're "ahead" and/or "behind" the upstream (in terms of commits). It's normal (even recommend-able) for the local branch and remote-tracking branches to use the same name (except for the remote prefix part), like source
and origin/source
, but that's not actually necessary.
And in this case, that's not happening. You have a local branch source
tracking a remote-tracking branch origin/master
.
You're not supposed to need to know the exact mechanics of how Git sets up a local branch to track a remote one, but they are relevant below, so I'll show how this works. We start with your local branch name, source
. There are two configuration entries using this name, spelled branch.source.remote
and branch.source.merge
. From the output you showed, it's clear that these are both set, so that you'd see the following if you ran the given commands:
$ git config --get branch.source.remote origin $ git config --get branch.source.merge refs/heads/master
Putting these together,2 this tells Git that your branch source
tracks your "remote-tracking branch", origin/master
.
But now look at the output of git branch -a
, which shows all the local and remote-tracking branch names in your repository. The remote-tracking names are listed under remotes/
... and there is no remotes/origin/master
. Presumably there was, at one time, but it's gone now.
Git is telling you that you can remove the tracking information with --unset-upstream
. This will clear out both branch.source.origin
and branch.source.merge
, and stop the warning.
It seems fairly likely that what you want, though, is to switch from tracking origin/master
, to tracking something else: probably origin/source
, but maybe one of the octopress/
names.
You can do this with git branch --set-upstream-to
,3 e.g.:
$ git branch --set-upstream-to=origin/source
(assuming you're still on branch "source", and that origin/source
is the upstream you want—there is no way for me to tell which one, if any, you actually want, though).
(See also How do you make an existing Git branch track a remote branch?)
I think the way you got here is that when you first did a git clone
, the thing you cloned-from had a branch master
. You also had a branch master
, which was set to track origin/master
(this is a normal, standard setup for git). This meant you had branch.master.remote
and branch.master.merge
set, to origin
and refs/heads/master
. But then your origin
remote changed its name from master
to source
. To match, I believe you also changed your local name from master
to source
. This changed the names of your settings, from branch.master.remote
to branch.source.remote
and from branch.master.merge
to branch.source.merge
... but it left the old values, so branch.source.merge
was now wrong.
It was at this point that the "upstream" linkage broke, but in Git versions older than 1.8.5, Git never noticed the broken setting. Now that you have 1.8.5, it's pointing this out.
That covers most of the questions, but not the "do I need to fix it" one. It's likely that you have been working around the broken-ness for years now, by doing git pull *remote branch*
(e.g., git pull origin source
). If you keep doing that, it will keep working around the problem—so, no, you don't need to fix it. If you like, you can use --unset-upstream
to remove the upstream and stop the complaints, and not have local branch source
marked as having any upstream at all.
The point of having an upstream is to make various operations more convenient. For instance, git fetch
followed by git merge
will generally "do the right thing" if the upstream is set correctly, and git status
after git fetch
will tell you whether your repo matches the upstream one, for that branch.
If you want the convenience, re-set the upstream.
1git pull
uses git fetch
, and as of Git 1.8.4, this (finally!) also updates the "remote-tracking branch" information. In older versions of Git, the updates did not get recorded in remote-tracking branches with git pull
, only with git fetch
. Since your Git must be at least version 1.8.5 this is not an issue for you.
2Well, this plus a configuration line I'm deliberately ignoring that is found under remote.origin.fetch
. Git has to map the "merge" name to figure out that the full local name for the remote-branch is refs/remotes/origin/master
. The mapping almost always works just like this, though, so it's predictable that master
goes to origin/master
.
3Or, with git config
. If you just want to set the upstream to origin/source
the only part that has to change is branch.source.merge
, and git config branch.source.merge refs/heads/source
would do it. But --set-upstream-to
says what you want done, rather than making you go do it yourself manually, so that's a "better way".
Before answering, let's add some background, explaining what this HEAD
is.
First of all what is HEAD?
HEAD
is simply a reference to the current commit (latest) on the current branch.
There can only be a single HEAD
at any given time (excluding git worktree
).
The content of HEAD
is stored inside .git/HEAD
and it contains the 40 bytes SHA-1 of the current commit.
detached HEAD
If you are not on the latest commit - meaning that HEAD
is pointing to a prior commit in history it's called detached HEAD
.
On the command line, it will look like this - SHA-1 instead of the branch name since the HEAD
is not pointing to the tip of the current branch:
A few options on how to recover from a detached HEAD:
git checkout
git checkout <commit_id> git checkout -b <new branch> <commit_id> git checkout HEAD~X // x is the number of commits to go back
This will checkout new branch pointing to the desired commit.
This command will checkout to a given commit.
At this point, you can create a branch and start to work from this point on.
# Checkout a given commit. # Doing so will result in a `detached HEAD` which mean that the `HEAD` # is not pointing to the latest so you will need to checkout branch # in order to be able to update the code. git checkout <commit-id> # Create a new branch forked to the given commit git checkout -b <branch name>
git reflog
You can always use the reflog
as well.
git reflog
will display any change which updated the HEAD
and checking out the desired reflog entry will set the HEAD
back to this commit.
Every time the HEAD is modified there will be a new entry in the reflog
git reflog git checkout HEAD@{...}
This will get you back to your desired commit
git reset --hard
"Move" your HEAD back to the desired commit.
# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32
# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts if you've modified things which were
# changed since the commit you reset to.
- Note: (Since Git 2.7) you can also use the
git rebase --no-autostash
as well.
git revert
"Undo" the given commit or commit range.
The reset command will "undo" any changes made in the given commit.
A new commit with the undo patch will be committed while the original commit will remain in the history as well.
# Add a new commit with the undo of the original one.
# The <sha-1> can be any commit(s) or commit range
git revert <sha-1>
This schema illustrates which command does what.
As you can see there, reset && checkout
modify the HEAD
.
-
If you are not on the latest commit - meaning that HEAD is pointing to a prior commit in history its called detached HEAD unless that prior commit in history is the tip of a different branch. In my experience, you could say that you are detached if HEAD is not pointing to a commit that is also pointed to by any branch. This does not apply for tags. – Tim Apr 19 '16 at 10:25
-
You can be in detached HEAD and on the same time have a branch with the same commit as the HEAD of this branch. I dont understand your comment – CodeWizard Apr 19 '16 at 10:29
-
3
I have issues with your use of inline-code markup for headings 🙂 – jub0bs Dec 22 '16 at 17:07
-
Could not find any better way to emphasize it. feel free to edit. you are more than welcome – CodeWizard Dec 22 '16 at 18:04
https://stackoverflow.com/questions/4114095/how-do-i-revert-a-git-repository-to-a-previous-commit
This depends a lot on what you mean by "revert".
Temporarily switch to a different commit
If you want to temporarily go back to it, fool around, then come back to where you are, all you have to do is check out the desired commit:
# This will detach your HEAD, that is, leave you with no branch checked out:
git checkout 0d1d7fc32
Or if you want to make commits while you're there, go ahead and make a new branch while you're at it:
git checkout -b old-state 0d1d7fc32
To go back to where you were, just check out the branch you were on again. (If you've made changes, as always when switching branches, you'll have to deal with them as appropriate. You could reset to throw them away; you could stash, checkout, stash pop to take them with you; you could commit them to a branch there if you want a branch there.)
Hard delete unpublished commits
If, on the other hand, you want to really get rid of everything you've done since then, there are two possibilities. One, if you haven't published any of these commits, simply reset:
# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32
# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts, if you've modified things which were
# changed since the commit you reset to.
If you mess up, you've already thrown away your local changes, but you can at least get back to where you were before by resetting again.
Undo published commits with new commits
On the other hand, if you've published the work, you probably don't want to reset the branch, since that's effectively rewriting history. In that case, you could indeed revert the commits. With Git, revert has a very specific meaning: create a commit with the reverse patch to cancel it out. This way you don't rewrite any history.
# This will create three separate revert commits:
git revert a867b4af 25eee4ca 0766c053
# It also takes ranges. This will revert the last two commits:
git revert HEAD~2..HEAD
#Similarly, you can revert a range of commits using commit hashes (non inclusive of first hash):
git revert 0d1d7fc..a867b4a
# Reverting a merge commit
git revert -m 1 <merge_commit_sha>
# To get just one, you could use `rebase -i` to squash them afterwards
# Or, you could do it manually (be sure to do this at top level of the repo)
# get your index and work tree into the desired state, without changing HEAD:
git checkout 0d1d7fc32 .
# Then commit. Be sure and write a good message describing what you just did
git commit
The git-revert
manpage actually covers a lot of this in its description. Another useful link is this git-scm.com section discussing git-revert.
If you decide you didn't want to revert after all, you can revert the revert (as described here) or reset back to before the revert (see the previous section).
You may also find this answer helpful in this case:
How can I move HEAD back to a previous location? (Detached head) & Undo commits
In its default mode, git pull is shorthand for git fetch followed by git merge FETCH_HEAD.
When you do a git pull origin master
,
git pull
performs a merge, which often creates a merge commit. Therefore, by default, pulling from the remote is NOT a harmless operation: it can create a new commit sha that didn’t exist before. This behavior can confuse a user, because what feels like it should be a harmless download operation actually changes the commit history in unpredictable ways.
To avoid this, you need
git pull --ff-only
(or not? read on to see which one fits your requirements)
With git pull --ff-only
, Git will update your branch only if it can be “fast-forwarded” without creating new commits. If this can’t be done, git pull --ff-only
simply aborts with an error message.
You can configure your Git client to always use --ff-only
by default, so you get this behavior even if you forget the command-line flag:
git config --global pull.ff only
Note: The --global
flag applies the change for all repositories on your machine. If you want this behaviour only for the repository you're in, omit the flag.
Taken from here
In Git 1.7.0 and later, you can checkout a new branch:
git checkout -b <branch>
Edit files, add and commit. Then push with the -u
(short for --set-upstream
) option:
git push -u origin <branch>
Git will set up the tracking information during the push.
It's also worth noting that if you have an existing tracking branch already set on the branch you're pushing, and push.default
is set to upstream
, this will not do what you think it will do. It will try to push over the existing tracking branch. Use: git push -u origin mynewfeature:mynewfeature
or do git branch --unset-upstream
first.
git pull
is the same as git fetch
followed by git merge
.
To create a local branch tracking a branch on a remote, first fetch from the remote and then run git checkout
with the name of a branch that matches that on the remote:
git fetch <remote> git checkout <branch>
<remote>
is the name of the remote, for instanceorigin
.<branch>
is the name of a branch on that remote. Ifgit branch -r
shows a branch nameorigin/foo
, Git should set this up correctly if you dogit checkout foo
.
Note first that your question shows a bit of misunderstanding. origin/HEAD represents the default branch on the remote, i.e. the HEAD that's in that remote repository you're calling origin. When you switch branches in your repo, you're not affecting that. The same is true for remote branches; you might have master
and origin/master
in your repo, where origin/master
represents a local copy of the master
branch in the remote repository.
origin's HEAD will only change if you or someone else actually changes it in the remote repository, which should basically never happen - you want the default branch a public repo to stay constant, on the stable branch (probably master). origin/HEAD is a local ref representing a local copy of the HEAD in the remote repository. (Its full name is refs/remotes/origin/HEAD.)
I think the above answers what you actually wanted to know, but to go ahead and answer the question you explicitly asked... origin/HEAD is set automatically when you clone a repository, and that's about it. Bizarrely, that it's not set by commands like git remote update
- I believe the only way it will change is if you manually change it. (By change I mean point to a different branch; obviously the commit it points to changes if that branch changes, which might happen on fetch/pull/remote update.)
Edit: The problem discussed below was corrected in Git 1.8.4.3; see this update.
There is a tiny caveat, though. HEAD is a symbolic ref, pointing to a branch instead of directly to a commit, but the git remote transfer protocols only report commits for refs. So Git knows the SHA1 of the commit pointed to by HEAD and all other refs; it then has to deduce the value of HEAD by finding a branch that points to the same commit. This means that if two branches happen to point there, it's ambiguous. (I believe it picks master if possible, then falls back to first alphabetically.) You'll see this reported in the output of git remote show origin
:
$ git remote show origin * remote origin Fetch URL: ... Push URL: ... HEAD branch (remote HEAD is ambiguous, may be one of the following): foo master
Oddly, although the notion of HEAD printed this way will change if things change on the remote (e.g. if foo is removed), it doesn't actually update refs/remotes/origin/HEAD
. This can lead to really odd situations. Say that in the above example origin/HEAD actually pointed to foo, and origin's foo branch was then removed. We can then do this:
$ git remote show origin ... HEAD branch: master $ git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/foo $ git remote update --prune origin Fetching origin x [deleted] (none) -> origin/foo (refs/remotes/origin/HEAD has become dangling)
So even though remote show knows HEAD is master, it doesn't update anything. The stale foo branch is correctly pruned, and HEAD becomes dangling (pointing to a nonexistent branch), and it still doesn't update it to point to master. If you want to fix this, use git remote set-head origin -a
, which automatically determines origin's HEAD as above, and then actually sets origin/HEAD to point to the appropriate remote branch.
https://stackoverflow.com/questions/1463340/how-to-revert-multiple-git-commits
Expanding what I wrote in a comment
The general rule is that you should not rewrite (change) history that you have published, because somebody might have based their work on it. If you rewrite (change) history, you would make problems with merging their changes and with updating for them.
So the solution is to create a new commit which reverts changes that you want to get rid of. You can do this using git revert command.
You have the following situation:
A <-- B <-- C <-- D <-- master <-- HEAD
(arrows here refers to the direction of the pointer: the "parent" reference in the case of commits, the top commit in the case of branch head (branch ref), and the name of branch in the case of HEAD reference).
What you need to create is the following:
A <-- B <-- C <-- D <-- [(BCD)-1] <-- master <-- HEAD
where [(BCD)^-1]
means the commit that reverts changes in commits B, C, D. Mathematics tells us that (BCD)-1 = D-1 C-1 B-1, so you can get the required situation using the following commands:
$ git revert --no-commit D $ git revert --no-commit C $ git revert --no-commit B $ git commit -m "the commit message for all of them"
Works for everything except merge commits.
Alternate solution would be to checkout contents of commit A, and commit this state. Also works with merge commits. Added files will not be deleted, however. If you have any local changes git stash
them first:
$ git checkout -f A -- . # checkout that revision over the top of local files $ git commit -a
Then you would have the following situation:
A <-- B <-- C <-- D <-- A' <-- master <-- HEAD
The commit A' has the same contents as commit A, but is a different commit (commit message, parents, commit date).
Alternate solution by Jeff Ferland, modified by Charles Bailey builds upon the same idea, but uses git reset. Here it is slightly modified, this way WORKS FOR EVERYTHING:
$ git reset --hard A $ git reset --soft D # (or ORIG_HEAD or @{1} [previous location of HEAD]), all of which are D $ git commit
$ git reset --hard A
$ git reset --soft D # (or ORIG_HEAD or @{1} [previous location of HEAD]), all of which are D
$ git commit
Follow
51.7k3131 gold badges218218 silver badges338338 bronze badges
answered Sep 24 '09 at 8:44
272k5959 gold badges209209 silver badges228228 bronze badges
-
50
If you added files in B, C or D. the
git checkout -f A -- .
Will not delete these, you will have to do it manually. I applied this strategy now, thanks Jakub – oma Mar 31 '11 at 14:56 -
19
Those solutions are not equivalent. The first one doesn't delete newly created files. – m33lky Jan 26 '12 at 5:57
-
10
@Jerry:
git checkout foo
might mean checkout branchfoo
(switch to branch) or checkout file foo (from index).--
is used to disambiguate, e.g.git checkout -- foo
is always about file. – Jakub Narębski Jan 23 '13 at 2:34 -
121
In addition to great answer. This shorthand works for me
git revert --no-commit D C B
– welldan97 Aug 9 '13 at 12:34 -
10
@welldan97: Thanks for a comment. When writing this answer
git revert
didn't accept multiple commits; it is quite new addition. – Jakub Narębski Aug 9 '13 at 18:39
Find commit you are set at on head
Use the command:
git rev-parse HEAD
For the short version:
git rev-parse --short HEAD
a899d14f
git reset --hard <SOME-COMMIT>
git reset --hard 1a35d478
First, it's always worth noting that git reset --hard
is a potentially dangerous command, since it throws away all your uncommitted changes. For safety, you should always check that the output of git status
is clean (that is, empty) before using it.
Initially you say the following:
So I know that Git tracks changes I make to my application, and it holds on to them until I commit the changes, but here's where I'm hung up:
That's incorrect. Git only records the state of the files when you stage them (with git add
) or when you create a commit. Once you've created a commit which has your project files in a particular state, they're very safe, but until then Git's not really "tracking changes" to your files. (for example, even if you do git add
to stage a new version of the file, that overwrites the previously staged version of that file in the staging area.)
In your question you then go on to ask the following:
When I want to revert to a previous commit I use: git reset --hard HEAD And git returns: HEAD is now at 820f417 micro
How do I then revert the files on my hard drive back to that previous commit?
If you do git reset --hard <SOME-COMMIT>
then Git will:
- Make your current branch (typically
master
) back to point at<SOME-COMMIT>
. - Then make the files in your working tree and the index ("staging area") the same as the versions committed in
<SOME-COMMIT>
.
HEAD
points to your current branch (or current commit), so all that git reset --hard HEAD
will do is to throw away any uncommitted changes you have.
So, suppose the good commit that you want to go back to is f414f31
. (You can find that via git log
or any history browser.) You then have a few different options depending on exactly what you want to do:
-
Change your current branch to point to the older commit instead. You could do that with
git reset --hard f414f31
. However, this is rewriting the history of your branch, so you should avoid it if you've shared this branch with anyone. Also, the commits you did afterf414f31
will no longer be in the history of yourmaster
branch. -
Create a new commit that represents exactly the same state of the project as
f414f31
, but just adds that on to the history, so you don't lose any history. You can do that using the steps suggested in this answer - something like:git reset --hard f414f31 git reset --soft HEAD@{1} git commit -m "Reverting to the state of the project at f414f31"
https://docs.gitlab.com/ee/user/project/merge_requests/revert_changes.html
Reverting changes all tiers
You can use Git’s powerful feature to revert any commit by clicking the Revert button in merge requests and commit details.
Reverting a merge request
The Revert button is available only for merge requests created in GitLab 8.5 and later. However, you can still revert a merge request by reverting the merge commit from the list of Commits page.
The Revert button is shown only for projects that use the merge method “Merge Commit”, which can be set under the project’s Settings > General > Merge request. Fast-forward commits can not be reverted by using the merge request view.
After the merge request has been merged, use the Revert button to revert the changes introduced by that merge request.
After you click that button, a modal appears where you can choose to revert the changes directly into the selected branch or you can opt to create a new merge request with the revert changes.
After the merge request has been reverted, the Revert button is no longer available.
Reverting a commit
You can revert a commit from the commit details page:
Similar to reverting a merge request, you can opt to revert the changes directly into the target branch or create a new merge request to revert the changes.
After a commit is reverted, the Revert button is no longer available.
When reverting merge commits, the mainline is always the first parent. If you want to use a different mainline, you need to do that from the command line.
Here’s an example to revert a merge commit using the second parent as the mainline:
git revert -m 2 7a39eb0
https://docs.gitlab.com/ee/topics/git/rollback_commits.html
Rollback commits all tiers
Undo Commits
-
Undo last commit putting everything back into the staging area:
git reset --soft HEAD^
Add files and change message with:
git commit --amend -m "New Message"
Undo last and remove changes:
git reset --hard HEAD^
Same as last one but for two commits back:
git reset --hard HEAD^^
Don’t reset after pushing
Reset Workflow
- Edit file again ‘edit_this_file.rb’
- Check status
- Add and commit with wrong message
- Check log
- Amend commit
- Check log
- Soft reset
- Check log
- Pull for updates
- Push changes
Commands
# Change file edit_this_file.rb git status git commit -am "kjkfjkg" git log git commit --amend -m "New comment added" git log git reset --soft HEAD^ git log git pull origin master git push origin master
Note
git revert
vsgit reset
- Reset removes the commit while revert removes the changes but leaves the commit
- Revert is safer considering we can revert a revert
# Changed file git commit -am "bug introduced" git revert HEAD # New commit created reverting changes # Now we want to re apply the reverted commit git log # take hash from the revert commit git revert <rev commit hash> # reverted commit is back (new commit created again)
HOW TO REVERSE A COMMIT - GITLAB
https://stackoverflow.com/questions/40245767/delete-commit-on-gitlab
Supose you have the following scenario:
* 1bd2200 (HEAD, master) another commit * d258546 bad commit * 0f1efa9 3rd commit * bd8aa13 2nd commit * 34c4f95 1st commit
Where you want to remove d258546 i.e. "bad commit".
You shall try an interactive rebase to remove it: git rebase -i 34c4f95
then your default editor will pop with something like this:
pick bd8aa13 2nd commit pick 0f1efa9 3rd commit pick d258546 bad commit pick 1bd2200 another commit # Rebase 34c4f95..1bd2200 onto 34c4f95 # # Commands: # p, pick = use commit # r, reword = use commit, but edit the commit message # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit # f, fixup = like "squash", but discard this commit's log message # x, exec = run command (the rest of the line) using shell # # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST. # # However, if you remove everything, the rebase will be aborted. # # Note that empty commits are commented out
just remove the line with the commit you want to strip and save+exit the editor:
pick bd8aa13 2nd commit pick 0f1efa9 3rd commit pick 1bd2200 another commit ...
git will proceed to remove this commit from your history leaving something like this (mind the hash change in the commits descendant from the removed commit):
* 34fa994 (HEAD, master) another commit * 0f1efa9 3rd commit * bd8aa13 2nd commit * 34c4f95 1st commit
Now, since I suppose that you already pushed the bad commit to gitlab, you'll need to repush your graph to the repository (but with the -f
option to prevent it from being rejected due to a non fastforwardeable history i.e. git push -f <your remote> <your branch>
)
Please be extra careful and make sure that none coworker is already using the history containing the "bad commit" in their branches.
Alternative option:
Instead of rewrite the history, you may simply create a new commit which negates the changes introduced by your bad commit, to do this just type git revert <your bad commit hash>
. This option is maybe not as clean, but is far more safe (in case you are not fully aware of what are you doing with an interactive rebase).