# Figure out which commit you want to edit by getting its SHA.
git log
# Start an interactive rebase ($SHA = your commit's SHA and the ^ is important!).
git rebase --interactive $SHA^
# [Change 'pick' to 'edit' for your commit and save the buffer]
# [Add your changes with git add -p, etc.]
# Change the commit and optionally add --no-edit if you want to keep the existing message.
git commit --amend
# Finalize and apply the rebase.
git rebase --continue
# Or cancel the rebase and go back to what it was like before you started rebasing.
git rebase --abort
From Nick Janetakis – Change a Git Commit in the Past with Amend and Rebase Interactive (https://nickjanetakis.com/blog/change-a-git-commit-in-the-past-with-amend-and-rebase-interactive)
Category Archives: Version control
Rebasing a git branch that has a pull request
I recently wanted to merge a pull request in a git repository, where a lot had changed in master since the pull request was opened. The owner of the repository wanted me to do a rebase
instead of merge
, so I this is what I figured out:
Step 1) Update your branches.
Update all branches from the remote repository to make sure everything is up to date (newfeature
is your branch with the pull request, develop
is the branch it should be merged to):
$ git checkout develop
$ git pull
$ git checkout newfeature
$ git pull
Step 2) Perform the rebase:
git rebase develop
...
CONFLICT (content): Merge conflict in <bla>
error: Failed to merge in the changes.
Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".
After each time git stops with an error, resolve the conflicts and use git add
. Do not commit anything during the rebase. Instead, just continue the rebase until everything is fine.
git rebase --continue
Now, you will have some modified files. You can make some final changes if necessary, and then commit your changes:
git add <bla> <blubb>
git commit -m "Resolve conflicts from rebase"
Step 3) Push your changes to the remote repository.
Unfortunately, using only git push
will not work, but give the message “Updates were rejected because the tip of your current branch is behind hint: its remote counterpart. Integrate the remote changes (e.g. hint: ‘git pull …’) before pushing again.”
Do NOT use git pull
at this moment!!
Instead, force push your changes onto the remote repository:
git push --force-with-lease
Now, you have overwritten the history on the remote repository with your local history. That is fine. Now you can merge the pull request and delete the branch and go on your merry way.
Step 4) BUT…
If you are not yet at the place where you merge the pull request, but someone else wants to work with the branch, that person is in trouble! A normal git pull
on the branch will fail, because history was changed! What you need to do is:
git pull --rebase
See also: Gerald Versluis: Git Rebase: Don’t be Afraid of the Force (Push)
Throw away your change and reset a git branch to remote
Sometimes, you do something really stupid and just want to get rid of it. Or you are suddenly in the middle of a complicated merge and don’t really know why anymore (“But I didn’t change anything!”). In this case, if you are sure you want to throw away everything in your local branch and just want to be at the same status as the remote branch, this is your rescue:
git reset --hard origin/<branchname>
But be careful, the --hard
option deletes all changes that you have made without recovery.
Copy a folder (with history) to a different git repository
No idea if this is the best way to do it, but for me it worked to follow the instructions by mcarans on Stackoverflow about How to move files from one git repo to another (not a clone), preserving history
Copying changes into your branch (`rebase`)
Situation: You create a branch newfeature
from develop
at point X to develop your super cool new feature. You do some commits in your branch. Meanwhile there have been some changes in develop
that you want to have in your new branch. To do this, rebase your branch. Basically, this replays every commit in your branch on top of the current state in the branch you do the rebase against. Do a rebase as follows:
$ git checkout develop Switched to branch 'develop' $ git pull ... $ git checkout newfeature Switched to branch 'newfeature' $ git rebase develop First, rewinding head to replay your work on top of it... Applying: intermediate commit
Before doing this, you need to commit or stash all your changes. During the rebase, if there are conflicts, you need to resolve them one by one for every commit in your branch. You can simplify conflict resolution in one of two ways: use the flag -Xours
to always take the version in the branch that you are rebasing against (develop
in our example); or use the flag -Xtheirs
to always take the version in your branch.
When there are conflicts, you need to resolve them. To resolve a conflict, edit the file that has the conflict and remove all places indicated by <<<<<
. Then add
all the modifications to the staging area. You can commit, but you do not have to. For things that you know they will be resolved later on anyway, you can also chose git rebase --skip
to ignore the problem (e.g., if a file was deleted in your branch and edited in the other and you know you copied the new file into your branch in a later commit). At the end, there may be things you need to commit to finalize the merge, then the rebase is complete. Don’t forget to push the result to your remote branch!
How to undo a commit in git
Really throw away everything (all changes!) from the last commit:
git reset --hard HEAD~1
Delete the commit, but preserve all changes:
git reset --soft HEAD~1
For more details and explanations, read this excellent answer by Ryan Lundy on stackoverflow.
A successful Git branching model
From the category "bookmarks/links": A successful Git branching model
SVN ignore
Sometimes you have files in your SVN folder that you don’t want to include in the svn. For example let’s say svn status
gives the following result:
M data/data.tex ? data/data.aux ? mydoc.bbl ? mydoc.blg ? mydoc.log ? mydoc.out M mydoc.tex M mydoc.pdf ? mydoc.toc
All these files are temporary files that LaTeX creates and I don’t want them in my SVN. Is there some way that I don’t have to see them anymore everytime I check what I have changed? YES! There’s a SVN property that you can set for a folder which is called "ignore".
So to ignore all files with the extension aux
in the current directory, you can do this:
svn propset svn:ignore *.aux .
But doing that for every one of the five filetypes is already too much for me. Also, the setting applies only to one folder, I would need to repeat the same thing for each subfolder! Fortunately, you can (a) specify a file which contains the stuff to be ignored and (b) call the command recursively on all subfolders. So I write all the things I want to ignore (*.aux, *.bbl, *.blg, *.out, *.toc) into the file ignorethisyoustupidsvn.txt
(one pattern per line) and execute the following command:
svn propset svn:ignore -R -F ignorethisyoustupidsvn.txt .
Now let’s do svn status
again:
M data/data.tex M mydoc.tex M mydoc.pdf
Yay 🙂
Links: SVN properties documentation, Getting svn to ignore files and directories (superchlorine)
The most important commands for SVN
Here are the most important commands for using SVN in the command line on Linux. You have to be inside your local folder where you put the svn else it won’t work (most common source for error “Skipping .'” or “. is not a working copy”).
update
To update your local working copy to the newest version that exists on the server (ALWAYS do this before you start to change things or your teammates will kill you!!):
svn update
add
Files you move into the local working copy folder are not added automatically. If you want the file to be part of the SVN, you have to add it. It works for multiple files or folders, too.
svn add
delete
To delete files from the repository, first mark them for deletion:
svn rm
On the next commit, the file will be deleted from the repository and from your local copy! If you want to keep the local copy, do
svn rm --keep-local
revert
With revert, you can undo pending changes in your working copy (e.g. add, delete) before the next commit.
svn revert
Also handy in case you forgot what local changes you made and you want to return to the latest “safe” version from the repository.
Note that this does NOT enable you to go back to a previous already-commited version. To do that, you can checkout the specific version of your repository at some other place (with the option -r) and manually get what you need or follow the procedure outlined here.
commit (changes to the repository)
If you have changed a file, added or deleted something and want to put the changes into the SVN you have to commit it, without that the changes are only in your working copy and not on the server!
svn ci -m ""
log
It is good practice to write log messages with commits. You can review these log messages with
svn log
You should do an update of your working copy before this command, otherwise you will not get all messages. In case this is a lot of messages, you can add a limit, e.g., display only the latest 5 log entries:
svn log -l 5
status
To see which files of your working copy haven’t been committed yet:
svn status
Common SVN status codes:
diff
To see what has changed in a file from the last version to the current version:
svn diff
More resources: You can always use “svn help” to see what else is there or take a look at the excellent book.
A typical SVN session
We assume you have created a working copy and there is already some content in your SVN that you share with others. All of this assumes that you are using some linux shell and are in the folder of your working copy. If you are in the wrong folder else it won’t work (most common source for error “Skipping .'” or “. is not a working copy”).
First thing you do is update (i.e. get the latest changes from the server), in case your teammates changed something. You don’t want to work on an old version!
svn update
Then you open some files, change some things (in "main.adb"), add a new file ("list.adb") and delete a different file ("array.adb"). After two hours work you need a coffee and it’s always a good idea to commit (i.e. send your changes to the server) before taking a longer break. Before you commit, you want to know what changed:
svn status
The message you get will look more or less like this:
M main.adb ? list.adb ! array.adb
This means, you have modified "main.adb", there is a file "list.adb" that SVN doesn’t really know about and "array.adb" should be there, but SVN cannot find it.
If you just commit, only "main.adb" will get changed and on the next update "array.adb" will be restored in your working copy. Why? Because you need to tell SVN explicitly that you want a file to be added or deleted. So let’s do that.
svn add list.adb svn del array.adb
Now let’s check the status again, the result will be:
M main.adb A list.adb D array.adb
We are satisfied and commit the whole thing:
svn ci -m "Replaced array with list, added list.adb, deleted array.adb"
It is always a very good idea to write a meaningful commit message (the parameter -m), so that your teammates know what has been changed. It also makes it easier to go back to a specific version, e.g. the version just before you removed the array.