Git: restore my changes which were amended to merge commit - git-commit

I accidentally amended merge commit instead of creating new one. Now I don't know how to extract the changes to normal commit which I can push. The changes will show up in gitk, but will not appear in format-patch. Please, help.

You have 2 SHAs that are of interest here - the original merge commit, and the amended merge commit. What you want to do is git reset your HEAD to the original merge commit, while preserving your index and working directory. You can then create a new commit hanging off the merge commit.
Use
git reflog
to find the SHA of the original merge commit
reset to the commit with
git reset ORIGINAL_MERGE_COMMIT_SHA or directly from reflog with git reset HEAD#{X} where X is 1 or the position in the reflog that represents the merge commit.
You should now be ready to git commit your original changes and don't pass in --amend here and you will create a new commit.

I've found one way which works:
git diff HEAD~1 > p.patch
git checkout master
git checkout -b branch-name
Manually edit p.patch to remove unrelated changes from merge.
git apply p.patch
But I suspect there is a much easier/better way to do it.

This worked for me:
Get the SHAs of both the original merge commit and the amended merge commit
git reset --hard xxx where xxx is the amended merge commit SHA
git reset --soft yyy where yyy is the original merge commit SHA
That left me with my accidentally-amended changes staged.

Related

How to do git-review in this case?

I did checkout to branch branch1 in origin, and after that i edited the file a.file by adding line to this file. After that, I did git add to this file, and then git commit -s.
Then i did git status to check what i get, and I got the following message:
On branch branch1
Your branch is ahead of 'origin/branch1' by 1 commit.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
And then I tried to do git-review in order to upload the commit to the remote-repository.
But, after that I did git-review I got the following message:
Error running git rebase --rebase-merges -i remotes/gerrit/master
Rebasing (1/4)
Rebasing (2/4)
Rebasing (3/4)
Auto-merging a.file
CONFLICT (content): Merge conflict in a.file
...
...
What is in fact the problem and how can I fix that problem so that I will upload this commit on the origin branch (and not about "Topic" with the name of the origin-branch name) ?

Git Working tree is dirty

If I execute git review git shows me "Working tree is dirty" error.
I made a commit and I sent to review. After that I update the branch from the upstream using git pull. Now I need to modify the previous commit message, so, there are my commands:
1) git reset <id-of-the-commit-to-modify>
2) git commit --amend
vim was opened to modify my commit. But here appears information about my commit and others commits as well and I don't know why. However, I modified the commit message and write/close vim.
3) git review
This command raise this error:
Errors running git rebase -i remotes/gerrit/master
doc/source/configuration.rst: needs update
doc/source/developing.rst: needs update
tools/sample_data.sh: needs update
Working tree is dirty
What I doing wrong?
git reset <id-of-the-commit-to-modify> without a mode option is defaulted to --mixed . This is what is said on the reset in the manual
--mixed
Resets the index but not the working tree (i.e., the changed files are preserved but not marked for commit) and reports what has not been updated. This is the default action.
This basically means your index has been reset, but not your working files. So all files that you pulled from upstream are still left in your working tree.
You should use git reset --hard <id-of-the-commit-to-modify> This will reset your index and remove the files that came with your upstream pull. You can then amend your commit and send it for review.
once a change was pushed to Gerrit, then it can be fetched directly. On the Gerrit review board you can find the chekcout command for each patchset, something like this: git fetch ssh://ebalbar#gerrit.ericsson.se:29418/TCC/TitanSim refs/changes/86/129686/5 && git checkout FETCH_HEAD Then, you can amend the commit as usual, and push the new change again. AFter that checkout your local branch and reset it with the remote branch: git reset --hard origin/<remote_branch> also a nice answer how to modify a commit which was pushed directly.

forget to move to another branch than master with Git

I'm using Git with a rails project.
Today i make a lot of changes and i forget to move to another branch, so all these changes are in the master branch but not committed yet.
this is what i get when i do git status command :
# On branch master
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: app/controllers/sessions_controller.rb
# modified: app/controllers/users_controller.rb
# modified: app/helpers/sessions_helper.rb
# modified: app/models/user.rb
# .....
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# app/assets/javascripts/password_resets.js.coffee
# app/assets/stylesheets/password_resets.css.scss
# app/controllers/password_resets_controller.rb
# .....
# ......
no changes added to commit (use "git add" and/or "git commit -a")
how i can solve this error and move all these untracked files from master to another branch already exists ? thank you.
Just create a new branch and then commit, e.g.:
git checkout -b my_branch
git commit -am "My commit."
If there are no commits marked C1, C2, etc. below
You're in the simple case; just use Henrik N's answer.
If there is a tracking branch
Your updated question/comments suggests that you have both committed changes and uncommitted changes, and you did them all on some tracking branch, such as master that tracks origin/master or devel that tracks origin/devel, but that you have not pushed any of them yet. (I'll assume master but you can just change each master to the feature/development/whatever branch name below.)
As a diagram, your repo's commit tree and working directory/index now looks something like this:
M1 -...- M5 -- M6 <-- origin/master
\
C1 -- C2 <-- master, HEAD=master
\
i, w <-- "index" and working-tree files
Here i is the stuff in the index (git add dir/file1, git rm file2, etc), which git status shows as changes to be committed, and w is the stuff in your working directory that git status shows as changes not staged for commit.
Here's what you want it to look like:
M1 -...- M5 -- M6 <-- master, origin/master
\
C1 -- C2 <-- my_branch, HEAD=my_branch
\
i, w <-- "index" and working-tree files
Remember that branch labels are like sticky-notes ("yellow stickies" or "Post-It® notes" or whatever): they have a name written on them and are pasted on to a commit. So what you have to do is add a new sticky-note, my_branch, pointing to commit C2, and also make HEAD refer to the new branch name:
git checkout -b my_branch
This uses the previous value of HEAD to name the commit that my_branch is pasted-on-to. Since that commit is C2 you now have both master and my_branch here. It then rewrites HEAD to point to the name my_branch. Now you have:
M1 -...- M5 -- M6 <-- origin/master
\
C1 -- C2 <-- master, my_branch, HEAD=my_branch
\
i, w <-- "index" and working-tree files
Now you need to move the sticky-note labeled master to point back where origin/master points. There are two ways to do this, with git reset, or with git branch. Using git reset is harder, so let's do it with git branch:
git branch -f master origin/master
The -f (force) flag tells git branch to change an existing sticky-note, rather than failing because it exists, and origin/master gives which commit master should point-to: so git peels the label off C2 and pastes it on M6, and you have the setup you wanted (the 2nd diagram).
Summary: it's just two commands:
git checkout -b my_branch # create new branch and change HEAD
git branch -f master origin/master # restore master to origin/master
You're now ready to check in changes as usual, on branch my_branch. (git add, git rm, git commit as needed.) That will add a new commit C3:
M1 -...- M5 -- M6 <-- master, origin/master
\
C1 -- C2 -- C3 <-- my_branch, HEAD=my_branch
What if there is no tracking branch?
Well, that's OK, it's just a little harder. Go back to the "have now" and "want" diagrams. In these diagrams, the commit I labeled M6 is the one you want master to name. You now have to find M6. Commits have these long hexadecimal-numeric (SHA-1) "true names" that never change, like 5e013711f5d6eb3f643ef562d49a131852aa4aa1 for example. (git rev-parse HEAD will show the "true name" for the current, i.e., HEAD, commit.) You can find that "true name", or you can find some alternate or abbreviated name that also names the same thing.
There are a whole lot of options for names, but let's stick with numbers that come out of git log and git log --oneline. The latter gives you something like this:
97206f5 peerish: set socket options earlier
4881af5 add semtest.c
b3f8bea fdm: repair example
where the number is an abbreviated SHA-1 and the text is the first line of the commit message. Since the logs are shown in reverse order, the top line is the most recent commit (C2 in the example above), and then each next line is the next one back (well, it's more complicated with merges, but close enough).
Let's say that from the above, you can immediately tell that the commit I labeled M6 is b3f8bea, i.e., that you need to skip two commits. Simply supply that value as the last argument to git branch:
git branch -f master b3f8bea
If your repo is huge and old, or has a lot of merge commits, you might want your logs to include more "decoration". I got these aliases from somewhere long ago:
[alias]
lol = git log --graph --decorate --oneline
lola = git log --graph --decorate --oneline --all
so that I can run git lol and git lola.
Alternatively, if you know for sure there were exactly two commits, master~2 (and in this case, after adding my_branch, my_branch~2) will get you the same SHA-1. The git rev-parse command shows you exactly which SHA-1 any given name "means". In one repo I have here, HEAD~2 is the same as origin/featureX:
$ git rev-parse HEAD~2
0f5a13497dd3da8aff8e452c8f56630f83253e79
$ git rev-parse origin/featureX
0f5a13497dd3da8aff8e452c8f56630f83253e79
but in general git log (or git lol, etc.) will get you the raw SHA-1 and you can add labels from there, as needed.
You simply need to create new branch.
Once you create a branch all the changes will be in the new branch.
and then clean your old stuff from master
// Checkout new branch
git checkout -b my_branch
// Prepare files for commit
git add .
// Commit changes
git commit -m "Your commit message"
// delete the dirty master
git branch -D master
// Now we are going to clean your changes from the master branch
// the -f is important in case you skipped the previous command to delete your master
git checkout -f master

Merge branch 'user' in git log

I am working in ROR in a Ubuntu machine. I had done some changes in my files and commited it with a msg.
Now when i checked with the git log thing..
I am getting a new msg rite above my commited message as Merge Branch 'myname' .. Why is it so coming like this ?
Please give suggestions..
EDIT :
Date: Mon Oct 11 11:42:29 2010 +0530
Merge branch 'aruna'
You shouldn't worry about git "merge commits". The merge commit just contains the differences between your local version of the branch and the remote version of the branch. (hence why they appear when you pull and there were any changes).
Rebasing, exactly as suggested in pawien's answer is a good way to avoid those, but only if you know what you are doing. Rebasing should only ever be used in a local feature branch (a branch that you never push), because it re-writes all the commits that have been commited to the feature branch. rebasing a branch that has other peoples commits in it can accidentally delete commit history if you don't know what you're doing.
This is a git question and is not related to Rails.
So - it is quite normal in git and it will happen in situation like this
- aruna: X -> Y
/
master: A -> B -> C -> D .....
when you merge aruna with master (either by doing merge aruna on the master branch or just by pulling [pull is "two in one" command - it makes fetch & merge]) you will get new "merge" node that is the merge of both branches (nodes C, D & X, Y)
As you are asking I bet that you don't like it. So the possible solution is to rebase the aruna branch instead of merge. For example:
# normally commit everything in your aruna branch
git checkout aruna
git add ...
git commit -m "..." ...
git checkout master
git pull # it will just fetch as there is nothing to be merged
git checkout aruna
git rebase master # and solve possible conflicts
git checkout master
git merge aruna # it will *not* make the "merge node"
git push
EDIT:
As others mentioned - the rebasing is really no option if you already pushed the branch or you have other people who pulled your branch.
But still - rebasing is an option if you are merging your local private branch. Which is a quite common scenario. And as your branch is named "aruna" (your name) I thought that's the case. But as I think about it again there is no reason to think so :-)
While rebasing (local feature branch), you will lost some part of history that says that you did your commits in parallel. But the trade-off is that you will have simpler narrow tree.

How to switch repositories from one to the next

I was using a github repository from a previous developer.
I am the only coder on this project, so I forked the project over to my own github repository.
Now I would like to commit soley to my repo.
Unfortunately, I realized that I never changed my .git/config , so I was still committing to the old repo. I just changed it to the appropriate url, and when I type :
$> git status
It returns :
=> Working directory clean.
But I know its not because I have several commits I've made. So my local box has different code then what it is pointed to on my repository.
My question is this. Obviously I'm halfway through the process of doing this. Do I need to re-fork to update, and then I'm good. Or is there a special command I need to run to let my local box know its 'git status' command is targeting a new repo to compare itself to? Equally, am I missing something else very important :D ?
Thank you everyone.
You can use git remote to manage your remote
rename origin
git remote rename origin old_origin
add a new origin
git remote add origin git://github.com/my/forked/repo.git
git fetch origin # will create all the remote branches references
# in your local repo
You can also easily setup a new upstream for your current master branch (git 1.7 and more):
git branch --set-upstream master origin/master
The "nothing to commit (working directory clean)" message of git status won't prevent you to push.
After changing the origin, you should see:
$ git status
# On branch master
# Your branch is ahead of 'origin/master' by xxx commits.
#
nothing to commit (working directory clean)
That means you have some commits to push to your new origin.
Note: "git remote"(man) rename failed to rename a remote without fetch refspec, which has been corrected with Git 2.39 (Q4 2022).
See commit 5a97b38 (22 Sep 2022) by Jeff King (peff).
(Merged by Junio C Hamano -- gitster -- in commit 20a5dd6, 10 Oct 2022)
remote: handle rename of remote without fetch refspec
Reported-by: John A. Leuenhagen
Signed-off-by: Jeff King
We return an error when trying to rename a remote that has no fetch refspec:
$ git config --unset-all remote.origin.fetch
$ git remote rename origin foo
fatal: could not unset 'remote.foo.fetch'
To make things even more confusing, we actually do complete the config modification, via git_config_rename_section().
After that we try to rewrite the fetch refspec (to say refs/remotes/foo instead of origin).
But our call to git_config_set_multivar() to remove the existing entries fails, since there aren't any, and it calls die().
We could fix this by using the "gently" form of the config call, and checking the error code.
But there is an even simpler fix: if we know that there are no refspecs to rewrite, then we can skip that part entirely.
git status only shows you the status of your working directory, not the entire repository. It seems like you only need to change the remotes that git push and git pull use by default. Open up .git/config and find your branch.<branch> entries and change them, as well as your remote.<remote> entries. For example, your master entry may look like this:
[branch "master"]
remote = origin
merge = refs/heads/master
Just change remote to reference your (forked) remote.
Also, your remote entry may look like the following:
[remote "myremote"]
url = git://github.com/me/repo.git
fetch = +refs/heads/*:refs/remotes/origin/*
You can add a push entry so that your master branch is pushed by default:
[remote "myremote"]
url = git://github.com/me/repo.git
fetch = +refs/heads/*:refs/remotes/origin/*
push = master
In whole, but I should include it in this answer. Is that before hand I manually altered my .git/config to include my new repository url. That's why I didn't have to rename or add any origin as Von suggested.
Then I just guessed this and performed
$> git fetch origin
Which returned
From git#github.com:gotoAndBliss/hq_channel
17326ca..043d395 master -> origin/master
* [new branch] panda_streaming -> origin/panda_streaming
+ 6ec9bf8...becbcc6 testing -> origin/testing (forced update)
Then on git status I got
# On branch testing
# Your branch is ahead of 'origin/testing' by 9 commits.
I git pushed origin testing, and I think I'm on target now.

Resources