Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug
Dulwich works well enough to be fundamental to hg-git, which itself works reasonably well. hg-git is a GitHub project, and may well have been the driving force behind Dulwich.

Adbot
ADBOT LOVES YOU

Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug

Ziir posted:

I just started using Git and I'm really not sure what I'm doing. Say I edit a file and want to commit the changes, if I type "git commit -m 'comments'" then it tells me that there were no changes to commit and suggests that I do "git add file" first and then commit. This doesn't make sense to me because I already added that file before, and I don't feel like I should have to re-add the file again just because I edited it.

Am I missing something here?

The resources that Mithaldu and ColdPie posted are great; especially the Pro Git book. I recommend that book to everyone who's starting with Git.

A direct answer to your question can't hurt either: you do have to add the file again. You always have to add whatever you're going to commit. Every time*. git add adds the current contents of the file (whether or not it's already tracked) to what will be in the next commit. This way, you can build up your next commit file-by-file over multiple commands instead of a long sequence of arguments, e.g. svn commit file1 file2 file3 file4 file5. Note that you can use git add . to add everything under the current directory, both tracked and untracked.

*Let's not discuss git commit -a. Getting used to the index is well worth it and helps with the "oops, I committed too much" problem.

Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug
:patriot:

I had two graphic designers at my side job using Git. It went remarkably well, actually. I was so proud when one of the designers asked me why there were divergent history and merges when it was just me (at the time) working on the website. (Hot fixes on the live server while working on larger features on a local machine.)

Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug
Or you can run
code:
git checkout B2
git reset B
which will force-move the B2 branch to point to the same commit as B. This won't touch your working tree, but since the branches (presumably) point to the same tree object, git status should show no changes after the reset.

Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug
You want Gitolite. It's easy to set up and very powerful.

When you're using a server run by Gitolite, everyone uses the same user (git) and access control works through SSH keys. You can restrict his access so that he can't push to the master branch, but all other branch names are fine.

Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug
git remote prune origin will delete your local copies of remote branches that no longer exist. This process is not automatic.

Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug
Yeah, it helps to remember (and may also help to tell your team this) that one of the high-level design decisions in Git is to be completely paranoid about preserving information in your local repository. Most of the time you have to explicitly tell Git when you want to remove some information, with the notable exception of reflog entries expiring after some large number of days so that unreachable objects can be pruned by git gc --auto.

Remote ref disappeared? Trouble might be afoot. :ninja:

Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug
On the other hand, if you use git add -p, there's no a priori guarantee that the states you're committing even compile, let alone work correctly. You're creating states in the repository that have never existed at any point before this, so you need to be careful not to commit e.g. a change to a function's signature without also committing changes to its usage everywhere. I typically commit the entire state of my working tree, but I do this often and after each logically separate change that still builds and doesn't break anything that isn't under active development. God help you if you want to use git bisect and the intermediate commits you're testing don't compile because you git add -p'd too much or too little.

You could conceivably write a script that will checkout each of your recent commits and verify that the project builds/passes unit tests, after which you can fix anything that's broken with git rebase -i. I find it a lot easier to commit my entire verified (syntactically correct) working tree after each incremental change I make.

Carelessly using git add -p reminds me of Subversion's misfeature that allows you to commit changes as long as the files you've modified don't have any newer changes in the repository. That makes me very uneasy, again because you're committing a state that has never existed before and has no guarantees of working.

Disclaimer: I use git add -p regularly, though not exclusively.

taqueso, Pro Git is excellent, as is gitref.org (by the same author).

Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug

Rocko Bonaparte posted:

I'm now scared shitless of actually trying to go the next step. :ohdear:

I'd be uneasy about this too. I don't believe Git is designed to work over a network mount like this, and who knows how well the dokan sshfs plugin works.

If msysgit bash actually recognizes the sshfs mount as a drive letter (good luck, by the way), you'll want make sure that your local development repository's .git/config has a remote URL of the form file:///z/path/to/repo.git. The file:// prefix forces Git to use its normal network transfer protocol instead of e.g. trying to hardlink pack files on a local disk.

This is all a horrible idea anyway; why don't you just install Git on your web host machine? (You can SSH into your web hosting and install things, right? You can even install Git into your home directory if you don't have root on the machine.)

Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug

Wideshanks posted:

Ah, this is perfect, thank you.

Cool command--get a list of each of the objects in your repo and what type they are:

find .git/objects -type f | awk 'BEGIN{FS="/"}{print$3$4}' | while read -r hash; do git cat-file -t $hash; done

FYI this only examines loose objects, i.e. those that aren't stored in a pack file. (A few git commands run git gc --auto after they complete, and this will consolidate loose objects into a pack file if there are too many. You can also manually pack your loose objects with git repack.)

EDIT:
code:
fatal: Not a valid object name packpack-265968c856973bfe79185a5c591d9317b8bb92e4.pack
fatal: Not a valid object name packpack-265968c856973bfe79185a5c591d9317b8bb92e4.idx
fatal: Not a valid object name infopacks

Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug
There's no good reason to do this one commit at a time; it's a huge waste. Run

code:
git filter-branch --env-filter 'export GIT_AUTHOR_NAME="new user name";
export GIT_AUTHOR_EMAIL="new_email@host.tld"' good_commit..bad_commit
where good_commit is the last commit with the correct authorship, and bad_commit is probably HEAD.

Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug
Looks good to me. Now that I think of it, you may also want to set GIT_COMMITTER_NAME and GIT_COMMITTER_EMAIL:

code:
git filter-branch --env-filter 'export GIT_AUTHOR_NAME="ufarn";
export GIT_AUTHOR_EMAIL="ufarn@gmail.com";
export GIT_COMMITTER_NAME="ufarn";
export GIT_COMMITTER_EMAIL="ufarn@gmail.com"' 758c58bd91ce0d1371c8145402de632045649252..HEAD

Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug

ufarn posted:

Now what? :ohdear:

Run gitk --all & to view the history in your repository. (I can never get any work done without having gitk open -- it's tremendously useful to see the history that you're adding to).

It looks like git filter-branch succeeded in rewriting the history, but failed to clean up some of its internal state. Try removing the c:/(...)/.git-rewrite directory yourself.

Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug
Here's a good question: what did you expect to happen when you changed your email address in those commits? Why do you think it looks like something failed or wasn't applied? (Also, there are no "files" that have branched out, those are commits.)

Always keep in mind that you cannot change a commit1. As a consequence, you cannot modify the history in your repository. Your only option is to make new history with the changes you want, and then forget the old commits by removing or reassigning all references to them.

You made new history with filter-branch, and git status indirectly told you that there are still references to the old commits:
code:
# Your branch and 'origin/registration' have diverged,
# and have 6 and 6 different commit(s) each, respectively.
You have 6 new commits with different authorship information, but those are only in your local repository because you haven't git push -f'd them.

However, I'd first redo the filter-branch with an earlier start commit -- the one before the first occurrence of the incorrect email address. You'll need to use the -f option since filter-branch is careful about keeping a backup of your old state, and it won't overwrite the previous backup by default. (This backup is the grey original/refs/heads/registration label in your gitk display.)



_____________________________________
1or any type of Git object: tags, commits, trees, blobs.

Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug

ufarn posted:

Thanks. Assuming things went okay, I have to re-enter the exact same command albeit with a different good_commit value? I just checked, and the value I entered the last time referred to a commit before the first wrongful commit. I can try stepping it one commit back, though.

Is the `-f` option only for the push or for the re-entered command as well?

Both. git push -f means "push, and don't worry about altering (as opposed to appending to) the history in the remote repository". git filter-branch -f means "rewrite history in bulk, and don't worry about overwriting the previous backup of which commit this branch pointed to".

EDIT: didn't respond to your other question. When you specify a range of commits such as A..B, you're telling Git "everything reachable from B minus everything reachable from A". This set of commits by definition doesn't include A. If you want to include A, you have to specify its parent (assuming it only has one) as part of the range -- either manually, or in the form A~..B. The ~ means 'parent', and there's a whole man page about specifying ranges of commits.

Lysidas fucked around with this message at 01:03 on Feb 10, 2012

Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug

ufarn posted:

Not sure it went as planned. I had forgotten to delete .git-rewrite and grant git bash full permissions. This is what I got:

...

And this is what my tree looks like:



It didn't go as planned because you told git filter-branch to make some changes that are already applied. That is, "make a new commit with the author and committer set to these values, but everything else the same" resulted in identical commits since the authorship information already matched the modification you did.

Run this:
code:
git filter-branch -f --env-filter 'export GIT_AUTHOR_NAME="John Appleseed";
export GIT_AUTHOR_EMAIL="john@appleseed.com";
export GIT_COMMITTER_NAME="John Appleseed";
export GIT_COMMITTER_EMAIL="john@appleseed.com"' HEAD~24..HEAD
Assuming that I counted correctly, HEAD~24 is the commit that's pretty far down, right before the first of the two with bad email addresses. I assume that you want to rewrite that entire range to also fix those two commits.

Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug

Ithaqua posted:

Out of curiousity: Are any of you SVN/git guys going to be taking a look at TFS express?

I assume the client and server software don't run on Linux or Mac OS, so that's a resounding "no". I'll also never consider going back to a centralized version control system for managing code; maybe for huge art assets that graphic designers work on.

(Seriously, why would you develop software on/for Windows in 2012? :v:)

Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug
Run this (assuming that 'master' is the right branch name):
code:
gitk origin/master..master
This is equivalent to gitk ^origin/master master, and shows you everything that's in your master branch minus everything in origin/master. These are the commits that you're about to push.

Lysidas fucked around with this message at 15:43 on Mar 16, 2012

Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug

Rocko Bonaparte posted:

I'm now looking into more rigorous backup strategies. I have some online web storage that takes SSH, but they won't add git. Regardless, is there a way to use scp to at least mirror stuff?

If you can SSH into a machine, you can install Git yourself. If you don't have root access, you can still install it into your home directory:

code:
tar -xf git-1.7.9.5.tar.gz
cd git-1.7.9.5
make configure
./configure --prefix="$HOME"
make
make install
Ensure that ~/bin is in your PATH by setting this in .bashrc (I believe that this is one of the times when the difference between .bashrc and .bash_profile matters), and then you can store bare repositories on this machine and use them as remotes in your local repositories.

I strongly recommend that you just use Bitbucket or GitHub though.

Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug
I think uXs is talking about local changes that are only in your working copy/repository -- running svn update or cvs update does a small merge at that time. If there's no textual conflict between what changed in the repository and your local modifications, I believe SVN will gracefully merge them. Otherwise, you get a conflict marker in your file. Even if you're working on a branch, your local uncommitted changes are in danger whenever you update.

Git, on the other hand, will abort a merge if any of the affected files have local modifications. The intent is that your local modifications should be commits instead of modified files; this helps in merging the history, and most importantly you don't have any risk of losing your work.

Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug

Otto Skorzeny posted:

I have a Debian VM on my workstation as well in case that turns out to be the easier route.

This will probably be the easiest route.

Short-term, you could use your Windows machines. You'd both create git-daemon-export-ok files in your repositories and run git daemon --base-path=/parent/dir/of/your/repository. You can then fetch from each other with URLs of the form git://your-coworkers-pc/repo-dir-name.

I would strongly recommend that you use a Linux machine, but once both of you start to depend on a repository host it can be a pain to use a VM on your desktop machine. You could conceivably create a new user in that VM, store a bare repository in that user's home directory and both of you can login as that user to push/pull from the bare repository (using SSH keys is preferred). That would be very easy to set up and I don't see any serious problems in using this for only two people.

The best solution would be to use Gitolite, though. This software manages access control to repositories, using usernames and SSH keys. You'd put your bare repository(ies) somewhere like /srv/git/repositories, install Gitolite into that location, and let Gitolite manage access control for you.

Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug

Mr. Crow posted:

Seems like Mercurial is free for private repositories, while Git is not? Probably end up trying Mercurial in that case, thanks :)

GitHub is not Git, and Bitbucket is not Mercurial.

Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug
  1. What does .git/refs/heads/temp contain?
  2. What does .git/HEAD contain?
  3. What is the output of git fsck?

Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug
As always, Linus has said this better than I'll be able to.

EDIT: Though more detail can't hurt. It depends on what you mean by "mistakes". If it's a mistake in the sense of "this algorithm didn't work; here's why I switched to another", then that probably should be published. The idea is to get rid of a ton of "forgot this file", "oops revert what I shouldn't have committed", "intermediate bug fix #2" commits -- these are meaningless to someone who's examining the history later, either for a code review or to track down a bug.

Lysidas fucked around with this message at 13:36 on Apr 4, 2013

Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug

ufarn posted:

I've got a rather annoying conflict that prevents me from saving my work:


I use Dropbox to store my work, so some conflict has apparently emerged at some point - presumably when editing a single Markdown file.

There are currently two ref heads, one "master", and one "master (conflict etc.)" file inside .git/.

How do I resolve such a conflict?

  1. Don't store Git repositories in Dropbox.
  2. Rename the "master (conflict ...)" file to "master-conflict" or something else that's a legal Git ref name. Then, look at your branches with gitk and figure out which copy of master is the right one.

Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug

MononcQc posted:

it represents commits as linked lists/trees of diffs/patches that can be applied

You lost me here, because this is flat out wrong. Git commits have pointers to full snapshots of the project content. Tools like rebase treat the differences between commits as diffs/patches, but Git internally does not store data in this way. The only tool that I know of that operates in this manner is darcs, but I haven't kept up with VCS news since starting to use Git.

I agree overall, though, that fundamentally understanding Git's data model is required to use it in any real capacity.

Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug

Suspicious Dish posted:

Git packfiles, which are what are sent over the network, and used as an archiving format for not-recently-accessed objects, are a delta storage format.

Very true, but that isn't really what MononcQc meant. He implied that Git commits fundamentally are patches against the previous version (a la darcs), so that if you make a commit Y on top of commit X, Y is defined and stored as "X plus these changes".

This isn't the case; commit Y isn't a diff but an annotated pointer to a tree object that specifies the full contents of every file in the project. Whether these objects (commit, trees, blobs) are stored as deltas is really an implementation detail and a file size optimization. It doesn't mean you can say that "Git stores commits as patches" -- packfile delta chains are mutable and in fact older objects are often stored as deltas against newer ones. (The rationale is that you're more likely to need to access newer objects, so CPU time shouldn't be spent to reconstruct those.)

The most accurate answer to "does Git store diffs" is something like "technically yes, but not in the way that you meant".

Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug

GrumpyDoctor posted:

I want the base version in the repo. I just don't want any changes to it to be tracked anywhere. Is there some way I can use .gitignore for this? Force-adding it still results in changes being tracked.

Don't do this. It only leads to pain in the long run.

Create a settings override mechanism and ignore the override file. I worked on a Django app a little while ago, and the last part of settings.py was
Python code:
# Keep this as the last section of this file:
try:
    from settings_override import *
except ImportError:
    # Don't care. No override settings are present.
    pass
settings_override.py was listed in the appropriate .gitignore.

Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug
I wouldn't object too strongly to storing a bare repository in Dropbox, that you'd use after e.g. git clone ~/dropbox-shared/repo.git. You'd then push to that bare repository and the pushed objects would be synchronized as normal. Each machine that you use could have its own non-bare clone of that shared bare repo.

Repacking the bare repository would cause a lot of churn in the Dropbox content, but that wouldn't happen very often.

I still consider this inferior to synchronizing changes purely through Git transport protocols, but it doesn't bother me that much.

Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug

Axiem posted:

Or am I just completely insane to want to host my own git repo for what is essentially a mom-and-pop operation?

Not at all. Host your own Gitolite installation.

Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug

fletcher posted:

I want to blow away any changes that may have occurred locally

Maybe
code:
git fetch
git fetch --tags
git reset --hard @{u}
@{u} is short for @{upstream} and is defined in .git/config for each local branch as "where does this branch pull from". The hard reset will move your local copy of the branch to match the remote branch and discard all working tree local modifications.

Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug
Requiring git add for already-tracked files is a consequence of Git having a staging area for the next commit. This staging area (and thus the need to git add files that are tracked) is not an implementation detail that should be hidden; it is a feature. It allows for easy implementation of operations like "only stage some of the textual changes in this file, leave the rest unstaged":

code:
$ git init
Initialized empty Git repository in /home/me/test/.git/
$ echo -e 'line 1\nline 2\nline 3\nline 4\nline 5' > file
$ git add file
$ git commit -m 'Add file'
[master (root-commit) 3a3def8] Add file
 1 file changed, 5 insertions(+)
 create mode 100644 file
~/test:master$ # edit file
$ git add -p
diff --git a/file b/file
index 94c99a3..36642bb 100644
--- a/file
+++ b/file
@@ -1,5 +1,5 @@
-line 1
 line 2
 line 3
 line 4
 line 5
+line 6
Stage this hunk [y,n,q,a,d,/,s,e,?]? s
Split into 2 hunks.
@@ -1,5 +1,4 @@
-line 1
 line 2
 line 3
 line 4
 line 5
Stage this hunk [y,n,q,a,d,/,j,J,g,e,?]? y
@@ -2,4 +1,5 @@
 line 2
 line 3
 line 4
 line 5
+line 6
Stage this hunk [y,n,q,a,d,/,K,g,e,?]? n

$ git status                                                                           
On branch master                                                                                                        
Changes to be committed:                                                                                                
  (use "git reset HEAD <file>..." to unstage)                                                                           

        modified:   file

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:   file

Adbot
ADBOT LOVES YOU

Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug

loquacius posted:

Ok, so I'm working from a Windows machine in a mostly Linux environment, on a huge (like 900,000 revisions) SVN repository. I've been doing this by using rsync to get my checkout from my dev server to my laptop and SFTP to move my changes back, but this causes issues when big changes to the repository happen, and one of those happened last week, so I'm playing around with alternatives. Using the Windows SVN client (command-line or Tortoise) fails due to some weird syntax somewhere that Windows doesn't know how to deal with; recently I found some success with git-svn. Meaning, I was able to successfully get a checkout from the repository directly to my laptop. Hooray.

But I'd also like to run Linux scripts on the checkout locally. I'm using CygWIN to do this, and the process is kinda buggy and lovely. Most recently, I found out that CygWIN's linux installation of SVN does not think my checkout is a working checkout, because Git-SVN did not generate a .svn directory. svn log doesn't work in CygWIN for the same reason (but it does in Windows SVN in cmd).

My questions: (1) is it the case that Git-SVN should have generated the .svn directory and hosed up somehow, and if so what could have caused this, and (2) if Git-SVN on Windows just doesn't generate that directory under any circumstances, what's the best way to make one? I could just WinSCP the one from my dev server over to my laptop (my if-all-else-fails option) but this seems like a bad idea.

  1. No; using git-svn creates a local Git repository that mirrors the remote SVN repository, and creates a Git working tree. The .svn directories are for a Subversion working copy, which you don't have. You have a Git repository and a Git work tree, with no SVN metadata of any kind.
  2. This question doesn't really make any sense. Do you want or need a SVN working copy? If so, then you can't use git-svn to clone the repository; you need to use SVN tools. I'm very surprised that the native Windows SVN client would recognize this, unless you have both .git and .svn directories in some abomination of a hybrid working copy. (I've actually done that before, incidentally.)

Your post implies a few more fundamental questions, though. Did you try simply checking out the repository, fresh, on your Windows system? What do you need to do with SVN tools, that you can't do locally with Git in your git-svn clone? Why are you going through so much pain to work on a local Windows system instead of just using Linux (perhaps locally), to avoid the "buggy and lovely" stuff you're encountering with Cygwin?

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply