I'm doing a pull origin some_branch and can see there are a lot of changes. Eventually I don't mind if their erase all mine.
How can I accept them all instead or using mergetool and merge files one by one?
Just:
git clone $url
Seriously! That's the best way.
You could do all sorts of git reset and git branch commands to move the refs, but the only purpose would be to keep your commits somewhere in your local repository for future reference. If that's the goal, just keep the whole repository as is, and re-clone the origin.
To accept all changes on just one branch, foo:
git checkout foo
git fetch origin +refs/heads/foo:refs/remotes/origin/foo
git reset refs/remotes/origin/foo
foo will now point at the same commit as foo on origin. If you want to blow away the files in your working directory, add --hard to git reset. If you want to merge first, replace fetch with pull.
You may have a bunch of dangling commits in your local repo, which git may clean-up someday, but for awhile you can still access them via the reflog.
Or:
git status | grep "both " | cut -f2 | cut -f11 -d" " | xargs git checkout --theirs
git status | grep "both " | cut -f2 | cut -f11 -d" " | xargs git add
which forces accepting all conflicting remote files.
Here's the approach I used, which seems to be OK. I have a branch called "theirs" which contains the new version of everything in the remote. A version named "ours" is my work based on a long-ago version of theirs, which too many irrelevant changes but many additions (new subdirectories of sites/all) that I want to keep.
git checkout ours
git checkout theirs -- *.php *.txt *.config modules themes includes scripts
git commit -m "New version with all new key files from 'theirs'"
As long as I got the list of files and directories in the second checkout correct, this should be fine.
If I wanted the history to be based on the "theirs" branch I might want to do this the other way round.
Related
In Git - with it's immutable changeset objects and mutable refs - I know that the original commits remain, which gives me a warm fuzzy feeling after an 'oops' "history rewriting" moment.
For example, after a "history rewriting" git rebase the original changesets (cbe7698, 09c6268) are still there and a new changeset (08832c0) was added. I can easily restore/access the other changesets until such a time as they are pruned.
$ git log --oneline --graph --decorate $(git rev-list -g --all)
* 08832c0 (HEAD -> master) Added bar and quxx to foo.txt
| * cbe7698 Added quxx to foo.txt
| * 09c6268 Added bar to foo.txt
|/
* 895c9bb Added foo.txt
Likewise, even a git commit --amend preserves the original/amended commit (d58dabc) and adds a new changeset:
$ git log --oneline --graph --decorate $(git rev-list -g --all)
* d9bb795 (HEAD -> master) Added cats and dogs to pets.txt
| * d58dabc Added cats to pets.txt
|/
* 08832c0 Added pets.txt
However, what happens in Hg after a "history rewriting" operation?
Do the original commits cease to exist? And if they still do exist, how can they be accessed and/or recovered?
It depends on whether you have the evolve extension installed or not. If you have the evolve extension installed, the only command that will actually remove revisions from the repository is hg strip; other commands leave the original commits in place, but hide them. You can see them with hg log --hidden (or other commands with the --hidden flag). If you want to get rid of them permanently, hg strip --hidden -r 'extinct()' can be used [1].
Most people, however, will just be using base Mercurial. In this case (and for hg strip even with evolve), the removed changesets will be stored as bundles in .hg/strip-backup. A Mercurial bundle is basically a read-only overlay repository; you can use hg log -R, hg tip -R, hg incoming, hg pull, etc. on it. This is all you need in principle, but it can be a bit cumbersome typing out the paths.
For convenience, Facebook has published a number of experimental extensions for Mercurial. Among them, the backups extension provides a convenience command (hg backups) that basically lists the commits in each bundle in .hg/strip-backup (similar to what hg incoming with an appropriate template would do) and hg backups --recover to pull in the changesets from the stripped commits (similar to what hg pull would do).
[1] Note that even then, a backup will be stored in .hg/strip-backup. If you want to get rid of them really permanently, you will also have to remove that backup.
It is a very simple and stupid question,
I am working on 2 tasks and modified 2 sets of files in the code.
Now when I type 'hg ci', it checks in all the files. Can I remove certain files from the checkin i.e. do checking for only one task?
If I remove the files in the 'check in message' will they be removed from the checkin
Thanks for all the answers
This seems like a big flaw, My use case is very simple and general. Most of the time dev are working on various tasks , some are ready , some are not, bug fixes etc.
Now the only simple solution seems to be multiple local repos or clones
Use hg ci <files>... to commit only certain files in your working directory.
If you want to pick file by file you can use the record command. It ships with mercurial, but you have to turn it on if you want to use it by putting: record= in the [extensions] section of your ~/.hgrc.
It goes hunk by hunk, but you can answer for a whole file:
y - record this change
n - skip this change
s - skip remaining changes to this file
f - record remaining changes to this file
d - done, skip remaining changes and files
a - record all changes to all remaining files
q - quit, recording no changes
? - display help
I'll point out that if you're committing some files but not others it's certain that you've not run your test suite on the one change without the other, but maybe that doesn't apply in your case.
This isn't possible with mercurial out of the box. As have been suggested there are several ways of selecting what files you want to commit. To get this function via the commit message template, you would need an extension or a shell script wrapping the commit command. Here's one way to do that:
[alias]
ci = ! hg-partial-commit
hg-partial-commit:
#!/bin/sh
# partial commit
edit=$(mktemp ${TMPDIR:-/tmp}/$(basename $0).XXXXXXXXXXXX)
filelist=$(mktemp ${TMPDIR:-/tmp}/$(basename $0).XXXXXXXXXXXX)
logmessage=$(mktemp ${TMPDIR:-/tmp}/$(basename $0).XXXXXXXXXXXX)
cleanup="rm -f '$edit' '$filelist' '$logmessage'"
trap "$cleanup" 0 1 2 3 15
(
echo user: $(hg debugconfig ui.username)
echo branch: $(hg branch)
hg parents --template 'parent: {rev}:{node|short} {author} {date|isodate}\n'
echo
echo 'Enter commit message. Select files to commit by deleting lines:'
hg status 'set:not unknown()' | sed -e 's/^/#/'
) | sed -e 's/^/HG: /' >"$edit"
${VISUAL:-${EDITOR:-vi}} "$edit"
egrep -v '^HG:' "$edit" >"$logmessage"
egrep '^HG: #' "$edit" | cut -c8- >"$filelist"
hg commit -l "$logmessage" "listfile:$filelist"
$cleanup
The real problem here is the fact that you're doing changes related to different tasks jumbled together. Mercurial has a few ways you can keep things separate.
Task Branches
Suppose you've been working on a task and you've checked in a few times since you last pulled, but things aren't ready to share yet.
o----o----B----o----o----o
Here, B is the revision where you started your changes. What we do is (after making sure our current changes are checked in):
> hg update -r B
<do our work on the other task>
> hg commit
We've now created a new branch with the changes for this task separated from the changes for our original task.
o----o----B----o----o----o
\
----o
We can do this for as many different tasks as we want. The only problem is that sometimes remembering which branch is which can be awkward. This is where features like bookmarks come in useful. A bookmark is a tag which moves forward as commits are made so that it always points at the head of a branch.
Mercurial Queues
MQ adds the ability to work on changes incrementally and move between them by pushing and poping then off a stack (or "Queue" I guess). So if I had a set of uncommitted changes that I needed to split up I'd:
> hg qrecord taska
> hg qrecord taskb
> hg qrecord taskc
I'd use the record extension (or more likely the crecord extension) to select which parts of files I want to select.
If I needed to go back to taska and make some changes:
> hg qpop; hg qpop # pop two off the queue to go back to task a
<Do changes>
> hg qrefresh # update task a with the new changes
When I want to turn the queue into normal changesets:
> hg qpush or hg qpop # get the changes I want converted onto the queue
> hg qfinish -a # converts mq changes to normal changesets
There's other methods too, but that will do for now.
You will unavoidably have to either specify the files that you want to add or the files you want to leave out. If you have a lot of files, as you indicate above, the following steps will simplify the procedure (I'm assuming a UNIX-ish system here, Windows would be slightly different).
First, generate a list of changed files:
hg status -mard -n >/tmp/changedlist.txt
The -mard options will list all files that were modified, added, removed, or delated. The -n option will list them without the status prefix so that all you have is a raw list of files.
Second, edit /tmp/changedlist.txt with your favorite text editor so that it contains only the files you wish to commit.
Third, commit these files:
hg commit `cat /tmp/changedlist.txt`
You will be able to review the files to be committed before actually performing the commit.
Alternatively, you can add more files to a commit incrementally by using
`hg commit --amend file...`
Here, hg commit --amend will not create a new commit, but add the new files to the existing commit. So, you start out with committing just a couple of files, then incrementally adding more until you are done. This still requires you to type all of them in.
For yet another alternative, you can use Mercurial Queues to split a commit in more sophisticated ways, but that's a bit more of an advanced topic.
I am aware of Mercurial for Beginners: The Definitive Practical Guide and answers like Mercurial merge branches? (abort: push creates new remote branches)
Here I've inadvertently created a situation where Mercurial wants to create a new remote head. What's the best way to undo this, and leave little or no trace of this mistake on the remote side?
###> hg push
pushing to http://example.com
searching for changes
abort: push creates new remote heads on branch 'default'!
(did you forget to merge? use push -f to force)
###> hg revert --all -r tip
###> hg update -C
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
###> hg incoming
comparing with http://example.com
searching for changes
no changes found
###> hg summary
parent: 488:e3db024fe901 tip
Misc.
branch: default
commit: (clean)
update: 6 new changesets, 2 branch heads (merge)
###> hg pull
pulling from http://example.com
searching for changes
no changes found
###> hg glog
# changeset: 488:e3db024fe901
| tag: tip
| summary: Misc.
|
o changeset: 487:b207579b9d41
| parent: 480:ce775708800c
| summary: Misc.
|
| o changeset: 486:59a7a5b34c7f
| | user: other
| | summary: fixes
| |
| o changeset: 485:b28264333e18
| | user: other
| | summary: binary
If I merge, it sort of seems OK:
hg merge
abort: outstanding uncommitted merges
But hg diff shows all sorts of changes I did not make. I'm willing to re-apply my changes... how can I bring this all back to a single tip, abandoning all local changes?
It looks like when you've done an hg merge, you haven't committed the resulting changeset.
When you merge in another branch (in your case you may need to specify hg merge 486 to merge in the other users changes), it merges that branch into your working directory. You then need to check that all conflicts are resolved (if there are any) by using a merge tool, or manually editing the files (and then running hg resolve on any conflicts). Once this is done you need to hg commit your new, merged changeset.
This would explain why hg diff gives you lots of changes you didn't make -- they're changes made on the other branch, that you have yet to commit. If you run hg summary or hg parents in your working directory, you should see two parents listed: 486 and 488. You should hg commit this working directory, creating a new merged 489.
If you want to undo the current merge and start again, you're correct in trying to run hg update -C, which will set your working directory back to its original (unmerged) state.
If you want to get rid of your changes (487 and 488 - you state you don't mind re-applying your changes), the easiest option without resorting to extensions is simply to re-clone the repository and continue your work from there.
To get rid of changes (ex 487 and 488):
If you feel (as I do) that re-cloning the repository, as recommended above and even officially recommended here is ridiculous, then you should get MqExtension
Once Mq is enabled, you can easily remove changes you don't want:
hg strip 487
hg strip 488
I did not do merge, but suddenly I am viewing the message the op has posted. When I do a hg pull, in the command line it shows abort !repository default not found.
If i'm working on some files that I don't want to commit, I just save them. I then have other files I want to push to the server, however if someone else has made changes to the repository, and I pull them down, it asks me to merge or rebase.. but either of these options will cause me to lose my local changes that I have not committed.
What are other people doing to get around this? I find the documentation for the shelving extension hard to get my head around.
Note: I'm using Mercurial Eclipse to push and pull files to/from the server.
Any explanation of this would be greatly appreciated! Thanks!
Example:
I'm working on my website in Mercurial Eclipse. I have a new folder and new files that I don't want to commit to the server just yet. I've also modified some existing files and I don't want to make those changes live just yet.
Then something on my website breaks and I need to fix it, it won't let me fix it without rebasing or merging with the most recent tip of the repo and this will cause me to lose all my uncommitted changes.
What should I do with my new folder and files i've edited if I don't want to lose it? Re-cloning seems tedious. Copying the files to a new folder seems tedious as well. I'm sure Shelving or MQ will do what I want, I just don't know how to go about it yet.
With reference to your example situation, here's what I would do (following Ry4an's strategy to just commit the things you're currently working on, but don't want to publish already):
Supposed you start working in a repository like this one:
$ hg status -A
C f1
C f2
$ hg glog
# changeset: 1:7f3c6c86a92f
| tag: tip
| summary: add f2
|
o changeset: 0:03ca1e6d5b86
summary: initial
That is there are 2 files and 2 commits/changesets. You do some work, let's say add a new feature, and then your working copy might look like this:
$ hg status
M f2
? f3
? f4
There are 2 new and 1 modified file. Now you have to fix a bug for which you also need any new changes in a remote repository. Snapshot your current work by committing it and pull the remote changes (in which order you do that does not matter, a pull by default does not touch the state of your working copy):
$ hg commit -A -m "snapshot feature work"
$ hg pull
This may result in a history like this:
o changeset: 3:2284ba62de07 <-- just pulled in
| tag: tip
| parent: 1:7f3c6c86a92f
| summary: edit f1
|
| # changeset: 2:4a19d371a04f <-- your interrupted work
|/ summary: snapshot feature work
|
o changeset: 1:7f3c6c86a92f
| summary: add f2
|
o changeset: 0:03ca1e6d5b86
summary: initial
Now you can update-to/checkout revision 3 and start fixing bugs:
$ hg update 3
.. fix the bug ..
$ hg commit -m "fix a bug"
$ hg glog --limit 3
# changeset: 4:5d3d947fb4af
| tag: tip
| summary: fix a bug
|
o changeset: 3:2284ba62de07
| parent: 1:7f3c6c86a92f
| summary: edit f1
|
| o changeset: 2:4a19d371a04f
|/ summary: snapshot feature work
:
Looks good, let's push your fix, i.e. make it live, while don't publishing your intermediate work:
$ hg push -r 4
This pushes all changes leading to revision 4, your bugfix, but no other branches in your local repository. You could also use -r ., which refers to the parent revision of your working copy, i.e. the revision you just committed.
Finally you can go back to your feature work and continue your work:
$ hg update 2
.. work, commit, work, commit ..
.. finally merge with the other branch, e.g. revision 4
These steps are on the command line, but I think it's not to hard to adapt the general concept to corresponding clicks in the Eclipse Mercurial plugin.
Some extra notes:
You may want to bookmark your snapshot commit, so you don't need to work with revision IDs or numbers.
If you want to publish your feature work in a single commit later, use the collapse extension once you're done.
I'm sure someone will help you find a bad workaround, but the best route is to change you goals -- just commit. Code that hasn't been committed hasn't been written. If you positively can't abide having frequent commits in your history use Mercurial Queues with a queue repository and commit that. You can then pop the changesets, push/pull/merge, and the push them back on, and all you valuable work will be committed in the patch queue.
I work on a team where we have a code in a mercurial repository with several subrepositories:
main/
main/subrepo1/
main/subrepo1/subrepo2/
The default behavior of Mercurial is that when a hg commit is performed in "main", any outstanding changes in the subrepositories "subrepo1" and "subrepo2" will also be committed. Similarly, when "main" is pushed, any outgoing commits in "subrepo1" and "subrepo2" will also be pushed.
We find that people frequently inadvertently commit and push changes in their subrepositories (because they forgot they had made changes, and hg status by default does not show recursive changes). We also find that such global commits / pushes are almost always accidental in our team.
Mercurial 1.7 recently improved the situation with hg status -S and hg outgoing -S, which show changes in subrepositories; but still, this requires people to be paying attention.
Is there a way in Mercurial to make hg commit and hg push abort if there are changes/commits in subrepostories that would otherwise be committed/pushed?
Since Mercurial 1.8 there is a configuration setting that disables recursive commits. In the parent repositories .hg/hgrc you can add:
[ui]
commitsubrepos = no
If a commit in the parent repository finds uncommitted changes in a subrepository the whole commit is aborted, instead of silently committing the subrepositories.
Mercurial 2.0 automatically prevents you from committing subrepositories unless you manually specify the --subrepos (or, alternatively, -S) argument to commit.
For example, you try to perform a commit while there are pending changes in a subrepository, you get the following message:
# hg commit -m 'change main repo'
abort: uncommitted changes in subrepo hello
(use --subrepos for recursive commit)
You can successfully perform the commit, however, by adding --subrepos to the command:
# hg commit --subrepos -m 'commit subrepos'
committing subrepository hello
Some things to still be careful about: If you have changed the revision a subrepository is currently at, but not the contents of the subrepository, Mercurial will happily commit the version change without the --subrepos flag. Further, recursive pushes are still performed without warning.
One notion is to use URLs to which you have read-only access in your .hgsub files. Then when you do actually want to push in the subrepo you can just cd into it and do a hg push THE_READ_WRITE_URL.
One possible solution, using VonC's "pre-commit" idea.
Setup two scripts; the first check_subrepo_commit.sh:
#!/bin/bash
# If the environment variable "SUBREPO" is set, allow changes.
[ "x$SUBREPO" != "x" ] && exit 0
# Otherwise, ensure that subrepositories have not changed.
LOCAL_CHANGES=`hg status -a -m`
GLOBAL_CHANGES=`hg status -S -a -m`
if [ "x${LOCAL_CHANGES}" != "x$GLOBAL_CHANGES" ]; then
echo "Subrepository changes exist!"
exit 1
fi
exit 0
The second, check_subrepo_push.sh:
#!/bin/bash
# If the environment variable "SUBREPO" is set, allow changes.
[ "x$SUBREPO" != "x" ] && exit 0
# Otherwise, ensure that subrepositories have not changed.
LOCAL_CHANGES=`hg outgoing | grep '^changeset:'`
GLOBAL_CHANGES=`hg outgoing -S | grep '^changeset:'`
if [ "x${LOCAL_CHANGES}" != "x$GLOBAL_CHANGES" ]; then
echo "Global changes exist!"
exit 1
fi
exit 0
Add the following to your .hgrc:
[hooks]
pre-commit.subrepo = check_subrepo_commit.sh
pre-push.subrepo = check_subrepo_push.sh
By default, hg push and hg commit will abort if there are outstanding changes in subrepositories. Running a command like so:
SUBREPO=1 hg commit
will override the check, allowing you to perform the global commit/push if you really want to.
May be a pre-commit hook (not precommit) could do the hg status -S for you, and block the commit if it detects any changes?