views:

150

answers:

4

It seems that it is suggested we can commit often to keep track of intermediate changes of code we wrote… such as on hginit.com, when using Mercurial or Git.

However, let's say if we work on a project, and we commit files often. Now for one reason or another, the manager wants part of the feature to go out, so we need to do a push, but I heard that on Mercurial or Git, there is no way to push individual files or a folder… either everything committed gets pushed or nothing get pushed. So we either have to revert all those files we don't want to push, or we just never should commit until before we push -- right after commit, we push?

+3  A: 

Develop on branches.

Have a release branch and feature branches. Merge in each feature as it becomes available.

Paul Nathan
+2  A: 

It is good practice to commit often. In your case, it seems like you need to start tagging and/or branching more often.

zdav
+7  A: 

The best way to manage this (whether you are using Mercurial, Git or any other revision control system) is to make sure your work is done on branches which correspond to these "parts of features". If there is even a small chance that some portion of work will need to be released independently from other work, it should have its own branch from the start.

This gives you the flexibility to push just the "part of the feature", and is much better suited in the case where the "part of feature" and some other "part of the feature" both contain changes to the same file.

The nice thing about using Mercurial or Git here is that managing these branches is trivial, so the cost to creating and using them (even if they turn out not to be necessary) is minimal.

Now, you can't always foresee everything. If you do end up stuck in the situation you describe, though, it's easy to get out of. Say you had 100 changesets locally (not yet on the server) and you wanted to just push the current contents of 1 file. Create a clone of the repository you're working on back to the server revision, copy the file over, commit, push, and integrate back. In Mercurial this would look something like the following:

$ cd ~/project
$ hg clone http://server/project/trunk trunk-oops
$ cp trunk/shouldve-branched trunk-oops/shouldve-branched
$ cd trunk-oops; hg addrem; hg ci -m "We need to organize better!"; hg push
$ cd ../trunk; hg fetch ../trunk-oops
nullptr
and then rmdir truck-oops? On PC, last time I "hg clone" and "hg update", it was like 500MB, so if I do step (2) above (the hg clone), it won't be very big data even on the PC? (just make sure not to do "hg update" or else it will pull the 500MB data?)
動靜能量
If space is a concern (or even if it isn't), clone locally. Mercurial will create hard links so the extra space isn't consumed.hg clone -rSERVER_REVISION_HASH trunk trunk-oops
nullptr
What's all this about cloning? I know Mercurial isn't identical to git, but surely you could create another branch, cherry-pick/rebase (or the hg analog) to get what you wanted and push that (then similarly take care of the original branch however you need to).
Jefromi
I've gone ahead and posted my own answer, which echoes what you've said about making sure to branch, but also emphasizes that with frequent committing, you should be able to do what you like even if you don't have a branch that's exactly what you want - and it doesn't require cloning or copying files to make new commits; it's all within the repo.
Jefromi
+1  A: 

To extend and clarify what others have said: committing often and flexible pushing are not mutually exclusive.

You do want to plan ahead, and make your commits such that you'll be able to adapt. This means two things: you need to make sure you really commit often, and you need to branch (as in git) frequently. If your commits are small, it'll be easier to reorganize them later should you need to selectively group together part of your work. And if your branches are well-organized, you may already have a branch which is exactly what you want to push.

Compare these two:

One branch, few commits:

- A1 - B1 - C1 - B2 - A2 - B3 - C3 (master)

Many branches, many commits:

  M1 - M2 (master)
 /
o - A1 - A2 - A3 - A4 - A5 - A6 (topicA)
|\
| B1 - B2 - B3 - B4 - B5 - B6 - B7 (topicB)
\ 
 C1 - C2 - C3 - C4 - C5 (topicC)

Now, if you want to release any of those three topics as-is, all you have to do is merge it to master and push! If you want to release half of topicA, and that half is taken care of in commits A1, A3, A4, and A6, all you have to do is rebase topicA to place those four commits first, merge the last of them into master, and push. The remainder of topicA (A2 and A5) can hang around for further work.

  M1 - M2 ------------- X (master)
 /                     /
o - A1 - A3' - A4' - A6' - A2' - A5' (topicA)

(Commits denoted by A1', ... because with git, a two commits with the same contents but different parents are actually different commits.)

Jefromi