20

I have been converting old SVN repos to GIT. I have gotten the branches and tags to convert. Including making SVN tags real tags in GIT.

However, I would like to add a gitignore to the very first commit in the newly created GIT repo. I want it to be as if the file had always been there. So all the commits that followed (on master or in branches) would now have this file as the parent tree(s) would lead back the the first commit.

It seems that some form of git rebase or git filter-branch --tree-filter is what I need. I have tried each of these but I end up with disconnected branches.

Carl Stewart
  • 335
  • 2
  • 11
  • You can easily do this for single branch using `git rebase -i`. But I'm not sure how to do it for all branches and tags in the whole repo. – svick Sep 03 '11 at 19:59
  • Yep. It was pretty easy for a single branch. I really am trying to "rewrite" history. I want to make it as if I added the gitignore from the beginning and everything flowed from there. – Carl Stewart Sep 03 '11 at 20:14

3 Answers3

23

I recently had to modify an early commit because of a problematic typo in the commit message. This works for changing anything about a previous commit. I modified Charles Bailey's answer to Combine the first two commits of a Git repository?

# Go back to the commit you want to change (detach HEAD)
git checkout <sha1_for_commit_to_change>

# Make any changes now (add your new file) then add them to the index
git add <new_files>

# amend the current commit
git commit --amend

# temporarily tag this new commit
# (or you could remember the new commit sha1 manually)
git tag tmp

# go back to the original branch (assume master for this example)
git checkout master

# Replay all the commits after the change onto the new initial commit
git rebase --rebase-merges --onto tmp <sha1_for_commit_to_change>

# remove the temporary tag
git tag -d tmp

Note that this will change all of your commit IDs following the amended commit, so it's not recommended on a public repository. Also, you'll have to recreate all of your tags

double-beep
  • 5,031
  • 17
  • 33
  • 41
Mason Heller
  • 367
  • 2
  • 7
1

Do this on a clean working tree, on a new clone if you wish:

$ git checkout -b withgitignore $firstcommithash
$ git add .gitignore
$ git commit --amend
$ for branch in branch1 branch2 branch3 ... ; do
      git checkout $branch
      git rebase withgitignore
   done

Untested ;)

holygeek
  • 15,653
  • 1
  • 40
  • 50
  • I'll give this a try and report back. – Carl Stewart Sep 03 '11 at 23:16
  • The only reason that I could think of why it wouldn't work is because one or more of the branches (or commits pointed to by the tags) did not share the same first commit. Could you verify that this is the case by doing something like 'git log --oneline branch|tail -1'? Compare the result for all branches and tags. – holygeek Sep 05 '11 at 20:19
  • Sorry for the delay. My wife gave birth early been busy! I checked each branch/tag and every one had the same first commit. I'm going to try it again and see if I can give further info. – Carl Stewart Sep 16 '11 at 20:00
  • Congratulations on being a father! Please tell your wife a random stranger wishes all the best for the whole family. As a father of two all I can say is that children can give you immeasurable happiness. – holygeek Sep 16 '11 at 23:16
  • Well, I tried it again and it didn't work. It goes through the motions but the gitignore file is not in any of the branches or tags when I switch/checkout them. Oh and thanks for the well wishes. 2 kid for me too. Definitely not a linear difficulty curve! Much harder. – Carl Stewart Sep 19 '11 at 20:48
0

Assuming that this is a brand new rebuild, then one trick is to start a branch at that first commit and add the gitignore there. You now have the 'right' commit at the head of that branch. Now for the trick - you use the grafts facility to reorder the perceived commit sequence. A plain git filter-branch will make it permanent, though the old hierarchy will be still be listed under originals in refs\info (IIRC).

While this will create an early commit that contains the gitignore file, all the other commits will still be without the gitignore file.

Edit:---------- The git-filter-branch, gives examples:

git filter-branch --tree-filter 'rm filename' HEAD, and a --index-filter variant.

You could simply add .gitignore your .gitignore instead of the remove, and use the --index-filter so that your work tree is still intact for copying from.

Make sure you have a backup first though ! Report if it works for you.

Philip Oakley
  • 13,333
  • 9
  • 48
  • 71
  • Hmmm. It still seems that this won't help the other commits. It isn't so much that I want the commit reordered, rather I'm hoping to achieve something that allow the other commits to "inherit" the newly added file. I'll read more on the --index-filter though in case I misunderstand. – Carl Stewart Sep 03 '11 at 23:20
  • What the command should do is go through each commit, one by one, and perform the filter action, which in this case is to add your `.gitignore`, and then re-write the commit. At the end of the command, if you use `gitk --all` you should see the newly formed branch, with every commit having `.gitignore` included, plus an `originals` pseudo branch 'just in case'. – Philip Oakley Sep 04 '11 at 10:03
  • I tried copying the gitignore into the working tree and then `git filter-branch --tree-filter 'git add gitignore' HEAD --index-filter`, but I get this error: *fatal: ambiguous argument 'add': unknown revision or path not in the working tree.* – Carl Stewart Sep 05 '11 at 17:48
  • @Carl: the `tree-filter` was the man page example. Have you tried it with the suggested `--index-filter`? i.e `git filter-branch --index-filter 'git add gitignore'` HEAD is assumed (is it `.gitignore`, or simply `gitignore`?) – Philip Oakley Sep 06 '11 at 12:04
  • Sorry for the delay. My wife gave birth early been busy! Anyway, I tried `git filter-branch --index-filter 'git add gitignore' HEAD`, `git filter-branch --index-filter 'git add gitignore'`, `git filter-branch --index-filter 'git add .gitignore'` and in each case still got the same error – Carl Stewart Sep 16 '11 at 19:52
  • @Carl, Congratulations, I hope everyone is well. – Philip Oakley Sep 16 '11 at 21:35