A question that occasionally arises is what is the best way to determine the changelist that you last synced to in Perforce. This is often needed for things like injecting the changelist number into the revision info by the automatic build system.
I haven't used perforce much so this may not be exactly be a 1:1 translation. Then again distributed source control systems like git and mercurial have a different workflow anyway so there really isn't (and there shouldn't) be a 1:1 translation. Anyway, here goes:
Create multiple pending changelists -> Use branches instead. In git branches are light and quick, takes less than a second to create and typically less than two seconds to merge. Don't be afraid of branching and rebase often.
git branch new-branch-name git checkout new-branch-name
Or do it all in one line:
git checkout -b new-branch-name
See a list of all pending changelists -> Since the equivalent of multiple pending changelist is multiple branches just view the branches:
If you want to view remote branches as well:
git branch -a
It is considered good practice to immediately delete a branch after a successful merge so you don't have to keep track of which branch are pending to be merged and which have already been merged.
List all changed files -> For a single pending "changelist" in a specific branch git has a concept of the index or cache. In order to commit a change you must first add files to this index. This allows you to manually select which group of files represent a single change or to ignore irrelevant files. To see the status of which files are added, or not to this index just do:
See a diff of a pending changelist -> There are two parts to this. First to see a diff between the working directory and the index:
But if you want to know the diff between what you're typing now and the last commit then you are really asking for a diff between the working directory+index and the HEAD:
git diff HEAD
For a given file, see which submitted changelists affected which lines -> This is easy:
git blame filename
or even better, if you are in a windowing environment:
git gui blame filename
Git gui takes longer to parse the file (it was written in tcl instead of C) but it has lots of neat features including the ability to "time travel" back into the past by clicking on a commit ID. I only wish they'd implement a feature to "time travel" to the future so I can find out how a given bug will finally be resolved ;-)
For a given file, see a list of the descriptions of the changelists that affected the file -> also easy:
git log filename
But git log is a much more powerful tool than just this. In fact most of my personal scripts piggyback off-of git log to read the repository. Read the man page.
Submit a pending changelist -> Also easy:
See my answer to a previous question to see my typical git workflow: Learning Git. Need to know if I am on the right track
If you follow the workflow I outlined then you'll find tools like gitk to be much more valuable since it allows you to clearly see groups of changes.
Git is very flexible and there are several ways to do what you describe. The thing to remember is to always start a new branch for each feature you're working on. This means the master branch isn't touched so you can always go back to it to do bug fixes. Working in git one should almost always start with:
git checkout -b new-feature-a
Now you can edit file a.txt. To work concurrently on another feature do:
git checkout master git checkout -b new-feature-z
Now you can edit file z.txt. To switch back to a.txt:
git checkout new-feature-a
But wait, there are changes to new-feature-z and git won't let you switch branches. At this point you have two choices. The first is the simplest, commit all changes to the current branch:
git add . git commit git checkout new-feature-a
This is what I'd recommend. But if you are really not ready to commit the code, you can temporarily stash it:
Now you can switch to branch new-feature-a. To go back to the code you were working on just pop the stash:
git checkout new-feature-z git stash pop
When all is done merge back all changes to master:
git merge --no-ff new-feature-a git merge --no-ff new-feature-z
Because merges are so quick and easy (easy because conflicts are so rare and conflict resolution, when one does happen, not too hard) we use branches in git for everything.
Here's another example of a common use of branches in git that you don't see in other source control tools (except perhaps mercurial):
Need to keep changing your config files to reflect your dev environment? Then use a branch:
git checkout -b dev-config
Now edit your config files in your favourite editor then commit changes:
git add . git commit
Now every new branch can start from the dev-config branch instead of master:
git checkout dev-config git checkout -b new-feature-branch
Once you're done remove the edits in dev-config from new-feature-branch using interactive rebase:
git rebase -i master
Delete the commits you don't want then save. Now you have a clean branch without custom config edits. Time to merge back to master:
git checkout master git merge --no-ff new-feature-branch # because master have changed, it's a good idea to rebase dev-config: git checkout dev-config git rebase master
It should be noted that removing edits with
git rebase -i even works when all changes happen in the same file. Git remembers changes, not file content*.
*note: actually, technically not entirely true but as a user that's what it feels like
More additional answer:
So, from you comments it looks like you want to have two branches to exist simultaneously so you can test how the combined code works. Well, this is a good way to illustrate the power and flexibility of branches.
First, a word on the implication of cheap branching and modifiable history on your workflow. When I was using CVS and SVN I was always a bit reluctant to commit. That's because committing unstable code would inevitably f**k up other people's working code. But with git I lost that fear. That's because in git other people won't get my changes until I merge them to master. So now I find myself committing code every 5 lines I write. You don't need perfect foresight to commit. You just need to change your mindset: commit-to-branch==add-to-changeset, merge-to-master==commit-changeset.
So, back to examples. Here's how I would do it. Say you have a branch
new-feature-z and you want to test it with
new-feature-a. I would just create a new branch to test it:
# assume we are currently in branch new-feature-z # branch off this branch for testing git checkout -b feature-z-and-feature-a # now temporarily merge new-feature-a git merge --no-ff new-feature-a
Now you can test. If you need to modify something to make feature-z work with feature-a then do so. If so you can merge back the changes to the relevant branch. Use
git rebase -i to remove irrelevant changes from the merge.
Alternatively, you can also use git rebase to temporarily change the base of new-feature-z to point to new-feature-a:
# assume we are currently in branch new-feature-z git rebase new-feature-a
Now the branch history is modified so that new-feature-z will be based off new-feature-a instead of master. Now you can test. Any changes committed in this branch will belong to the branch new-feature-z. If you need to modify new-feature-a just switch back to it and the rebase to get the new changes:
git checkout new-feature-a # edit code, add, commit etc.. git checkout new-feature-z git rebase new-feature-a # now new-feature-z will contain new changes from new-feature-a
When you're done, simply rebase back to master to remove changes from new-feature-a:
# assume we are currently in branch new-feature-z git rebase master
Don't be afraid to start a new branch. Don't be afraid to start a throwaway branch. Don't be afraid to throw away branches. And since merge==submit and commit==add-to-changeset don't be afraid to commit often. Remember, commit is a developer's ultimate undo tool.
Oh, and another thing, in git deleted branches still exist in your repository. So if you've accidentally deleted something that you later realise is useful after all you can always get it back by searching the history. So don't be afraid to throw away branches.
One way is to create another branch, as in:
- p4 integ //depot/build/branch/...@1000 //depot/bugfix/branch/...
- p4 submit
- p4 integ //depot/build/branch/...@=1051 //depot/bugfix/branch/...
- p4 resolve
- p4 submit
Now build //depot/bugfix/branch and give that to your test team.